Панды заполняются с помощью groupby

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

#python #панды

Вопрос:

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

Например, у меня есть этот фрейм данных:

 one | two | three
1      1     10
1      1     nan
1      1     nan
1      2     nan
1      2     20
1      2     nan
1      3     nan
1      3     nan
 

Я хотел использовать ключи столбца one и two который похож, и если столбец three не полностью nan, то вменить существующее значение из строки похожих ключей со значением в столбце ‘3’.

Вот мой желаемый результат:

 one | two | three
1      1     10
1      1     10
1      1     10
1      2     20
1      2     20
1      2     20
1      3     nan
1      3     nan
 

Вы можете видеть, что ключи 1 и 3 не содержат никакого значения, потому что существующее значение не существует.

Я пытался использовать groupby fillna() :

 df['three'] = df.groupby(['one','two'])['three'].fillna()
 

что выдало мне ошибку.

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

 df['three'] = df.groupby(['one','two'], sort=False)['three'].ffill()
 

Ответ №1:

Если для каждой группы используется только одно значение, отличное от NaN ffill (прямое заполнение) и bfill (обратное заполнение) для каждой группы, поэтому необходимо apply с lambda :

 df['three'] = df.groupby(['one','two'], sort=False)['three']
                .apply(lambda x: x.ffill().bfill())
print (df)
   one  two  three
0    1    1   10.0
1    1    1   10.0
2    1    1   10.0
3    1    2   20.0
4    1    2   20.0
5    1    2   20.0
6    1    3    NaN
7    1    3    NaN
 

Но если несколько значений для каждой группы и требуется заменить NaN на некоторую константу — например mean , по группе:

 print (df)
   one  two  three
0    1    1   10.0
1    1    1   40.0
2    1    1    NaN
3    1    2    NaN
4    1    2   20.0
5    1    2    NaN
6    1    3    NaN
7    1    3    NaN

df['three'] = df.groupby(['one','two'], sort=False)['three']
                .apply(lambda x: x.fillna(x.mean()))
print (df)
   one  two  three
0    1    1   10.0
1    1    1   40.0
2    1    1   25.0
3    1    2   20.0
4    1    2   20.0
5    1    2   20.0
6    1    3    NaN
7    1    3    NaN
 

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

1. @jezrael: есть ли какая-либо причина, по которой force использовать apply в вашем ответе? Я спрашиваю, потому что я попробовал direct ffill и bfill , и он возвращает правильный результат: df['three'] = df.groupby(['one', 'two'])['three'].ffill().bfill()

2. @Andy L. Это работает правильно, потому что последняя группа — это только NaN-группа. Если изменить образец данных для первой только NaN-группы (от 10 до NaN), ваше решение не удалось. Причина в том, что последнее заполнение работает не для групп, а для серии, возвращаемой groupby ffill .

3. ах, я забыл, что bfill обратное заполнение выходных рядов ffill , а не groupby . Спасибо за ответы

4. Могу ли я спросить, как я могу применить df['three'] = df.groupby(['one','two'], sort=False)['three'].apply(lambda x: x.ffill().bfill()) к нескольким столбцам three, four, five, etc , а не только three к тем, которые нуждаются в groupby one и two и fillna?

5. @ahbon — Использовать cols = ['three','four','five'] и df[cols] = df.groupby(['one','two'], sort=False)[cols].apply(lambda x: x.ffill().bfill())

Ответ №2:

Вы можете сортировать данные по столбцу с пропущенными значениями, затем groupby и forwardfill:

 df.sort_values('three', inplace=True)
df['three'] = df.groupby(['one','two'])['three'].ffill()