Подтвердить что ты не робот

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()

Спасибо, куча.

4b9b3361

Ответ 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

fillna + groupby + transform + mean

Это кажется интуитивно понятным:

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