繁体   English   中英

用 pandas 替换 dataframe 中的 NaN 值

[英]replacing NaN values in dataframe with pandas

我想创建一个 function ,它采用 dataframe 并将 NaN 替换为分类列中的模式,并将数值列中的 NaN 替换为该列的平均值。 如果分类列中有多个模式,则应使用第一种模式。

我已经设法用以下代码做到了:

def exercise4(df):
    df1 = df.select_dtypes(np.number)
    df2 = df.select_dtypes(exclude = 'float')
    mode = df2.mode()
    df3 = df1.fillna(df.mean())
    df4 = df2.fillna(mode.iloc[0,:])
    new_df = [df3,df4]
    df5 = pd.concat(new_df,axis=1)
    new_cols = list(df.columns)
    df6 = df5[new_cols]
    return df6

但我确信有一种更简单的方法可以做到这一点?

您可以使用:

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到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

使用 DataFrame.pipe 传递给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

另一个想法是使用DataFrame.apply ,但需要result_type='expand'参数和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

传递给 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)

实际上你已经有了所有的成分。 你的一些步骤可以被链接起来,尽管其他一些步骤已经过时了。

例如看这两行:

mode = df2.mode()
df4 = df2.fillna(mode.iloc[0,:])

您可以将它们替换为df4 = df2.fillna(df2.mode().iloc[0,:] 。然后,您无需不断地将新的(子)数据帧重新分配给变量,更改它们并将它们连接起来,您可以inplace进行这些更改,这意味着它们直接应用于有问题的 dataframe。最后exclude='float'可能适用于您的特定(示例)情况,但如果 dataframe 中有更多数据类型怎么办?可能是字符串列?

我的建议:

def mean_mode(df):
    df.select_dtypes(np.number).fillna(df.mean(), inplace=True)
    df.select_dtypes('category').fillna(df.mode()[0], inplace=True)
    return df

您可以使用_get_numeric_data()方法来获取数字列(以及分类列):

numerical_col = df._get_numeric_data().columns

此时,您只需要一行代码使用贯穿各列的应用 function:

fixed_df = df.apply(lambda col: col.fillna(col.mean()) if col.name in numerical_col else col.fillna(col.mode()[0]), axis=0)

您可以按以下方式工作:

df = df.apply(lambda x: x.fillna(x.mode()[0]) if (x.dtypes==category) else  x.fillna(x.mean()) )

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM