在Pandas DataFrame中查找违反一对一映射的行
我有一个数据表,长得像这样:
| index | col_1 | col_2 |
| 0 | A | 11 |
| 1 | B | 12 |
| 2 | B | 12 |
| 3 | C | 13 |
| 4 | C | 13 |
| 5 | C | 14 |
在这个表里,col_1
和 col_2
之间的关系可能不是一一对应的,这可能是因为数据有问题。
我该如何使用Pandas来找出哪些行的 col_1
和 col_2
的值不符合一一对应的规则呢?
在这个例子中,最后三行就是问题行,因为字母C可以对应数字13或14。
4 个回答
0
我刚开始学Python,但我找到了一种方法,可以把所有独特的组合放到一个列表里,然后筛选出那些没有唯一映射的组合。
data = pd.DataFrame({'Col_1': ['A', 'B', 'B', 'C', 'C', 'C'], 'Col_2': [11,12,12,13,13,14]})
combos = []
for x, y in enumerate(range(len(data['Col_1']))):
combo = '%s_%s' %(data['Col_1'][x], data['Col_2'][x])
combos.append(combo)
data.index = data['Col_1']
for item in combos:
if len([comb for comb in combos if item[2:] in comb[2:]]) != len([comb for comb in combos if item[0] in comb[0]]):
data = data.drop(item[0])
data.reset_index(drop=True)
0
我会使用一个 collections.Counter
,因为在一列中每个项目出现多次就打破了一对一的对应关系:
>>> import pandas
>>> import numpy
>>> import collections
>>> df = pandas.DataFrame(numpy.array([['a', 1],['b', 2], ['b', 3], ['c', 3]]))
>>> df
0 1
0 a 1
1 b 2
2 b 3
3 c 3
>>> collections.Counter(df[0])
Counter({'b': 2, 'a': 1, 'c': 1})
>>> violations1 = [k for k, v in collections.Counter(df[0]).items() if v > 1]
>>> violations2 = [k for k, v in collections.Counter(df[1]).items() if v > 1]
>>> violations1
['b']
>>> violations2
['3']
1
我测试了这个代码 g.transform(lambda x: len(x.unique())),效果不错,但速度比较慢,尤其是当组很多的时候。下面的代码运行得快多了,所以我把它放在这里。
df2 = pd.DataFrame(df[['col1', 'col2']].groupby(['col1','col2']).size(),columns=['count'])
df2.reset_index(inplace=True)
df3 = pd.DataFrame(df2.groupby('col1').size(), columns=['count'])
df4 = df3[df3['count']>1]
df_copy = df.copy()
df_copy.set_index('col1', inplace=True)
df_outlier = df_copy.ix[df4.index]
3
你可以使用一种转换方法,来计算每组中独特对象的数量。首先,查看这些特定列的子集,然后根据某一列进行分组:
In [11]: g = df[['col1', 'col2']].groupby('col1')
In [12]: counts = g.transform(lambda x: len(x.unique()))
In [13]: counts
Out[13]:
col2
0 1
1 1
2 1
3 2
4 2
5 2
剩下的列(如果不是全部的话)
In [14]: (counts == 1).all(axis=1)
Out[14]:
0 True
1 True
2 True
3 False
4 False
5 False
dtype: bool