【问题标题】:Elegant way to assign value to a column based on day interval of a group根据组的天间隔为列分配值的优雅方法
【发布时间】:2019-08-27 18:28:45
【问题描述】:

我有一个如下所示的数据框

df1 = pd.DataFrame({'subject_id' :[1,1,1,1,1,1,1,2,2,2,2],'day':[3,7,9,10,11,19,20,7,13,18,22] , 'fake_flag' :['fake VAC','','fake VAC','fake VAC','fake VAC','fake VAC','fake VAC','fake VAC','fake VAC','fake VAC','fake VAC']})

如下图所示

我想根据以下规则在actual_flag 列中填写值

a) fake_flag 的值应为 fake_vac 且不应为空

b) 仅填写出现fake_vac 的第一天和14 days interval 之后的记录的值。

这是我尝试过的

t = df1[df1['fake_flag'] == 'fake VAC']
sub_list = t['subject_id'].unique().tolist()
   for sub in sub_list:
     day_list = t['day'][t['subject_id']==sub].tolist()
     min_value = min(day_list)
     index = t[t['day']==min_value].index
     df1.loc[index, 'actual_flag'] = 'act_vac'
     i_14day = min_value + 14
     day_values = [i for i in day_list if i >= i_14day]
     print("day greater than 14 are ", day_values)
     if len(day_values) > 0:
         for val in day_values:
            index = t[t['day']==val].index
            df1.loc[index, 'actual_flag'] = 'act_vac'

如您所见,这非常冗长,我无法对百万条记录的数据集执行此操作。任何有效而优雅的方法都是有帮助的

希望我的输出如下所示

在这种情况下,对于 subject_id = 1,day 3 是第一次出现 fake vacday 19(19 是 gt > 14 天的间隔从 3)和 day 20(20 是 > 14 天的间隔3) 间隔 14 天后。任何优雅高效的解决方案都会有所帮助

用于测试的样本数据

df1 = pd.DataFrame({'subject_id' :[1,1,1,1,1,1,1,1,2,2,2,2],'day':[2,3,7,9,10,11,19,20,7,13,18,22] , 'fake_flag' :['','fake VAC','','fake VAC','fake VAC','fake VAC','fake VAC','fake VAC','fake VAC','fake VAC','fake VAC','fake VAC']})

**更新截图**

【问题讨论】:

  • 我不希望遍历所有主题或记录来为我的数据集执行此操作。它有超过一百万条记录,并且会非常慢

标签: python python-3.x pandas


【解决方案1】:

一种方法是从每个组中的所有日期中减去第一天,检查大于14 的日期并将其设置为"act_vac",以及初始天数:

import numpy as np
# Returns a boolean with True if a given day - first day > 14
ix = df1.fake_flag.ne('').groupby(df1.subject_id).transform('idxmax')
c1 = df1.day.sub(df1.values[ix, 1]).gt(14)
# True if the id is different to previous row
c2 = df1.subject_id.ne(df1.subject_id.shift())
# logical OR of the above conditions
df1['actual_flag'] = np.where(c1 | c2, 'act_vac', '')

     subject_id  day fake_flag actual_flag
0            1    3  fake VAC     act_vac
1            1    7                      
2            1    9  fake VAC            
3            1   10  fake VAC            
4            1   11  fake VAC            
5            1   19  fake VAC     act_vac
6            1   20  fake VAC     act_vac
7            2    7  fake VAC     act_vac
8            2   13  fake VAC            
9            2   18  fake VAC            
10           2   22  fake VAC     act_vac

详情

df1.assign(c1=c1, c2=c2, actual_flag= np.where(c1 | c2, 'act_vac', ''))

     subject_id  day fake_flag actual_flag     c1     c2
0            1    3  fake VAC     act_vac  False   True
1            1    7                        False  False
2            1    9  fake VAC              False  False
3            1   10  fake VAC              False  False
4            1   11  fake VAC              False  False
5            1   19  fake VAC     act_vac   True  False
6            1   20  fake VAC     act_vac   True  False
7            2    7  fake VAC     act_vac  False   True
8            2   13  fake VAC              False  False
9            2   18  fake VAC              False  False
10           2   22  fake VAC     act_vac   True  False

【讨论】:

  • 你介意帮我写这篇文章吗? stackoverflow.com/questions/57669326/…
  • 请让我知道这是否通过接受为您解决了。我添加了更多解释@SSMK
  • 是 python 新手。所以我尝试通过逐行执行来学习。肯定会很快更新
  • 这里您考虑了使用最小值的第一天,但​​最小值必须从我们看到fake_vac 的第一天开始。在上面的例子中,第一天是day 3 for subject_id = 1。我们必须计算与fake_vac第一次发生的那一天的14天差异。所以day 3 将有act_vacday 3 14 天后的任何天都将有act_vae,如day 18day 19
  • 为了帮助您,我在底部的帖子中添加了示例数据。你可以试试这个
猜你喜欢
  • 2020-06-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-10-26
相关资源
最近更新 更多