首页 > 解决方案 > Pandas 遍历行和条件计数

问题描述

我正在尝试在一个名为 Stage 的新列中使用条件计数迭代 pandas Dataframe 中的行。对于每个名称,阶段应该从 1 开始,如果行之间的名称相同,那么在“健康”状态之后应该开始一个新阶段。如果存在,“健康”事件将与之前的“生病”事件处于同一阶段。我以前在excel中完成过代码,但不知道如何在python中完成。

我现在拥有的是:

日期 姓名 地位
2020-01-02 玛丽 健康
2020-01-05 玛丽 生病的
2020-01-15 玛丽 生病的
2020-01-20 玛丽 健康
2020-02-03 玛丽 健康
2020-02-06 玛丽 生病的
2020-02-10 玛丽 生病的
2020-02-15 玛丽 健康
2020-01-02 鲍勃 健康
2020-01-05 鲍勃 健康
2020-01-15 鲍勃 健康
2020-01-20 鲍勃 生病的
2020-02-03 鲍勃 生病的
2020-02-06 鲍勃 生病的
2020-02-10 鲍勃 生病的
2020-02-15 鲍勃 健康

我想拥有的:

日期 姓名 地位 阶段
2020-01-02 玛丽 健康 1
2020-01-05 玛丽 生病的 2
2020-01-15 玛丽 生病的 2
2020-01-20 玛丽 健康 2
2020-02-03 玛丽 健康 3
2020-02-06 玛丽 生病的 4
2020-02-10 玛丽 生病的 4
2020-02-15 玛丽 健康 4
2020-01-02 鲍勃 健康 1
2020-01-05 鲍勃 健康 2
2020-01-15 鲍勃 健康 3
2020-01-20 鲍勃 生病的 4
2020-02-03 鲍勃 生病的 4
2020-02-06 鲍勃 生病的 4
2020-02-10 鲍勃 生病的 4
2020-02-15 鲍勃 健康 4

标签: pandascountconditional-statements

解决方案


您不需要显式循环。您需要以下内容:

  • 按名称列分组
  • 适用于每个组:
    • 移动状态列以查看上一个值
    • 取以下系列的累积总和:
      • 如果前一个值为空且当前值为健康,我们在第一行所以称它为一个
      • 如果上一行是健康的,就叫它一个
      • 否则,称其为零

from io import StringIO

import numpy
import pandas

df = pandas.read_csv(StringIO("""\
|Date|Name|Stage|
|2020-01-02|Mary|Healthy|
|2020-01-05|Mary|Sick|
|2020-01-15|Mary|Sick|
|2020-01-20|Mary|Healthy|
|2020-02-03|Mary|Healthy|
|2020-02-06|Mary|Sick|
|2020-02-10|Mary|Sick |
|2020-02-15|Mary|Healthy|
|2020-01-02|Bob|Healthy|
|2020-01-05|Bob|Healthy|
|2020-01-15|Bob|Healthy|
|2020-01-20|Bob|Sick|
|2020-02-03|Bob|Sick|
|2020-02-06|Bob|Sick|
|2020-02-10|Bob|Sick |
|2020-02-15|Bob|Healthy|
"""), sep='|').loc[:, ['Date', 'Name', 'Stage']]

output = (
    df.assign(Status=lambda df: df.groupby('Name')['Stage'].apply(lambda g: 
        numpy.bitwise_or(  #  returns 1 if either two conditions are met
            g.shift().eq('Healthy'),  # general case
            g.shift().isnull() & g.eq("Healthy") #  handles first row of a group
        ).cumsum()
    ))
)

print(output.to_string())

我得到:

          Date  Name    Stage  Status
0   2020-01-02  Mary  Healthy       1
1   2020-01-05  Mary     Sick       2
2   2020-01-15  Mary     Sick       2
3   2020-01-20  Mary  Healthy       2
4   2020-02-03  Mary  Healthy       3
5   2020-02-06  Mary     Sick       4
6   2020-02-10  Mary    Sick        4
7   2020-02-15  Mary  Healthy       4
8   2020-01-02   Bob  Healthy       1
9   2020-01-05   Bob  Healthy       2
10  2020-01-15   Bob  Healthy       3
11  2020-01-20   Bob     Sick       4
12  2020-02-03   Bob     Sick       4
13  2020-02-06   Bob     Sick       4
14  2020-02-10   Bob    Sick        4
15  2020-02-15   Bob  Healthy       4

推荐阅读