Pandas: заполнение отсутствующих значений по средним значениям в каждой группе
Это должно быть просто, но ближайшая вещь, которую я нашел, - это сообщение:
pandas: заполнение отсутствующих значений внутри группы, и я все еще не могу решить свою проблему....
Предположим, что у меня есть следующий файл данных
df = pd.DataFrame({'value': [1, np.nan, np.nan, 2, 3, 1, 3, np.nan, 3], 'name': ['A','A', 'B','B','B','B', 'C','C','C']})
name value
0 A 1
1 A NaN
2 B NaN
3 B 2
4 B 3
5 B 1
6 C 3
7 C NaN
8 C 3
и я хотел бы заполнить "NaN" средним значением в каждой группе "имя", т.е.
name value
0 A 1
1 A 1
2 B 2
3 B 2
4 B 3
5 B 1
6 C 3
7 C 3
8 C 3
Я не уверен, куда идти:
grouped = df.groupby('name').mean()
Спасибо, куча.
Ответы
Ответ 1
Один из способов - использовать transform
:
>>> df
name value
0 A 1
1 A NaN
2 B NaN
3 B 2
4 B 3
5 B 1
6 C 3
7 C NaN
8 C 3
>>> df["value"] = df.groupby("name").transform(lambda x: x.fillna(x.mean()))
>>> df
name value
0 A 1
1 A 1
2 B 2
3 B 2
4 B 3
5 B 1
6 C 3
7 C 3
8 C 3
Ответ 2
@DSM имеет правильный ответ IMO, но я хотел бы поделиться своим обобщением и оптимизацией вопроса: несколько столбцов для группового и имеющих несколько столбцов значений:
df = pd.DataFrame(
{
'category': ['X', 'X', 'X', 'X', 'X', 'X', 'Y', 'Y', 'Y'],
'name': ['A','A', 'B','B','B','B', 'C','C','C'],
'other_value': [10, np.nan, np.nan, 20, 30, 10, 30, np.nan, 30],
'value': [1, np.nan, np.nan, 2, 3, 1, 3, np.nan, 3],
}
)
... дает...
category name other_value value
0 X A 10.0 1.0
1 X A NaN NaN
2 X B NaN NaN
3 X B 20.0 2.0
4 X B 30.0 3.0
5 X B 10.0 1.0
6 Y C 30.0 3.0
7 Y C NaN NaN
8 Y C 30.0 3.0
В этом обобщенном случае мы хотели бы сгруппировать по category
и name
и называть только value
.
Это можно решить следующим образом:
df['value'] = df.groupby(['category', 'name'])['value']\
.transform(lambda x: x.fillna(x.mean()))
Обратите внимание на список столбцов в предложении group-by и выберите столбец value
сразу после группового. Это превращает трансформацию только в этот конкретный столбец. Вы можете добавить его до конца, но затем вы запустите его для всех столбцов, чтобы только выпустить все, кроме одного столбца измерения в конце. Стандартный планировщик запросов SQL мог бы оптимизировать это, но pandas (0.19.2), похоже, не делает этого.
Тест производительности путем увеличения набора данных, выполняя...
big_df = None
for _ in range(10000):
if big_df is None:
big_df = df.copy()
else:
big_df = pd.concat([big_df, df])
df = big_df
... подтверждает, что это увеличивает скорость, пропорциональную количеству столбцов, которые вам не нужно приписывать:
import pandas as pd
from datetime import datetime
def generate_data():
...
t = datetime.now()
df = generate_data()
df['value'] = df.groupby(['category', 'name'])['value']\
.transform(lambda x: x.fillna(x.mean()))
print(datetime.now()-t)
# 0:00:00.016012
t = datetime.now()
df = generate_data()
df["value"] = df.groupby(['category', 'name'])\
.transform(lambda x: x.fillna(x.mean()))['value']
print(datetime.now()-t)
# 0:00:00.030022
В заключительной заметке вы можете еще более обобщить, если хотите наложить более одного столбца, но не все:
df[['value', 'other_value']] = df.groupby(['category', 'name'])['value', 'other_value']\
.transform(lambda x: x.fillna(x.mean()))
Ответ 3
Я бы сделал это так.
df.loc[df.value.isnull(), 'value'] = df.groupby('group').value.transform('mean')
Ответ 4
Это кажется интуитивно понятным:
df['value'] = df['value'].fillna(df.groupby('name')['value'].transform('mean'))
Синтаксис groupby
+ transform
отображает групповое среднее значение на индекс исходного кадра данных. Это примерно эквивалентно решению @DSM, но избавляет от необходимости определять анонимную функцию lambda
.
Ответ 5
Рекомендуемый высокоуровневый ответ работает только для pandas Dataframe с двумя столбцами. Если вместо этого используется больше случаев использования столбцов:
df['Crude_Birth_rate'] = df.groupby("continent").Crude_Birth_rate.transform(
lambda x: x.fillna(x.mean()))
Ответ 6
def groupMeanValue(group):
group['value'] = group['value'].fillna(group['value'].mean())
return group
dft = df.groupby("name").transform(groupMeanValue)
Ответ 7
df.fillna(df.groupby(['name'], as_index=False).mean(), inplace=True)
Ответ 8
Вы также можете использовать "dataframe or table_name".apply(lambda x: x.fillna(x.mean()))
.
Ответ 9
Я только что сделал это
df.fillna(df.mean(), inplace=True)
Все отсутствующие значения в вашем DataFrame будут заполняться средним значением. Если это то, что вы ищете. Это сработало для меня. Это просто и выполняет свою работу.