【问题标题】:Pandas dataframe: uniformly scale down values when column sum exceeds treshold熊猫数据框:当列总和超过阈值时统一缩小值
【发布时间】:2019-08-26 07:06:21
【问题描述】:

初始情况

考虑以下示例数据框:

df = pd.DataFrame({
    'A': [3., 2., 1., np.nan],
    'B': [7., np.nan, 1., 3.],
    'C': [4., 5., 1., 2.],
    'D': [1., 0., 2., 3.]    
})

打印出来的样子是这样的:

     A    B    C    D
0  3.0  7.0  4.0  1.0
1  2.0  NaN  5.0  0.0
2  1.0  1.0  1.0  2.0
3  NaN  3.0  2.0  3.0

期望的结果

我现在想对该数据框的每一列执行以下操作:

  1. 计算列值的总和(忽略任何 NaN 值)。
  2. 如果总和超过 10.0,那么我想统一缩小列中的所有值,使新总和正好为 10.0(再次忽略任何 NaN 值)。

基本上我想获得一个如下所示的结果数据框:

     A         B         C    D
0  3.0  6.363636  3.333333  1.0
1  2.0       NaN  4.166667  0.0
2  1.0  0.909091  0.833333  2.0
3  NaN  2.727273  1.666667  3.0

到目前为止尝试过

下面的代码得到了想要的结果。

def helper_func(s):
    if s.sum() > 10.:
        return s * 10. / s.sum()
    else:
        return s

result_df = df.apply(helper_func)

但是,我觉得这段代码有点冗长且效率低下。根据我迄今为止对 pandas 的经验,我怀疑仍然可能有一个更加矢量化的解决方案。谁能帮我找到这个?

【问题讨论】:

  • 首先,如果s.sum > 10,您将计算s.sum() 两次。将该值保存到变量中。虽然,为了解决您不太冗长的问题,您可以使用 lambda 函数 df.apply(lambda s: s*10 / s.sum() if s.sum() > 10 else s)

标签: python pandas dataframe


【解决方案1】:

这是一种方法:

thres = 10
result = df * thres / df.sum().clip(lower=thres)

【讨论】:

    【解决方案2】:

    这是另一种方法:

    colSums = df.sum()
    df / ((colSums * (colSums > 10) / 10) + (colSums <= 10))
    

    在这里,我们为每列创建一个具有总和值的变量,然后分母检查列的总和是否超过 10 调整这些列,使它们总和为 10。总和小于 10 的那些列将递增到 1,这样我们就不会除以 0。然后,生成的数组将跨列划分。这将返回所需的结果。

    Out[46]: 
         A         B         C    D
    0  3.0  6.363636  3.333333  1.0
    1  2.0       NaN  4.166667  0.0
    2  1.0  0.909091  0.833333  2.0
    3  NaN  2.727273  1.666667  3.0
    

    【讨论】:

    • 感谢您的回复,但这个结果数据框似乎与我想要的结果数据框不同。不是吗?
    • @Xukrao 我在第一次阅读时错过了 10 的总和。该方法已经过调整以符合此标准。
    • @Trenton_M 我在第一次阅读时错过了 10 的总和。该方法已经过调整以符合此标准。
    猜你喜欢
    • 1970-01-01
    • 2018-11-19
    • 2020-10-18
    • 2017-07-25
    • 1970-01-01
    • 2019-05-21
    • 1970-01-01
    • 1970-01-01
    • 2020-08-08
    相关资源
    最近更新 更多