Pandas Fillna of Multiple Columns with Mode of Each Column
Asked Answered
S

5

10

Working with census data, I want to replace NaNs in two columns ("workclass" and "native-country") with the respective modes of those two columns. I can get the modes easily:

mode = df.filter(["workclass", "native-country"]).mode()

which returns a dataframe:

  workclass native-country
0   Private  United-States

However,

df.filter(["workclass", "native-country"]).fillna(mode)

does not replace the NaNs in each column with anything, let alone the mode corresponding to that column. Is there a smooth way to do this?

Suffrage answered 18/3, 2017 at 4:42 Comment(0)
F
16

If you want to impute missing values with the mode in some columns a dataframe df, you can just fillna by Series created by select by position by iloc:

cols = ["workclass", "native-country"]
df[cols]=df[cols].fillna(df.mode().iloc[0])

Or:

df[cols]=df[cols].fillna(mode.iloc[0])

Your solution:

df[cols]=df.filter(cols).fillna(mode.iloc[0])

Sample:

df = pd.DataFrame({'workclass':['Private','Private',np.nan, 'another', np.nan],
                   'native-country':['United-States',np.nan,'Canada',np.nan,'United-States'],
                   'col':[2,3,7,8,9]})

print (df)
   col native-country workclass
0    2  United-States   Private
1    3            NaN   Private
2    7         Canada       NaN
3    8            NaN   another
4    9  United-States       NaN

mode = df.filter(["workclass", "native-country"]).mode()
print (mode)
  workclass native-country
0   Private  United-States

cols = ["workclass", "native-country"]
df[cols]=df[cols].fillna(df.mode().iloc[0])
print (df)
   col native-country workclass
0    2  United-States   Private
1    3  United-States   Private
2    7         Canada   Private
3    8  United-States   another
4    9  United-States   Private
Firenze answered 18/3, 2017 at 6:26 Comment(0)
P
4

You can do it like that:

df[["workclass", "native-country"]]=df[["workclass", "native-country"]].fillna(value=mode.iloc[0])

For example,

    import pandas as pd
d={
    'key3': [1,4,4,4,5],
    'key2': [6,6,4],
    'key1': [6,4,4],
}

df=pd.DataFrame.from_dict(d,orient='index').transpose()

Then df is

  key3  key2    key1
0   1   6       6
1   4   6       4
2   4   4       4
3   4   NaN     NaN
4   5   NaN     NaN

Then by doing:

l=df.filter(["key1", "key2"]).mode()
df[["key1", "key2"]]=df[["key1", "key2"]].fillna(value=l.iloc[0])

we get that df is

  key3  key2    key1
0   1   6        6
1   4   6        4
2   4   4        4
3   4   6        4
4   5   6        4
Palestine answered 18/3, 2017 at 4:56 Comment(1)
When I do this I get the following message:``` /anaconda3/envs/exts-ml/lib/python3.6/site-packages/pandas/core/frame.py:4024: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame```Missis
I
0

I think it's cleanest to use a dict as the fillna parameter 'value'

ref: https://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.fillna.html

create a toy df from @miriam-farber's response

import pandas as pd
d={
    'key3': [1,4,4,4,5],
    'key2': [6,6,4],
    'key1': [6,4,4],
}

d_df=pd.DataFrame.from_dict(d,orient='index').transpose()

create a dict

mode_dict = d_df.loc[:,['key2','key1']].mode().to_dict('records')[0]

use this dict in fillna method

d_df.fillna(mode_dict, inplace=True)
Inner answered 23/9, 2018 at 3:5 Comment(0)
C
0

This code impute mean to the int columns and mode to the object columns making a list of both types of columns and imputing the missing value according to the conditions.

cateogry_columns=df.select_dtypes(include=['object']).columns.tolist()
integer_columns=df.select_dtypes(include=['int64','float64']).columns.tolist()

for column in df:
    if df[column].isnull().any():
        if(column in cateogry_columns):
            df[column]=df[column].fillna(df[column].mode()[0])
        else:
            df[column]=df[column].fillna(df[column].mean)`
Chimerical answered 26/2, 2020 at 11:38 Comment(0)
B
0

You can also use the SimpleImputer to solve this problem as follows:

from sklearn.impute import SimpleImputer

imputer = SimpleImputer(strategy='most_frequent', missing_values=np.nan)
df[["workclass", "native-country"]] = imputer.fit_transform(df[["workclass", "native-country"]])
Backbone answered 2/11, 2022 at 21:11 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.