使用pandas groupby计算唯一值的数量

132

我有以下形式的数据:

df = pd.DataFrame({
    'group': [1, 1, 2, 3, 3, 3, 4],
    'param': ['a', 'a', 'b', np.nan, 'a', 'a', np.nan]
})
print(df)

#    group param
# 0      1     a
# 1      1     a
# 2      2     b
# 3      3   NaN
# 4      3     a
# 5      3     a
# 6      4   NaN

组内的非空值始终相同。我想为每个组(存在值的地方)计算一次非空值,然后找到每个值的总计数。

我目前正在以下(笨拙而低效)的方式进行:

param = []
for _, group in df[df.param.notnull()].groupby('group'):
    param.append(group.param.unique()[0])
print(pd.DataFrame({'param': param}).param.value_counts())

# a    2
# b    1

我相信有一种更简洁的方法可以做到这一点,而且不需要使用循环,但我似乎无法解决它。任何帮助将不胜感激。

5个回答

217

我认为你可以使用SeriesGroupBy.nunique

print (df.groupby('param')['group'].nunique())
param
a    2
b    1
Name: group, dtype: int64

使用unique方法,创建一个新的df,再通过DataFrame.from_records重塑为Series,最后使用stackvalue_counts函数:

a = df[df.param.notnull()].groupby('group')['param'].unique()
print (pd.DataFrame.from_records(a.values.tolist()).stack().value_counts())
a    2
b    1
dtype: int64

我使用 df = pd.DataFrame({ 'group': [1, 1, 2, 3, 3, 3, 4], 'param': ['a', 'c', 'b', np.nan, 'c', 'a', np.nan] }) 进行测试,但你的代码返回了不同的输出,因为它只使用了每个 group 中第一个唯一元素的列表。我的代码返回所有唯一值。请检查一下,看看我是否理解了你的需求。谢谢。 - jezrael
我们如何获取列名 - dondapati
2
@dondapati - 添加 .reset_index() - jezrael
请注意,此解决方案只能生成一个系列(series),而不是一个数据框(dataframe)。使用 @datapug 的解决方案可以创建一个数据框。 - Kane Chew

84

如果您想计算不仅是唯一值,而是其他聚合函数,那么这只是解决方案的附加部分:

df.groupby(['group']).agg(['min', 'max', 'count', 'nunique'])

这个解决方案将创建一个数据框。 - Kane Chew

20

上面的回答也可以,但是如果你想向现有数据框中添加一个包含唯一计数的列,可以使用 transform函数实现

df['distinct_count'] = df.groupby(['param'])['group'].transform('nunique')

输出:

   group param  distinct_count
0      1     a             2.0
1      1     a             2.0
2      2     b             1.0
3      3   NaN             NaN
4      3     a             2.0
5      3     a             2.0
6      4   NaN             NaN

并且检查群组计数是否由 @jezrael 强调。

print (df.groupby('param')['group'].nunique())
param
a    2
b    1
Name: group, dtype: int64

9

我知道这篇文章发表已经有一段时间了,但我认为这也会对你有所帮助。 我想要计算唯一值并按这些唯一值的数量过滤组,以下是我的做法:

df.groupby('group').agg(['min','max','count','nunique']).reset_index(drop=False)

0

这种方式更快,更方便:

df.groupby('param').agg({'group':lambda x: len(pd.unique(x))})

比什么更快?你能展示一下你用来比较替代方法时间的代码和数据吗? - Sycorax

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