感谢您抽出时间阅读我的问题。
我想用名称以“ A”开头的列中的平均值填充以下df中的NaN。
例如,第一个NaN应填充2.5,这是2和3的平均值。最后一个NaN应替换为1.5。尽管列中以“ B”开头的任何值都位于同一df中。
A.1.a A.3.d A.6.i B.2.b
NaN 2 3 12
1 2 3 12
1 NaN 3 12
1 2 3 12
NaN 2 3 12
1 2 NaN 12
这是我的成功尝试。
# read only columns which names started with A.
cols_A = [col for col in df if col.startswith('A')]
cols_A = df[cols_A]
cols_A = cols_A.apply(lambda row: row.fillna(row.mean()), axis=1)
cols_A
我正在寻找一种更有效的方法,因为我的df有更多的列。
答案 0 :(得分:1)
仅用A
替换的Numpy解决方案开始了以下列:
#select only A starting columns
mask = df.columns.str.startswith('A')
df1 = df.loc[:, mask]
print (df1)
A.1.a A.3.d A.6.i
0 NaN 2.0 3.0
1 1.0 2.0 3.0
2 1.0 NaN 3.0
3 1.0 2.0 3.0
4 NaN 2.0 3.0
5 1.0 2.0 NaN
#convert to 2d array
arr = df1.values
#broadcast to 2d array by df1 shape
a = np.broadcast_to(np.nanmean(arr, axis=1)[:, None], df1.shape)
#check missing values
m = np.isnan(arr)
#replace them by mask
arr[m] = a[m]
print (arr)
[[2.5 2. 3. ]
[1. 2. 3. ]
[1. 2. 3. ]
[1. 2. 3. ]
[2.5 2. 3. ]
[1. 2. 1.5]]
#assign back
df.loc[:, mask] = arr
print (df)
A.1.a A.3.d A.6.i B.2.b
0 2.5 2.0 3.0 12
1 1.0 2.0 3.0 12
2 1.0 2.0 3.0 12
3 1.0 2.0 3.0 12
4 2.5 2.0 3.0 12
5 1.0 2.0 1.5 12
如果需要用列的第一个值定义的组替换NaN
,则
df = df.combine_first(df.groupby(lambda x: x[0], axis=1).transform('mean'))
#alternative
#df = df.combine_first(df.groupby(df.columns.str[0], axis=1).transform('mean'))
print (df)
A.1.a A.3.d A.6.i B.2.b
0 2.5 2.0 3.0 12
1 1.0 2.0 3.0 12
2 1.0 2.0 3.0 12
3 1.0 2.0 3.0 12
4 2.5 2.0 3.0 12
5 1.0 2.0 1.5 12
另一个想法是创建Series
的字典并替换为DataFrame.fillna
:
df1 = df.groupby(df.columns.str[0], axis=1).mean()
df = df.fillna({x: df1[x[0]] for x in df.columns})
print (df)
A.1.a A.3.d A.6.i B.2.b
0 2.5 2.0 3.0 12
1 1.0 2.0 3.0 12
2 1.0 2.0 3.0 12
3 1.0 2.0 3.0 12
4 2.5 2.0 3.0 12
5 1.0 2.0 1.5 12
答案 1 :(得分:1)
IIUC,您可以尝试broadcasting
和fillna
cols = [x for x in df.columns if x.startswith('A')]
df.fillna(pd.DataFrame((df[cols].sum(1)/df[cols].notnull().sum(1)).values[:,None] * np.ones([len(cols),1]).T, columns=cols))
A.1.a A.3.d A.6.i B.2.b
0 2.5 2.0 3.0 12
1 1.0 2.0 3.0 12
2 1.0 2.0 3.0 12
3 1.0 2.0 3.0 12
4 2.5 2.0 3.0 12
5 1.0 2.0 1.5 12
好的时机
df = pd.concat([df]*1000).reset_index(drop=True)
%timeit df.fillna(pd.DataFrame(df[cols].sum(1).div(df[cols].notnull().sum(1)).values[:,None] * np.ones([len(cols),1]).T, columns=cols))
5.73 ms ± 272 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%timeit df.combine_first(df.groupby(lambda x: x[0], axis=1).transform('mean'))
856 ms ± 22.4 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
答案 2 :(得分:0)
另一个选择是:
cols_A = cols_A.T.fillna(cols_A.mean(axis=1)).T
输出:
A.1.a A.3.d A.6.i
0 2.5 2.0 3.0
1 1.0 2.0 3.0
2 1.0 2.0 3.0
3 1.0 2.0 3.0
4 2.5 2.0 3.0
5 1.0 2.0 1.5