#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. Есть ли у вас доказательства, подтверждающие ваше утверждение о том, что это быстрее?