我有一个dataframe
,其中包含群组标签(' B')和每个群组的元素(' A')。组标签是有序的,我想知道组i中有多少元素出现在组i + 1中。
一个例子:
df= pd.DataFrame({ 'A': ['a','b','c','a','c','a','d'], 'B' : [1,1,1,2,2,3,3]})
A B
0 a 1
1 b 1
2 c 1
3 a 2
4 c 2
5 a 3
6 d 3
所需的输出类似于:
B
1 NaN
2 2
3 1
解决这个问题的一种方法是计算组I和组i + 1的并集中的不同元素的数量,然后减去每个组中不同元素的数量。我试过了:
pd.rolling_apply(grp['A'], lambda x: len(x.unique()),2)
但这会产生错误:
AttributeError: 'Series' object has no attribute 'type'
如何让它与rolling_apply
一起使用,还是有更好的方法来解决这个问题?
答案 0 :(得分:1)
使用集合并移动结果的方法:
首先对数据帧进行分组,然后将每个组的A列转换为集合:
In [86]: grp = df.groupby('B')
In [87]: s = grp.apply(lambda x : set(x['A']))
In [88]: s
Out[88]:
B
1 set([a, c, b])
2 set([a, c])
3 set([a, d])
dtype: object
要计算连续集之间的交集,请进行移位版本(我将NaN替换为空集以进行下一步):
In [89]: s2 = s.shift(1).fillna(set([]))
In [90]: s2
Out[90]:
B
1 set([])
2 set([a, c, b])
3 set([a, c])
dtype: object
合并两个系列并计算交叉点的长度:
In [91]: s.combine(s2, lambda x, y: len(x.intersection(y)))
Out[91]:
B
1 0
2 2
3 1
dtype: object
执行最后一步的另一种方法(对于集&
意味着intersection
):
df = pd.concat([s, s2], axis=1)
df.apply(lambda x: len(x[0] & x[1]), axis=1)
滚动应用不起作用的原因是1)你提供了一个GroupBy对象而不是一个系列,2)它只适用于数值。