Pandas:使用groupby和一个函数进行DataFrame过滤

4
使用Python 3.3和Pandas 0.10
我有一个由多个CSV文件连接而成的DataFrame。首先,我过滤掉Name列中包含特定字符串的所有值。结果看起来像这样(为简洁起见缩短了内容,实际上还有更多列):
Name    ID
'A'     1
'B'     2
'C'     3
'C'     3
'E'     4
'F'     4
...     ...

现在我的问题是,我想要删除一种特殊情况的“重复”值。 我想要删除所有ID重复(实际上是整行)的记录,其中映射到此ID的相应Name值相似。 在上面的示例中,我希望保留ID为1、2和3的行。 当ID = 4时,名称值是不相等的,我想要删除这些行。
我尝试使用以下代码行(基于此处的建议:Python Pandas:根据出现次数删除条目)。
代码:
df[df.groupby('ID').apply(lambda g: len({x for x in g['Name']})) == 1]

然而,这给了我一个错误: ValueError: Item wrong length 51906 instead of 109565! 编辑:
我还尝试使用transform(),但是这给了我一个错误:AttributeError: 'int' object has no attribute 'ndim'。非常感谢有关为什么每个函数的错误不同的解释!
此外,我想保留上面示例中ID = 3的所有行。
提前致谢, Matthijs
2个回答

5

我认为你想考虑每个分组中名称的唯一值数量,而不是长度len。使用nunique(),并查看这个很棒的过滤分组的配方。

df[df.groupby('ID').Name.transform(lambda x: x.nunique() == 1).astype('bool')]

如果你升级到 pandas 0.12 版本,你可以在分组上使用新的 filter 方法,这使得代码更加简洁明了。
df.groupby('ID').filter(lambda x: x.Name.nunique() == 1)

一般而言,有时候您确实需要知道组的长度,但是在某些情况下,我发现sizelen更安全,因为在某些情况下len会给我带来麻烦。


我总是忘记 transform! :) - Andy Hayden
哈哈。人们经常没有发现这一点--我认为我每周至少回答一个转换问题。 - Dan Allan
嗨,丹,谢谢!我明天会试一下你的代码,但到目前为止,它对我来说是有意义的。我不知道 nunique(),所以感谢你指出来。实际上,你能简要描述一下为什么你使用 transform() 而不是 apply() 吗? - Matthijs
2
apply将返回一个较短的Series,每个组只有一个条目。相反,我们希望得到与原始Series相同长度的Series,其中每个组的整个内容都映射为“True”或“False”块。然后,我们可以使用该布尔Series来屏蔽原始Series。有关更多信息,请参见文档 - Dan Allan
嗨,丹,我刚刚运行了你的代码,它非常好用。还要感谢你对transform()apply()的解释! - Matthijs

0

你可以先删除重复项:

In [11]: df = df.drop_duplicates()

In [12]: df
Out[12]:
  Name ID
0    A  1
1    B  2
2    C  3
4    E  4
5    F  4

根据groupby id进行分组,并且只考虑那些只有一个元素的情况:

In [13]: g = df.groupby('ID')

In [14]: size = (g.size() == 1)

In [15]: size
Out[15]:
ID
1      True
2      True
3      True
4     False
dtype: bool

In [16]: size[size].index
Out[16]: Int64Index([1, 2, 3], dtype=int64)

In [17]: df['ID'].isin(size[size].index)
Out[17]:
0     True
1     True
2     True
4    False
5    False
Name: ID, dtype: bool

通过以下方式进行布尔索引:

In [18]: df[df['ID'].isin(size[size].index)]
Out[18]:
  Name ID
0    A  1
1    B  2
2    C  3

谢谢你的帮助,安迪,但我会选择丹的答案。 - Matthijs

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接