使用pandas按组获取计数

5
我有一个Pandas数据框,其中包含以下数据:

ID  year_month_id   Class
1   201612          A
2   201612          D
3   201612          B
4   201612          Other
5   201612          Other
6   201612          Other
7   201612          A
8   201612          Other
9   201612          A
1   201701          B

因此,一个ID在特定月份可以属于任何一个班级,下个月他的班级可能会改变。 现在我想做的是为每个ID获取它已经属于某个班级的月份数以及最新属于的班级。如下所示:

ID  Class_A Class_B Class_D Other Latest_Class
1   2        3       4         0    B
2   12       0       0         0    D

我该如何在Python中实现这个功能? 有人能帮我吗? 另外,由于真实数据集非常庞大,手动验证是不可能的,那么我该如何获取属于多个类别的ID列表?

4个回答

4
我们可以使用数据透视表和concat函数。
ndf = df.pivot_table(index=['ID'],columns=['Class'],aggfunc='count',fill_value=0)\
    .xs('year_month_id', axis=1, drop_level=True)

ndf['latest'] = df.sort_values('ID').groupby('ID')['Class'].tail(1).values

Class  A  B  D  Other latest
ID                          
1      1  1  0      0      B
2      0  0  1      0      D
3      0  1  0      0      B
4      0  0  0      1  Other
5      0  0  0      1  Other
6      0  0  0      1  Other
7      1  0  0      0      A
8      0  0  0      1  Other
9      1  0  0      0      A

1
使用 pivot 在这里是一个不错的选择,我猜应该是最快的。 - cs95
1
当一个人只旋转2列并使用count作为aggfunc,填充零(确切地说是这种情况)时,值得考虑使用pd.crosstab - jo9k
非常感谢@Dark。由于数据量很大,我无法手动检查每个ID的输出是否正确,我该如何获取具有多个列中条目为1的ID列表。 - Shuvayan Das

3
您可以通过使用聚合函数groupby和计数函数count来获取计数,再通过unstack函数进行数据重塑。最后,使用drop_duplicates函数添加新列:
df1 = df.groupby(['ID','Class'])['year_month_id'].count().unstack(fill_value=0)
df1['Latest_Class'] = df.drop_duplicates('ID', keep='last').set_index('ID')['Class']
print (df1)
Class  A  B  D  Other Latest_Class
ID                                
1      1  1  0      0            B
2      0  0  1      0            D
3      0  1  0      0            B
4      0  0  0      1        Other
5      0  0  0      1        Other
6      0  0  0      1        Other
7      1  0  0      0            A
8      0  0  0      1        Other
9      1  0  0      0            A

如果我的回答有什么问题,请下投票者告诉我,这样我就可以纠正它。谢谢。 - jezrael

3

您可以使用groupby + value_counts + unstack来统计所参加的课程数量 -

g = df.groupby('ID')
i = g.Class.value_counts().unstack(fill_value=0)

要获取最后一个类,使用groupby+ last
j = g.Class.last()

连接字符串以获取结果 -

pd.concat([i, j], 1).rename(columns={'Class': 'LastClass'})

    A  B  D  Other LastClass
ID                          
1   1  1  0      0         B
2   0  0  1      0         D
3   0  1  0      0         B
4   0  0  0      1     Other
5   0  0  0      1     Other
6   0  0  0      1     Other
7   1  0  0      0         A
8   0  0  0      1     Other
9   1  0  0      0         A

要获取一行中有超过1个ID的列表,请使用sum +掩码 -
k = i.sum(axis=1)
k[k > 1]

ID
1    2
dtype: int64

1
如果回答有什么问题,请下投票者告诉我,这样我就可以纠正它。谢谢。 - jezrael
2
@jezrael 有人把圣诞节当成愚人节了。 - cs95

1
当只需要将两列作为轴并使用count作为aggfunc时,填充缺失条目为零(正是这种情况),考虑使用pd.crosstab
 >> new_df = pd.crosstab(df.ID, df.Class)
 >> new_df
Class  A  B  D  Other
ID
1      1  1  0      0
2      0  0  1      0
3      0  1  0      0
4      0  0  0      1
5      0  0  0      1
6      0  0  0      1
7      1  0  0      0
8      0  0  0      1
9      1  0  0      0

你可以通过按ID分组并选择最后一个条目来获取初始数据帧中类的最后一个值:
>> df.groupby('ID').Class.last()
ID
1        B
2        D
3        B
4    Other
5    Other
6    Other
7        A
8    Other
9        A

然后,您可以使用连接将它们组合起来:
>> new_df = pd.concat([new_df, df.groupby('ID').Class.last()], 1)
    A  B  D  Other  Class
ID
1   1  1  0      0      B
2   0  0  1      0      D
3   0  1  0      0      B
4   0  0  0      1  Other
5   0  0  0      1  Other
6   0  0  0      1  Other
7   1  0  0      0      A
8   0  0  0      1  Other
9   1  0  0      0      A

而要得到您想要的精确输出:

>> new_df = new_df.rename(columns={'Class':'LastClass'})
    A  B  D  Other LastClass
ID
1   1  1  0      0         B
2   0  0  1      0         D
3   0  1  0      0         B
4   0  0  0      1     Other
5   0  0  0      1     Other
6   0  0  0      1     Other
7   1  0  0      0         A
8   0  0  0      1     Other
9   1  0  0      0         A

将所有内容合并为一行,如下所示:

将所有内容合并为一行:

>> new_df = pd.concat([pd.crosstab(df.ID, df.Class),df.groupby('ID').Class.last()],1).rename(columns={'Class':'LastClass'})

>> new_df
    A  B  D  Other LastClass
ID
1   1  1  0      0         B
2   0  0  1      0         D
3   0  1  0      0         B
4   0  0  0      1     Other
5   0  0  0      1     Other
6   0  0  0      1     Other
7   1  0  0      0         A
8   0  0  0      1     Other
9   1  0  0      0         A

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