仅为包含特定值的单元格填充DataFrame的组中位数



我正试图找到一个漂亮/聪明的用组的中值填充我的DataFrame的方法。
我有两个组"我"one_answers";J"和2个因素';a &;和";B"。我想用这个值所属群的中位数来代替负值。
一个约束是我不想替换NaN值。下面是初始化DataFrame

的代码
tuples = [('I','0'), ('I','1'), ('I', '2'), ('J', '3'), ('I', '4'), ('J', '5')]
index = pd.MultiIndex.from_tuples(tuples, names=["Id1", "Id2"])
df = pd.DataFrame(np.arange(12).reshape(-1, 2), columns=['A', 'B'], index=index)
df["A"].iloc[0]=-1
df["B"].iloc[-1:]=-1
df["B"].iloc[-2]=18
df["B"].iloc[0]=np.NaN
df["B"].iloc[1]=np.NaN

给了:

A   B
Id1 Id2     
I   0   -1  NaN
1   2   NaN
2   4   5.0
J   3   6   7.0
I   4   8   18.0
J   5   10  -1.0

我是这样解决的:

ind, col = np.where(df<0)
nb_df_lt_0 = len(ind)
for ii in np.arange(nb_df_lt_0) : 
df.iloc[ind[ii],col[ii]] = np.NAN
xx, yy = ind[ii], col[ii]
index_Id1 = df.index.get_level_values("Id1")[xx]
df.iloc[xx,yy] = df.loc[index_Id1,:].iloc[:,yy].median()
df

这就是我要找的:

A   B
Id1 Id2     
I   0   4.0  NaN
1   2.0  NaN
2   4.0  5.0
J   3   6.0  7.0
I   4   8.0  18.0
J   5   10.0 7.0

它可以工作,但它看起来不太好,而且肯定不是很有效,因为我有一个For循环。我会很高兴看到一个解决方案与熊猫或numpy功能,使工作。
提前致谢

你可以这样做:

df.mask(df<0, df.mask(df<0, np.nan).groupby(level=0).median())

让我们来分析一下。你需要两组的中位数和";J"排除负值:

median_df = df.mask(df<0, np.nan).groupby(level=0).median()

然后用中位数替换原始DataFrame中的负值:

df.mask(df<0, median_df)

你可以这样做:

它对每个冷进行分组,然后找到组的中位数(不包括-1值)

for col in df.columns:
df[col] = df.groupby('Id1')[col].apply(lambda x: (
x.replace(-1, x.loc[x != -1].median())
))

让我们从创建源DataFrame的方式的一个小更正开始:由于每一列可以包含NaN,这是float的特殊情况,创建数据类型为float:

的临时DataFrame
np.arange(12, dtype='float')

(创建DataFrame的其余代码不需要更改)。

您将需要以下组处理功能:

def grpProc(grp):
grp[grp == -1] = grp[grp != -1].median()
return grp

从elements !=0计算中位数并保存在elements ==中-1,假设源组(grp)是当前列的一部分对于每个Id1。然后返回修改后的组。

要得到结果,将它应用到DataFrame的每一列,按分组Id1(0级):

result = df.apply(lambda col: col.groupby(level=0).apply(grpProc))

没有传递axis参数,因此此函数应用于每一个(axis == 0).

对于示例数据,结果为:

A     B
Id1 Id2            
I   0     4.0   NaN
1     2.0   NaN
2     4.0   5.0
J   3     6.0   7.0
I   4     8.0  18.0
J   5    10.0   7.0

最新更新