如何计算 Pandas 数据框中的重复行?
- 2025-03-10 08:52:00
- admin 原创
- 63
问题描述:
我正在尝试计算数据框中每种类型的行的重复项。例如,假设我在 Pandas 中有一个数据框,如下所示:
df = pd.DataFrame({'one': pd.Series([1., 1, 1]),
'two': pd.Series([1., 2., 1])})
我得到一个如下所示的 df:
one two
0 1 1
1 1 2
2 1 1
我想象第一步是找到所有不同的唯一行,我这样做:
df.drop_duplicates()
这给了我以下 df:
one two
0 1 1
1 1 2
现在我想从上面的 df ([1 1] 和 [1 2]) 中取出每一行,并计算每行在初始 df 中出现的次数。我的结果看起来会像这样:
Row Count
[1 1] 2
[1 2] 1
我应该如何完成这最后一步?
编辑:
下面是一个更大的例子,可以更清楚地说明这一点:
df = pd.DataFrame({'one': pd.Series([True, True, True, False]),
'two': pd.Series([True, False, False, True]),
'three': pd.Series([True, False, False, False])})
给我:
one three two
0 True True True
1 True False False
2 True False False
3 False False True
我想要一个结果告诉我:
Row Count
[True True True] 1
[True False False] 2
[False False True] 1
解决方案 1:
您可以groupby
在所有列上调用size
索引来指示重复的值:
In [28]:
df.groupby(df.columns.tolist(),as_index=False).size()
Out[28]:
one three two
False False True 1
True False False 2
True True 1
dtype: int64
解决方案 2:
具体到您的问题,其他人提到的快速简便的方法是:
df.groupby(df.columns.tolist(),as_index=False).size()
如果您想计算特定列上的重复项:
len(df['one'])-len(df['one'].drop_duplicates())
如果要计算整个数据框中的重复项:
len(df)-len(df.drop_duplicates())
或者简单地使用DataFrame.duplicated(subset=None, keep='first'):
df.duplicated(subset='one', keep='first').sum()
在哪里
子集:列标签或标签序列(默认使用所有列)
保留:{'first','last',False},默认'first'
first:除第一次出现外,将重复项标记为 True。
last:除最后一次出现的情况外,将重复项标记为 True。
False:将所有重复项标记为 True。
解决方案 3:
df.groupby(df.columns.tolist()).size().reset_index().\n rename(columns={0:'records'})
one two records
0 1 1 2
1 1 2 1
解决方案 4:
我使用:
used_features =[
"one",
"two",
"three"
]
df['is_duplicated'] = df.duplicated(used_features)
df['is_duplicated'].sum()
它给出了重复行的数量,然后您可以通过新列对其进行分析。我在这里没有看到这样的解决方案。
解决方案 5:
如果您只需要找到唯一行和重复行(整行重复)的计数,那么这种方法可以奏效:
df.duplicated().value_counts()
输出:False 11398 True 154 dtype:int64
解决方案 6:
现有的答案都没有提供一个简单的解决方案来返回“只是重复的并且应该被删除的行数”。这是一个一刀切的解决方案,它的作用是:
# generate a table of those culprit rows which are duplicated:
dups = df.groupby(df.columns.tolist()).size().reset_index().rename(columns={0:'count'})
# sum the final col of that table, and subtract the number of culprits:
dups['count'].sum() - dups.shape[0]
解决方案 7:
如果您发现某些计数缺失或出现错误:ValueError: Length mismatch: Expected axis has nnnn elements, new values have mmmm elements
,请阅读此处:
1. 计算有条目的重复行NaN
:
被接受的解决方案很棒,相信对许多成员都有帮助。在最近的一项任务中,我发现它可以进一步微调以支持对包含条目的数据框进行完整NaN
计数。Pandas 支持将缺失条目或空值作为NaN
值。让我们看看当我们的数据框包含条目时此用例的输出是什么NaN
:
Col1 Col2 Col3 Col4
0 ABC 123 XYZ NaN # group #1 of 3
1 ABC 123 XYZ NaN # group #1 of 3
2 ABC 678 PQR def # group #2 of 1
3 MNO 890 EFG abc # group #3 of 4
4 MNO 890 EFG abc # group #3 of 4
5 CDE 234 567 xyz # group #4 of 2
6 ABC 123 XYZ NaN # group #1 of 3
7 CDE 234 567 xyz # group #4 of 2
8 MNO 890 EFG abc # group #3 of 4
9 MNO 890 EFG abc # group #3 of 4
应用代码:
df.groupby(df.columns.tolist(),as_index=False).size()
给出:
Col1 Col2 Col3 Col4 size
0 ABC 678 PQR def 1
1 CDE 234 567 xyz 2
2 MNO 890 EFG abc 4
哦,为什么缺少具有 3 个重复行的组 #1 的计数?!
对于某些 Pandas 版本,你可能会收到错误:ValueError: Length mismatch: Expected axis has nnnn elements, new values have mmmm elements
解决方案:
dropna=
使用该函数的参数.groupby()
,如下所示:
df.groupby(df.columns.tolist(), as_index=False, dropna=False).size()
给出:
Col1 Col2 Col3 Col4 size
0 ABC 123 XYZ NaN 3 # <=== count of rows with `NaN`
1 ABC 678 PQR def 1
2 CDE 234 567 xyz 2
3 MNO 890 EFG abc 4
NaN
可以使用 成功输出重复行数。此参数自Pandas 1.1.0 版本dropna=False
开始支持
2. 替代解决方案
计算重复行的另一种方法NaN
如下:
df.value_counts(dropna=False).reset_index(name='count')
给出:
Col1 Col2 Col3 Col4 count
0 MNO 890 EFG abc 4
1 ABC 123 XYZ NaN 3
2 CDE 234 567 xyz 2
3 ABC 678 PQR def 1
在这里,我们使用了.value_counts()
带有参数的函数。但是,此参数自Pandas 版本 1.3.0dropna=False
起才被支持。 如果您的版本比此版本更旧,则需要使用解决方案来获取包含条目的行的完整计数。.groupby()
`NaN`
您将看到输出的顺序与之前的结果不同。计数按降序排列。如果您想获得未排序的结果,您可以指定sort=False
:
df.value_counts(dropna=False, sort=False).reset_index(name='count')
它给出与解决方案相同的结果df.groupby(df.columns.tolist(), as_index=False, dropna=False).size()
:
Col1 Col2 Col3 Col4 count
0 ABC 123 XYZ NaN 3
1 ABC 678 PQR def 1
2 CDE 234 567 xyz 2
3 MNO 890 EFG abc 4
请注意,此.value_counts()
解决方案支持有和没有NaN
条目的数据框,可以用作通用解决方案。
其实在底层实现中,获取counts的代码.value_counts()
调用如下GroupBy.size
:点击链接查看底层代码:counts = self.groupby(subset, dropna=dropna).grouper.size()
因此,对于此用例,.value_counts()
和.groupby()
接受的解决方案中的解决方案实际上是在做同样的事情。我们应该能够使用该.value_counts()
函数同样好地获得所需的重复行数。
使用.value_counts()
函数获取重复行数的另一个好处是语法更简单。您可以简单地使用df.value_counts()
或,df.value_counts(dropna=False)
具体取决于您的数据框是否包含。如果您希望结果为数据框而不是系列,NaN
请链接使用。.reset_index()
解决方案 8:
df = pd.DataFrame({'one' : pd.Series([1., 1, 1, 3]), 'two' : pd.Series([1., 2., 1, 3] ), 'three' : pd.Series([1., 2., 1, 2] )})
df['str_list'] = df.apply(lambda row: ' '.join([str(int(val)) for val in row]), axis=1)
df1 = pd.DataFrame(df['str_list'].value_counts().values, index=df['str_list'].value_counts().index, columns=['Count'])
生成:
>>> df1
Count
1 1 1 2
3 2 3 1
1 2 2 1
如果索引值必须是一个列表,则可以进一步执行上述代码:
df1.index = df1.index.str.split()
生成:
Count
[1, 1, 1] 2
[3, 2, 3] 1
[1, 2, 2] 1
解决方案 9:
今天遇到了这个问题,想包含 NaN,所以我暂时用“”(空字符串)替换它们。如果您不明白,请发表评论 :)。此解决方案假设“”对您来说不是相关值。它也应该适用于数值数据(我已经成功测试过它,但不是广泛测试),因为在用 np.nan 替换“”后,pandas 会再次推断数据类型。
import pandas as pd
# create test data
df = pd.DataFrame({'test':['foo','bar',None,None,'foo'],
'test2':['bar',None,None,None,'bar'],
'test3':[None, 'foo','bar',None,None]})
# fill null values with '' to not lose them during groupby
# groupby all columns and calculate the length of the resulting groups
# rename the series obtained with groupby to "group_count"
# reset the index to get a DataFrame
# replace '' with np.nan (this reverts our first operation)
# sort DataFrame by "group_count" descending
df = (df.fillna('')\n .groupby(df.columns.tolist()).apply(len)\n .rename('group_count')\n .reset_index()\n .replace('',np.nan)\n .sort_values(by = ['group_count'], ascending = False))
df
test test2 test3 group_count
3 foo bar NaN 2
0 NaN NaN NaN 1
1 NaN NaN bar 1
2 bar NaN foo 1
解决方案 10:
要计算 DataFrame 中的行数,可以使用该方法value_counts
(Pandas 1.1.0):
df = pd.DataFrame({'A': [1, 1, 2, 2, 3], 'B': [10, 10, 20, 20, 30]})
df.value_counts().reset_index(name='counts').query('counts > 1')
输出:
A B counts
0 1 10 2
1 2 20 2
解决方案 11:
它非常简单:
df = pd.DataFrame({'one': pd.Series([True, True, True, False]),
'two': pd.Series([True, False, False, True]),
'three': pd.Series([True, False, False, False])})
rs = pd.DataFrame(df.value_counts(sort=False).index.to_list(), columns=df.columns)
rs["#"] = df.value_counts(sort=False).values
one two three #
0 False True False 1
1 True False False 2
2 True True True 1
但是,如果你只想告知这段代码就足够了:
df.value_counts(sort=False)
解决方案 12:
df.groupby(df.columns.tolist()).size().reset_index(name='count')
one two count
0 1 1 2
1 1 2 1
扫码咨询,免费领取项目管理大礼包!