我有一个超过2500列的大数据帧,但结构与此非常相似:
A B C D E
0 1 0 8 0 0
1 0 0 0 0 5
2 1 2 3 0 0
3 0 2 0 1 0
我需要检测所有值大于0的列,我已经完成了以下操作:
df['X'] = df.gt(0).dot(df.columns + ',')
然后我得到了这个:
A B C D E X
0 1 0 8 0 0 A,C
1 0 0 0 0 5 E
2 1 2 9 0 0 A,B,C
3 0 3 0 1 0 B,D
问题是,我不需要在"X"中输入列的名称,而是列的值,我需要执行以下数学运算:
我希望它只检测2个最低值,并从第二个最低值中减去最低值。在"X"中的值不超过2的情况下,我只显示列的值就足够了。
在我的示例中,最终结果如下:
A B C D E X
0 1 0 8 0 0 7
1 0 0 0 0 5 5
2 1 2 9 0 0 1
3 0 3 0 1 0 2
知道如何解决它吗?或者有什么方向吗?
您可以将apply
与函数一起使用,并且必须指定axis=1
才能逐行应用该函数。我添加了一个get_diff
函数,但没有100%,如果这正是您所需要的。我还添加了一个assign
调用,以创建一个具有新列名X
的新数据帧,其中包含所需的值
def get_diff(in_:pd.Series) -> int | float:
res = in_[in_ != 0].sort_values(ascending=False)
if len(res) == 0:
return 0 # Not sure if this is what you want to do in that case
return res[-2] - res[-1] if len(res) > 1 else res[0]
df = df.assign(X=lambda df: df.apply(get_diff, axis=1))
我们可以执行nsmallest
,然后执行np.ptp
,并且这些行的条件只有一个值不等于0
df['new'] = df.apply(lambda x : np.ptp(pd.Series.nsmallest(x[x!=0],2)) if sum(x!=0) != 1 else x[x!=0].iloc[0],axis=1)
Out[520]:
0 7
1 5
2 1
3 1
dtype: int64
或者做两步
df['new'] = df[df.ne(0).sum(1)>1].apply(lambda x : np.ptp(pd.Series.nsmallest(x,2)),axis=1)
df['new'].fillna(df.max(1),inplace=True)
df
Out[530]:
A B C D E new
0 1 0 8 0 0 7.0
1 0 0 0 0 5 5.0
2 1 2 3 0 0 1.0
3 0 2 0 1 0 1.0
我认为您可以简单地使用apply()
,因为您希望对每一行执行行操作。
请参阅https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.apply.html
一个选项是在排序和修剪以获得X
:的值之前识别大于0的值
temp = df.where(df.gt(0), np.nan, axis = 0)
# you could use `np.partition` instead
# which should be more efficient
temp = np.sort(temp, axis = 1)[:, :2]
temp = np.nan_to_num(temp)
temp = np.ptp(temp, axis = 1)
df.assign(X = temp)
A B C D E X
0 1 0 8 0 0 7.0
1 0 0 0 0 5 5.0
2 1 2 3 0 0 1.0
3 0 2 0 1 0 1.0