web-dev-qa-db-ja.com

Pandasデータフレーム:NaNを行平均で置き換える

pandasを学習しようとしていますが、次のことに困惑しています。NaNを行平均のデータフレームに置き換えたいので、df.fillna(df.mean(axis=1))のようなものが機能するはずですしかし、なんらかの理由で失敗します。何か不足しているのでしょうか、何か問題がありますか?実装されていないためです ここにリンク を参照してください

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
17
Aenaon

コメントのとおり、fillnaの軸引数は 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
27
Andy Hayden

別の方法として、次のようにapplylambda式とともに使用することもできます。

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
12
Cleb

ちょうど同じ問題がありました。この回避策が機能していることがわかりました:

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

このソリューションの効率についてはわかりませんが。

0
LKho

Numpy配列へのキャストを含む代替案を提案します。パフォーマンスに関しては、これはより効率的であり、これまでに提案された他のソリューションよりもおそらく拡張性が高いと思います。

インジケーターマトリックス(df.isna().valuesは要素がN/Aの場合は1、それ以外の場合は0)を使用し、それを行平均にブロードキャスト乗算するという考えです。したがって、元の要素がN/Aの場合は行平均値を含み、それ以外の場合は0を含む行列(元のdfとまったく同じ形状)になります。

この行列を元の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
0
Troy

元と同じインデックスを持つ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
0
ALollz