#python #pandas #dataframe #group-by
Вопрос:
Я хочу найти наиболее распространенное значение для каждой группы. ОБНОВЛЕНИЕ: Если есть реальные значения и NAN, я хочу отказаться от NAN. Я хочу только НаН, когда это все ценности.
В некоторых моих группах отсутствуют все их данные. И я хотел бы, чтобы результатом в этих случаях были отсутствующие данные (NaN) как наиболее распространенное значение.
В этих случаях DataFrame.groupby.agg(pd.Series.mode)
функция возвращает пустое категориальное значение. Чего я хочу, так это Нэн.
Ниже приведен пример игрушки …
data = """
Group, Value
A, 1
A, 1
A, 1
B, 2
C, 3
C,
C,
D,
D,
"""
from io import StringIO
df = (
pd.read_csv(StringIO(data),
skipinitialspace=True)
.astype('category')
)
df.groupby('Group')['Value'].agg(pd.Series.mode)
Что дает результат …
A 1.0
B 2.0
C 3.0
D [], Categories (3, float64): [1.0, 2.0, 3.0]
Name: Value, dtype: object
Мой вопрос: есть ли способ получить NAN или обнаружить пустую категорию и сделать ее NaN. ОБНОВЛЕНО: Отмечая, что я не могу использовать dropna=False
, так как это дало бы мне неправильный ответ на C выше.
В контексте мой исходный фрейм данных содержит 27 миллионов строк, а мой сгруппированный фрейм-6 миллионов строк. Поэтому я хочу избежать медленных решений.
Комментарии:
1. Ты пробовал
df.replace('', 'NaN').groupby('Group')['Value'].agg(pd.Series.mode)
?2. там, где у меня есть значения, отличные от NaN, я хочу, чтобы метод mode игнорировал NaN. Таким образом, сопоставление NAN с чем-то другим в данном случае не работает.
Ответ №1:
Вы можете подать pd.Series.mode
заявку, а затем pd.to_numeric
с errors="coerce"
:
x = df.groupby("Group")["Value"].agg(pd.Series.mode)
print(pd.to_numeric(x, errors="coerce"))
С принтами:
Group
A 1.0
B 2.0
C 3.0
D NaN
Name: Value, dtype: float64
Ответ №2:
Вы можете использовать пользовательскую агрегацию и проверить, если isna().all()
:
df.groupby('Group')['Value'].agg(lambda x: x.mode() if not x.isna().all() else np.nan)
# Group
# A 1.0
# B 2.0
# C 3.0
# D NaN
# Name: Value, dtype: float64
Из любопытства, приурочено к df = pd.concat([df] * 100000)
(900 000 строк):
>>> def coerce(df):
... x = df.groupby("Group")["Value"].agg(pd.Series.mode)
... return pd.to_numeric(x, errors="coerce")
>>> %timeit coerce(df)
22.1 ms ± 2.79 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
>>> def isna(df):
... return df.groupby('Group')['Value'].agg(lambda x: x.mode() if not x.isna().all() else np.nan)
>>> %timeit isna(df)
20.9 ms ± 732 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
Комментарии:
1. Спасибо за тест, очевидно
isna()
, что версия быстрее (для больших кадров данных). 1