我想在大熊猫中做一个groupby
,以获取一个数据帧,该数据帧具有用于groupby
的列,每个组的元素数以及其中的元素数作为列在每个组中,满足/不满足基于另一个列值的条件的元素数。
例如,像这样的输入:
type success
A True
B False
A False
C True
我想要类似的东西
type total numOfSuccess numOfFailure
A 2 1 1
B 1 0 1
C 1 1 0
在pyspark中,我这样做
import pyspark.sql.functions as F
df = df.groupBy("type").agg(\
F.count('*').alias('total'), \
F.sum(F.when(F.col('success')=="true", 1).otherwise(0)).alias('numOfSuccess'),
F.sum(F.when(F.col('success')!="true", 1).otherwise(0)).alias('numOfFails'))
在大熊猫中,我只能将total
和numOfSuccess
设置为:
df_new = df.groupby(['type'], as_index=False)['success'].agg({'total':'count', 'numOfSuccess':'sum'})
或仅将总数设为:
df = df.groupby(['type']).size().reset_index(name='NumOfReqs')
但是我无法获得第三列numOfFailures
,而且如果还有替代方法而不是对布尔值求和,那会更好,因为我认为in可以扩展到其他情况,也更容易。
我该怎么做?
答案 0 :(得分:2)
将groupby
与GroupBy.size
一起用于计数所有数据,然后需要对每个类别的计数进行透视-使用GroupBy.size
和unstack
,crosstab
或{{3 }}:
df1 = df.groupby('type').size().reset_index(name='count')
df2 = (df.groupby(['type', 'success']).size().unstack(fill_value=0)
.rename(columns={True:'numOfSuccess', False:'numOfFails'}))
df2
的替代项:
df2 = pd.crosstab(df['type'], df['success'])
.rename(columns={True:'numOfSuccess', False:'numOfFails'}))
或者:
df2 = (df.pivot_table(index='type', columns='success', fill_value=0, aggfunc='size')
.rename(columns={True:'numOfSuccess', False:'numOfFails'}))
df_new = df1.join(df2, on='type')
print (df_new)
type count numOfFails numOfSuccess
0 A 2 1 1
1 B 1 1 0
2 C 1 0 1
另一种解决方案是在pivot_table
中使用参数margins
并通过使用crosstab
进行索引来删除最后一行:
df = (pd.crosstab(df['type'], df['success'], margins=True)
.rename(columns={True:'numOfSuccess', False:'numOfFails', 'All':'count'})
.iloc[:-1]
.reset_index()
.rename_axis(None, axis=1))
print (df)
type numOfFails numOfSuccess count
0 A 1 1 2
1 B 1 0 1
2 C 0 1 1
编辑:如果True
或False
不存在,请添加iloc
来添加缺少的列:
print (df)
type success
0 A True
1 B True
2 A True
3 C True
df1 = df.groupby('type').size().reset_index(name='count')
df2 = (df.groupby(['type', 'success']).size().unstack(fill_value=0)
.reindex(columns=[True, False], fill_value=0)
.rename(columns={True:'numOfSuccess', False:'numOfFails'}))
df_new = df1.join(df2, on='type')
print (df_new)
type count numOfSuccess numOfFails
0 A 2 2 0
1 B 1 1 0
2 C 1 1 0