Pandas Dataframe:用行平均值替换NaN

时间:2015-10-10 20:21:05

标签: python pandas dataframe missing-data

我正在努力学习大熊猫,但我对以下内容感到困惑。我想替换NaNs是一个具有行平均值的数据帧。因此像df.fillna(df.mean(axis=1))这样的东西应该可以工作,但由于某些原因它不适合我。我错过了什么,我做错了什么?是因为它没有实施;见link here

import pandas as pd
import numpy as np
​
pd.__version__
Out[44]:
'0.15.2'

In [45]:
df = pd.DataFrame()
df['c1'] = [1, 2, 3]
df['c2'] = [4, 5, 6]
df['c3'] = [7, np.nan, 9]
df

Out[45]:
    c1  c2  c3
0   1   4   7
1   2   5   NaN
2   3   6   9

In [46]:  
df.fillna(df.mean(axis=1)) 

Out[46]:
    c1  c2  c3
0   1   4   7
1   2   5   NaN
2   3   6   9

然而,这样的事情看起来工作正常

df.fillna(df.mean(axis=0)) 

Out[47]:
    c1  c2  c3
0   1   4   7
1   2   5   8
2   3   6   9

5 个答案:

答案 0 :(得分:23)

如注释,fillna的axis参数为NotImplemented

df.fillna(df.mean(axis=1), axis=1)

注意:这在此非常关键,因为您不希望用第n行平均值填充第n列。

现在你需要迭代:

In [11]: m = df.mean(axis=1)
         for i, col in enumerate(df):
             # using i allows for duplicate columns
             # inplace *may* not always work here, so IMO the next line is preferred
             # df.iloc[:, i].fillna(m, inplace=True)
             df.iloc[:, i] = df.iloc[:, i].fillna(m)

In [12]: df
Out[12]:
   c1  c2   c3
0   1   4  7.0
1   2   5  3.5
2   3   6  9.0

另一种方法是填充转置然后转置,这可能更有效......

df.T.fillna(df.mean(axis=1)).T

答案 1 :(得分:10)

作为替代方案,您还可以使用带有apply表达式的lambda,如下所示:

df.apply(lambda row: row.fillna(row.mean()), axis=1)

也屈服于

    c1   c2   c3
0  1.0  4.0  7.0
1  2.0  5.0  3.5
2  3.0  6.0  9.0

答案 2 :(得分:1)

也有同样的问题。我发现此解决方法正在起作用:

df.transpose().fillna(df.mean(axis=1)).transpose()

我不确定该解决方案的效率。

答案 3 :(得分:0)

我将提出一个替代方案,其中涉及转换为numpy数组。在性能方面,我认为这比迄今为止提出的其他解决方案更有效,并且扩展性更好。

这个想法是使用一个指标矩阵(df.isna().values,如果元素为N / A,则为1,否则为0),并将其广播乘以该行平均值。 因此,我们得到一个矩阵(形状与原始df完全相同),如果原始元素为N / A,则该矩阵包含行平均值,否则为0。

我们将此矩阵添加到原始df中,并确保用0填充,实际上,我们用相应的行平均值填充了N / A。

# setup code
df = pd.DataFrame()
df['c1'] = [1, 2, 3]
df['c2'] = [4, 5, 6]
df['c3'] = [7, np.nan, 9]

# fillna row-wise
row_avgs = df.mean(axis=1).values.reshape(-1,1)
df = df.fillna(0) + df.isna().values * row_avgs
df

给予

    c1   c2   c3
0   1.0  4.0  7.0
1   2.0  5.0  3.5
2   3.0  6.0  9.0

答案 4 :(得分:0)

您可以将均值广播到具有与原始索引相同的索引的DataFrame,然后将updateoverwrite=False结合使用来获得.fillna的行为。与.fillna不同,update允许在索引重复的标签时进行填充。对于小于50,000行左右的记录,应比循环.fillna更快。

fill = pd.DataFrame(np.broadcast_to(df.mean(1).to_numpy()[:, None], df.shape), 
                    columns=df.columns,
                    index=df.index)

df.update(fill, overwrite=False)
print(df)

     1    1    1
0  1.0  4.0  7.0
0  2.0  5.0  3.5
0  3.0  6.0  9.0