You can use:
df = pd.DataFrame({ 'A':list('abcdec'), 'B':[4,5,4,5,5,4], 'C':[7,8,9,4,2,3], 'D':[1,3,5,7,1,0], 'E':list('bbcdeb'), }) df.iloc[[1,3], [1,2,0,4]] = np.nan print (df) A B C D E 0 a 4.0 7.0 1 b 1 NaN NaN NaN 3 NaN 2 c 4.0 9.0 5 c 3 NaN NaN NaN 7 NaN 4 e 5.0 2.0 1 e 5 c 4.0 3.0 0 b
Idea is use DataFrame.select_dtypes for non numeric columns with DataFrame.mode and select first row by DataFrame.iloc for positions, then count means - non numeric are expluded by default, so possible use Series.append for Series with all values for replacement passed to DataFrame.fillna:
modes = df.select_dtypes(exclude=np.number).mode().iloc[0] means = df.mean() both = modes.append(means) print (both) A c E b B 4.25 C 5.25 D 2.83333 dtype: object df.fillna(both, inplace=True) print (df) A B C D E 0 a 4.00 7.00 1 b 1 c 4.25 5.25 3 b 2 c 4.00 9.00 5 c 3 c 4.25 5.25 7 b 4 e 5.00 2.00 1 e 5 c 4.00 3.00 0 b
Passed to function with DataFrame.pipe:
def exercise4(df): modes = df.select_dtypes(exclude=np.number).mode().iloc[0] means = df.mean() both = modes.append(means) df.fillna(both, inplace=True) return df df = df.pipe(exercise4) #alternative #df = exercise4(df) print (df) A B C D E 0 a 4.00 7.00 1 b 1 c 4.25 5.25 3 b 2 c 4.00 9.00 5 c 3 c 4.25 5.25 7 b 4 e 5.00 2.00 1 e 5 c 4.00 3.00 0 b
Another idea is use DataFrame.apply, but is necessary result_type='expand' parameter with test dtypes by types.is_numeric_dtype:
from pandas.api.types import is_numeric_dtype f = lambda x: x.mean() if is_numeric_dtype(x.dtype) else x.mode()[0] df.fillna(df.apply(f, result_type='expand'), inplace=True) print (df) A B C D E 0 a 4.00 7.00 1 b 1 c 4.25 5.25 3 b 2 c 4.00 9.00 5 c 3 c 4.25 5.25 7 b 4 e 5.00 2.00 1 e 5 c 4.00 3.00 0 b
Passed to function:
from pandas.api.types import is_numeric_dtype def exercise4(df): f = lambda x: x.mean() if is_numeric_dtype(x.dtype) else x.mode()[0] df.fillna(df.apply(f, result_type='expand'), inplace=True) return df df = df.pipe(exercise4) #alternative #df = exercise4(df) print (df)