【问题标题】:How to distribute column values to another columns based on condition in pandas如何根据熊猫中的条件将列值分配到另一列
【发布时间】:2017-12-18 02:33:41
【问题描述】:

我有一个小数据框。下面给出一个例子。

+-------+---------+---------+------+----------+  
| code  | surplus | deficit | gone | has come |  
+-------+---------+---------+------+----------+
| 0100  |    1000 |       0 |      |          |
| 0103  |       0 |     100 |      |          |
| 0104  |       0 |     600 |      |          |
| 0190  |       0 |       0 |      |          |
| 0191  |       0 |     800 |      |          |
| 0192  |     500 |       0 |      |          |
| 0193  |     700 |       0 |      |          |
| 0194  |       0 |     300 |      |          |
| 0195  |       0 |       0 |      |          |
+-------+---------+---------+------+----------+

我需要将surplus 列中的数据分布,以便覆盖deficit 列中的数据。在gone 列中写下我从surplus 列中获得了多少,在has come 列中写下我为填补赤字增加了多少。从surplus 列中,我将数据作为值减少。并且总是从最大的赤字开始。

在我的示例中,它将如下所示:

为了弥补最大的赤字(在示例中这是800),我将部分价值分配给1000

为了弥补下一个赤字(在示例中为600),我从值1000 中取出余数,然后从值700 中取出400

为了弥补300 的不足,我取了700 的剩余部分。

最后,为了弥补赤字100,我参与了价值500

结果应该是下一个数据帧:

+------+---------+---------+------+----------+
| code | surplus | deficit | gone | has come |
+------+---------+---------+------+----------+
| 0100 |    1000 |       0 | 1000 |        0 |
| 0103 |       0 |     100 |    0 |      100 |
| 0104 |       0 |     600 |    0 |      600 |
| 0190 |       0 |       0 |    0 |        0 |
| 0191 |       0 |     800 |    0 |      800 |
| 0192 |     500 |       0 |  100 |        0 |
| 0193 |     700 |       0 |  700 |        0 |
| 0194 |       0 |     300 |    0 |      300 |
| 0195 |       0 |       0 |    0 |        0 |
+------+---------+---------+------+----------+

surplusdeficit 列中的值可以不同。

我想不出这个任务的算法。如果有任何想法,我将不胜感激。

【问题讨论】:

  • 所以基本上你是从把所有的盈余加起来开始的?然后,您从总盈余中尽可能多地弥补赤字?
  • @ArthurTacca 一般是这样的,但我需要从surplus列中的最大值开始,然后按降序取其余的(我的意思是1000,@987654343 @, 500)

标签: python pandas


【解决方案1】:

恐怕我不了解 pandas,所以我无法给出答案的细节,但这是一个我认为可以正常工作的通用算法。由您决定将其与 pandas API 进行匹配。

对于“来了”一栏:

  • 按不足对条目进行排序(降序)
  • 计算此排序列表中赤字条目的累积总和
  • 用 sum(surplus) 绑定,即创建一个列 max(cumsum(deficit), sum(surplus))
  • 现在做每一项与下一项的区别(我认为这是 pandas.Series.diff 方法?),使用 0 作为第“-1”项(也许你必须添加一个虚拟行?)。这是你的“已经到来”的价值

对于“来了”列(如果sum(surplus) >= sum(deficit)):

  • 在这种情况下,您只需为所有行设置 "has come" = "deficit",这将比上述计算更快
  • 但如果您不明确检查这种情况,上述计算仍然有效

对于“gone”列:只需执行与上述完全相同的操作,颠倒“deficit”和“surplus”即可。

编辑:在您的示例中,消失的列是棘手的,因为在这种情况下 sum(deficit)

sum(surplus) = 2200
sum(deficit) = 1800

+------+---------+---------+-----------------+-----------------------------------+----------------+
| code | surplus | deficit | cumsum(surplus) | max(cumsum(surplus),sum(deficit)) | diff(prev row) |
+------+---------+---------+-----------------+-----------------------------------+----------------+
| NaN  |       0 |       0 |               0 |                                 0 |           NaN  |
| 0100 |    1000 |       0 |            1000 |                              1000 |           1000 |
| 0193 |     700 |       0 |            1700 |                              1700 |           700  |
| 0192 |     500 |       0 |            2200 |                              1800 |           100  |
| 0191 |       0 |     800 |            2200 |                              1800 |           0    |
| 0103 |       0 |     100 |            2200 |                              1800 |           0    |
| 0104 |       0 |     600 |            2200 |                              1800 |           0    |
| 0190 |       0 |       0 |            2200 |                              1800 |           0    |
| 0194 |       0 |     300 |            2200 |                              1800 |           0    |
| 0195 |       0 |       0 |            2200 |                              1800 |           0    |
+------+---------+---------+-----------------+-----------------------------------+----------------+

最后一列是您想要的结果。请注意,我在开头添加了一个虚拟行,以便我可以计算成对差异。事实证明,shift() 是计算该列所需的关键方法;见this question

编辑 2:我认为添加替代解决方案可能值得。这有点难以理解,但它可能更容易实现,因为您不需要摆弄额外的虚拟行。

  • 和以前一样:按不足对条目进行排序(降序)
  • 和以前一样:计算此排序列表中赤字条目的累积总和
  • 新增:查找累积总和大于盈余总和的第一行的索引(我不知道在 pandas 中得到这个有多容易)。我们称之为i(如果不存在这样的行,则使用i=Inf)。
  • 对于该索引之前的所有行(即df[:i]),设置“has come”=“deficit”
  • 对于该索引之后的所有行(即df[i+1:]),设置“has come”=0
  • 对于该行(即df[i],如果i 存在),将“已经来”设置为:
    • has come = sum(surplus) - (cumsum(deficit) - deficit)
    • (顺便说一句,(cumsum(deficit) - deficit) 实际上等于上一行的 cumsum(deficit),如果这是第一行,则为 0。)

【讨论】:

  • 感谢您的回答!您能否更详细地解释一下我在第四步中需要为“已经来”列做些什么?恐怕我没有完全理解。
  • @YanaDolyuk 我添加了一些细节
  • 一个优雅的解决方案。非常感谢!
  • 顺便说一句,我添加了另一种方法(实际上只是另一种方法的变体)。不知道会不会更容易。
  • 谢谢!我将尝试为此方法编写代码。
【解决方案2】:

对于“如何根据 pandas 中的条件将列值分配到其他列?”的问题也许功能 np.where 是您正在寻找的:

import numpy as np
import pandas as pd 

# df[Column title] = np.where ( condition on this line, if condition true then value to assign, else value to assign)
df["gone"] = np.where((df["surplus"] - df["deficit"]) > 0 , df["surplus"] - df["deficit"] , 0)
df["has come"] = np.where((df["surplus"] - df["deficit"]) < 0 , 0, df["deficit"] - df["surplus"] )

【讨论】:

  • 这在我测试代码时不会产生预期的结果。我认为这个问题比乍一看要复杂得多。查看 code=0192 的行
  • 是的,我知道,这只是回答标题的想法,而不是问题。
  • 好的,只是检查一下,因为问题不是很清楚。顺便说一句,我没有投反对票。我认为这不是一个完整的答案,但也不值得投反对票。
猜你喜欢
  • 2023-02-15
  • 2020-12-11
  • 1970-01-01
  • 2022-12-16
  • 2021-09-03
  • 1970-01-01
  • 2012-05-29
  • 1970-01-01
相关资源
最近更新 更多