замена значений во фрейме данных на основе значений сводной таблицы

#python #pandas

#python #pandas

Вопрос:

Я хочу заменить значения nan в «возрастных столбцах» фрейма данных на основе значений, приведенных в сводной таблице,

«0 как женский, 1 как мужской»

 Example of df

Pclass Gender Age
  3      1     22
  1      0     38
  2      1     27
  3      0    NaN

Pivot table
            Age
    Gender 0  1
    PClass 
    1     40  35
    2     30  28
    3     25  21
 

например, если возраст парня пропущен, и если он / она имеет класс 3 и пол 0, то его возраст равен 25.

У меня около 100 строк, которые необходимо обновить, есть ли быстрый способ?

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

1. пожалуйста, предоставьте текст (не изображение) вашего df. Например, вы можете использовать df.to_dict() .

2. в nan столбце Age нет s…

3. Я только что обновил текст

Ответ №1:

Я бы преобразовал сводную таблицу в обычный df

pdf = pivot_table.stack().reset_index()

затем объедините с nan df помощью и combine_first

 nan_df = df.loc[df['Age'].isna(), ['Pclass', 'Gender']].merge(pdf, how='left')
df.set_index(['Pclass', 'Gender']).combine_first(nan_df.set_index(['Pclass', 'Gender'])).reset_index()
 
    Pclass  Gender   Age
0       1       0  38.0
1       2       1  27.0
2       3       0  25.0
3       3       1  22.0
 

Ответ №2:

Вы можете использовать сначала создать pivot_table и объединить его обратно df с дополнительным столбцом из поворота и заменить значения, если NaN наблюдается

 Example of df

Pclass Gender Age
  3      1     22
  1      0     38
  2      1     27
  3      0    NaN

Pivot table
            Age
    Gender 0  1
    PClass 
    1     40  35
    2     30  28
    3     25  21
 
 import pandas as pd
import numpy as np

df = pd.DataFrame(columns=['PClass','Gender','Age'])
df['PClass'] = [3,1,2,3]
df['Gender'] = [1,0,1,0]
df['Age'] = [22,38,27,np.nan]

df_pivot = pd.pivot_table(df,index=['PClass'],columns=['Gender'],values=['Age'],aggfunc='mean',fill_value=0) ### you can choose your own aggfunc
### I have taken `mean` here , but there ae a bunch of available options

df_pivot = df_pivot.unstack().reset_index().rename(columns={0:'Avg_Age_Pivot'})

df = pd.merge(df,df_pivot[['PClass','Gender','Avg_Age_Pivot']],on=['PClass','Gender'])

def replace_na(inp):
     inp = inp.values
     if pd.isnull(inp[0]):
        return inp[1]
     return inp[0]
 
 
df['Age'] = df[['Age','Avg_Age']].apply(replace_na,axis=1)
 
 df _pivot O/P --->

>>> pd.pivot_table(df,index=['PClass'],columns=['Gender'],values=['Age'],aggfunc='mean') ### you can choose your own aggfunc
         Age      
Gender     0     1
PClass            
1       38.0   NaN
2        NaN  27.0
3        NaN  22.0

 

Далее вы можете решить сохранить Avg_Age_Pivot столбец или удалить его.

Также я заметил, что при объеме предоставленных вами данных в сводной таблице были NaN значения, поэтому вы не видите желаемого результата с текущими df значениями

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

1. Большое вам спасибо! Однако я не совсем понимаю, что вы подразумеваете под значениями «NaN» в сводной таблице, поскольку в ней ровно 3×2 и 6 записей.

2. Добавлен df_pivot вывод в ответе для сводного индекса, где сами данные отсутствовали, функция aggfunc вернет NaN

3. О, я вижу! Это не фактические данные, не беспокойтесь. Спасибо

Ответ №3:

Пожалуйста, ознакомьтесь с этим подходом. Создал общий столбец с именем new, объединив столбцы ‘PClass’ и ‘Gender’. Затем используется map и df.fillna для замены значений NaN. Мне пришлось создать этот новый столбец, потому что я могу применить map метод только на pd.series .

Входные данные:

 import io
df1  = pd.read_csv(io.StringIO("""
PClass Gender Age
  3      1     22
  1      0     38
  2      1     27
  3      0    NaN
  """), sep=r"s{1,}", engine="python") 

import io
df2  = pd.read_csv(io.StringIO("""
PClass  Gender Age
    1     0  40
    2     0  30
    3     0  25
    1     1  35
    2     1  28
    3     1  21
  """), sep=r"s{1,}", engine="python")
 

df1 (фактический df)

   PClass  Gender   Age
0       3       1  22.0
1       1       0  38.0
2       2       1  27.0
3       3       0   NaN
 

df2 (Сводная таблица)

   PClass  Gender  Age
0       1       0   40
1       2       0   30
2       3       0   25
3       1       1   35
4       2       1   28
5       3       1   21
 

Код:

 df1['new'] = df1['PClass'].astype(str) df1['Gender'].astype(str)
df2['new'] = df2['PClass'].astype(str) df2['Gender'].astype(str)
fill = df2.set_index(['new'])['Age'].to_dict()
df1['Age'] = df1['Age'].fillna(df1['new'].map(fill))
df1 = df1.drop('new',axis=1)
print(df1)
 

С принтами:

    PClass  Gender   Age
0       3       1  22.0
1       1       0  38.0
2       2       1  27.0
3       3       0  25.0