【发布时间】:2020-05-23 15:21:33
【问题描述】:
如果这是一个骗局,请指路。我checked 几个questions 来了close 但并没有解决我的问题。
我有一个假人DataFrame,如下:
grp Ax Bx Ay By A_match B_match
0 foo 3 2 2 2 False True
1 foo 2 1 1 0 False False
2 foo 4 3 0 3 False True
3 foo 4 3 1 4 False False
4 foo 4 4 3 0 False False
5 bar 3 0 3 0 True True
6 bar 3 4 0 3 False False
7 bar 1 2 1 2 True True
8 bar 1 3 4 1 False False
9 bar 1 1 0 3 False False
我的目标是比较As 和Bs 列并通过grp 总结结果:
A_match B_match
False True False True
grp
bar 3 2 3 2
foo 5 0 3 2
所以我添加了两个_match 列如下,得到上面的df:
df['A_match'] = df['Ax'].eq(df['Ay'])
df['B_match'] = df['Bx'].eq(df['By'])
根据我的理解,我希望我能做这样的事情,但它不起作用:
df.groupby('grp')[['A_match', 'B_match']].agg(pd.Series.value_counts)
# trunc'd Traceback:
# ... ValueError: no results ...
# ... During handling of the above exception, another exception occurred: ...
# ... ValueError: could not broadcast input array from shape (5,7) into shape (5)
在我的实际数据中,我能够通过以相当不令人满意的方式将 _matches 强制为 pd.Categorical 来回避这个问题。但是,我注意到成功和失败,即使使用这些虚拟数据,即使使用pd.Categorial,我也会得到与上述完全相同的错误:
df['A_match'] = pd.Categorical(df['Ax'].eq(df['Ay']).values, categories=[True, False])
df['B_match'] = pd.Categorical(df['Bx'].eq(df['By']).values, categories=[True, False])
df.groupby('grp')[['A_match', 'B_match']].agg(pd.Series.value_counts)
# ... ValueError: could not broadcast input array from shape (5,7) into shape (5)
这对我来说毫无意义 - 形状 (5, 7) 是从哪里来的?上次我检查时,每个 agg 都会传递一个形状 (5,)。甚至agg 的运行似乎与我想象的不同,它应该针对Series 运行:
>>> df.groupby('grp')[['A_match', 'B_match']].agg(lambda x: type(x))
A_match B_match
grp
bar <class 'pandas.core.series.Series'> <class 'pandas.core.series.Series'>
foo <class 'pandas.core.series.Series'> <class 'pandas.core.series.Series'>
# Good - it's Series, I should be able to call value_counts directly?
>>> df.groupby('grp')[['A_match', 'B_match']].agg(lambda x: x.value_counts())
# AttributeError: 'DataFrame' object has no attribute 'value_counts' <-- ?!?!? Where did 'DataFrame' come from?
我最终能够使用以下组合,但仍然相当不满意,因为它引入了许多不必要的 axis 名称。
>>> df.melt(id_vars='grp', value_vars=['A_match', 'B_match']).reset_index().pivot_table(index='grp', columns=['variable', 'value'], aggfunc=pd.Series.count)
index
variable A_match B_match
value False True False True
grp
bar 3 2 3 2
foo 5 0 3 2
这两种方法似乎都比较做作,以实现应该相对常见的用途。我想我的问题是,我在这里忽略了一些明显的东西吗?
【问题讨论】: