Подсчет уникальных значений с помощью pandas groupby

#python #python-3.x #pandas #dataframe

#python #pandas #группировать по

Вопрос:

У меня есть данные следующего вида:

 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
 

Я уверен, что есть способ сделать это более чисто и без использования цикла, но я просто не могу с этим справиться. Любая помощь будет высоко оценена.

Ответ №1:

Я думаю, вы можете использовать SeriesGroupBy.nunique :

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

Другое решение с unique помощью , затем создайте новое df по DataFrame.from_records , измените на Series по stack и последнее value_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
 

Комментарии:

1. Я тестирую это с df = pd.DataFrame({ 'group': [1, 1, 2, 3, 3, 3, 4], 'param': ['a', 'c', 'b', np.nan, 'c', 'a', np.nan] }) помощью, но ваш код возвращает разные выходные данные, потому что в каждом используется только первый уникальный элемент списка group . Мой код возвращает все уникальные значения. Пожалуйста, проверьте это, если я понимаю, что вам нужно. Спасибо.

2. Как мы получаем имена столбцов

3. @dondapati — добавить .reset_index()

Ответ №2:

Это просто дополнение к решению на случай, если вы хотите вычислять не только уникальные значения, но и другие агрегированные функции:

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

Ответ №3:

Приведенные выше ответы тоже работают, но в случае, если вы хотите добавить столбец с unique_counts в существующий фрейм данных, вы можете сделать это с помощью 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
 

Ответ №4:

Я знаю, что прошло много времени с тех пор, как это было опубликовано, но я думаю, что это тоже поможет. Я хотел подсчитать уникальные значения и отфильтровать группы по количеству этих уникальных значений, вот как я это сделал:

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

Ответ №5:

Этот способ быстрее и удобнее:

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

Комментарии:

1. Есть ли у вас доказательства, подтверждающие ваше утверждение о том, что это быстрее?