Pandas 值的行总和 > 0
Pandas row sum for values > 0
我有以下格式的数据框
ROW Value1 Value2 Value3 Value4
1 10 10 -5 -2
2 50 20 -10 -7
3 10 5 0 -1
我希望计算每一行的正总数和负总数之和。所以本质上,结果帧应该看起来像
ROW Post_Total Neg_Total
1 20 -7
2 70 -17
3 15 -1
我的数据集中有一件事,一列只能有正值或负值。
关于如何做到这一点的任何想法。我尝试用 >0 进行子集化,但没有成功。
谢谢!
由于所有列都可以全部为正数或全部为负数,您可以使用 all()
检查列的条件,然后 groupby:
df.groupby(df.gt(0).all(), axis=1).sum()
输出:
False True
ROW
1 -7 20
2 -17 70
3 -1 15
一般来说,我会 subset/clip 和总和:
out = pd.DataFrame({'pos': df.clip(lower=0).sum(1),
'neg': df.clip(upper=0).sum(1)
})
使用 DataFrame.melt
,但如果性能很重要,则另一种解决方案更好 ;):
df1 = (df.melt('ROW')
.assign(g = lambda x: np.where(x['value'].gt(0),'Pos_Total','Neg_Total'))
.pivot_table(index='ROW',columns='g', values='value', aggfunc='sum', fill_value=0)
.reset_index()
.rename_axis(None, axis=1))
print (df1)
ROW Neg_Total Pos_Total
0 1 -7 20
1 2 -17 70
2 3 -1 15
Numpy 替代 numpy.clip
:
a = df.set_index('ROW').to_numpy()
df = pd.DataFrame({'Pos_Total': np.sum(np.clip(a, a_min=0, a_max=None), 1),
'Neg_Total': np.sum(np.clip(a, a_min=None, a_max=0), 1)},
index=df['ROW'])
您可以使用:
(df.melt(id_vars='ROW')
.assign(sign=lambda d: np.where(d['value'].gt(0), 'Pos_Total', 'Neg_Total'))
.groupby(['ROW', 'sign'])['value'].sum()
.unstack('sign')
)
或者,使用遮罩。
numpy 版本(更快):
import numpy as np
a = df.set_index('ROW').values
mask = a > 0
pd.DataFrame({'Pos_Total': np.where(mask, a, 0).sum(1),
'Neg_Total': np.where(mask, 0, a).sum(1)})
pandas 版本(比 numpy 慢但比 melt 快):
d = df.set_index('ROW')
mask = d.gt(0)
pd.DataFrame({'Pos_Total': d.where(mask).sum(1),
'Neg_Total': d.mask(mask).sum(1)},
index=df['ROW'])
输出:
Pos_Total Neg_Total
ROW
1 20.0 -7.0
2 70.0 -17.0
3 15.0 -1.0
让我们尝试申请
out = df.set_index('ROW').apply(lambda x : {'Pos':x[x>0].sum(),'Neg':x[x<0].sum()} ,
result_type = 'expand',
axis=1)
Out[33]:
Pos Neg
ROW
1 20 -7
2 70 -17
3 15 -1
所有回答的时间顺序或速度。在具有唯一 ROW 值的 30k 行上使用 timeit
计算。
# @mozway+jezrael (numpy mask v2)
940 µs ± 10.3 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
# @mozway (numpy mask):
1.29 ms ± 26.5 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
# @Quang Hoang (groupby)
4.68 ms ± 184 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
# @Quang Hoang (clip)
5.2 ms ± 91 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
# @mozway (pandas mask)
10.5 ms ± 612 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
# @mozway (melt+groupby)
36.2 ms ± 1.14 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
# @jezrael (melt+pivot_table)
48.5 ms ± 740 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
# @BENY (apply)
9.05 s ± 76.8 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
设置:
df = pd.DataFrame({'ROW': [1, 2, 3],
'Value1': [10, 50, 10],
'Value2': [10, 20, 5],
'Value3': [-5, -10, 0],
'Value4': [-2, -7, -1]})
df = pd.concat([df]*10000, ignore_index=True)
df['ROW'] = range(len(df))
我有以下格式的数据框
ROW Value1 Value2 Value3 Value4
1 10 10 -5 -2
2 50 20 -10 -7
3 10 5 0 -1
我希望计算每一行的正总数和负总数之和。所以本质上,结果帧应该看起来像
ROW Post_Total Neg_Total
1 20 -7
2 70 -17
3 15 -1
我的数据集中有一件事,一列只能有正值或负值。
关于如何做到这一点的任何想法。我尝试用 >0 进行子集化,但没有成功。 谢谢!
由于所有列都可以全部为正数或全部为负数,您可以使用 all()
检查列的条件,然后 groupby:
df.groupby(df.gt(0).all(), axis=1).sum()
输出:
False True
ROW
1 -7 20
2 -17 70
3 -1 15
一般来说,我会 subset/clip 和总和:
out = pd.DataFrame({'pos': df.clip(lower=0).sum(1),
'neg': df.clip(upper=0).sum(1)
})
使用 DataFrame.melt
,但如果性能很重要,则另一种解决方案更好 ;):
df1 = (df.melt('ROW')
.assign(g = lambda x: np.where(x['value'].gt(0),'Pos_Total','Neg_Total'))
.pivot_table(index='ROW',columns='g', values='value', aggfunc='sum', fill_value=0)
.reset_index()
.rename_axis(None, axis=1))
print (df1)
ROW Neg_Total Pos_Total
0 1 -7 20
1 2 -17 70
2 3 -1 15
Numpy 替代 numpy.clip
:
a = df.set_index('ROW').to_numpy()
df = pd.DataFrame({'Pos_Total': np.sum(np.clip(a, a_min=0, a_max=None), 1),
'Neg_Total': np.sum(np.clip(a, a_min=None, a_max=0), 1)},
index=df['ROW'])
您可以使用:
(df.melt(id_vars='ROW')
.assign(sign=lambda d: np.where(d['value'].gt(0), 'Pos_Total', 'Neg_Total'))
.groupby(['ROW', 'sign'])['value'].sum()
.unstack('sign')
)
或者,使用遮罩。
numpy 版本(更快):
import numpy as np
a = df.set_index('ROW').values
mask = a > 0
pd.DataFrame({'Pos_Total': np.where(mask, a, 0).sum(1),
'Neg_Total': np.where(mask, 0, a).sum(1)})
pandas 版本(比 numpy 慢但比 melt 快):
d = df.set_index('ROW')
mask = d.gt(0)
pd.DataFrame({'Pos_Total': d.where(mask).sum(1),
'Neg_Total': d.mask(mask).sum(1)},
index=df['ROW'])
输出:
Pos_Total Neg_Total
ROW
1 20.0 -7.0
2 70.0 -17.0
3 15.0 -1.0
让我们尝试申请
out = df.set_index('ROW').apply(lambda x : {'Pos':x[x>0].sum(),'Neg':x[x<0].sum()} ,
result_type = 'expand',
axis=1)
Out[33]:
Pos Neg
ROW
1 20 -7
2 70 -17
3 15 -1
所有回答的时间顺序或速度。在具有唯一 ROW 值的 30k 行上使用 timeit
计算。
# @mozway+jezrael (numpy mask v2)
940 µs ± 10.3 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
# @mozway (numpy mask):
1.29 ms ± 26.5 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
# @Quang Hoang (groupby)
4.68 ms ± 184 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
# @Quang Hoang (clip)
5.2 ms ± 91 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
# @mozway (pandas mask)
10.5 ms ± 612 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
# @mozway (melt+groupby)
36.2 ms ± 1.14 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
# @jezrael (melt+pivot_table)
48.5 ms ± 740 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
# @BENY (apply)
9.05 s ± 76.8 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
设置:
df = pd.DataFrame({'ROW': [1, 2, 3],
'Value1': [10, 50, 10],
'Value2': [10, 20, 5],
'Value3': [-5, -10, 0],
'Value4': [-2, -7, -1]})
df = pd.concat([df]*10000, ignore_index=True)
df['ROW'] = range(len(df))