Pandas python:按项目月份和状态计算中断的服务数量



我有一个测试数据集,它显示了每个客户端、service_id和时间段的服务状态("in_progress"或"已停止"(。我编写了代码,以便您可以复制和粘贴以生成数据帧。让我们看看(暂时忽略左箭头(:

In [1]: import pandas as pd
In [2]: my_data = 
      [{'client_id' : '01', 'service_id': '01', 'status_start' : '2014-01-01', 'status_end' : '2014-02-13', 'service_status' : 'in_progress'},
       {'client_id' : '01', 'service_id': '02', 'status_start' : '2014-01-01', 'status_end' : '2014-02-18', 'service_status' : 'stopped'},
       {'client_id' : '01', 'service_id': '12', 'status_start' : '2014-02-14', 'status_end' : '2014-04-13', 'service_status' : 'in_progress'},
       {'client_id' : '02', 'service_id': '56', 'status_start' : '2014-03-01', 'status_end' : '2014-04-13', 'service_status' : 'in_progress'},
       {'client_id' : '02', 'service_id': '58', 'status_start' : '2014-02-04', 'status_end' : '2014-04-13', 'service_status' : 'stopped'},
       {'client_id' : '02', 'service_id': '60', 'status_start' : '2014-02-08', 'status_end' : '2014-04-23', 'service_status' : 'stopped'},
       {'client_id' : '03', 'service_id': '61', 'status_start' : '2014-02-10', 'status_end' : '2014-04-28', 'service_status' : 'in_progress'},
       {'client_id' : '03', 'service_id': '63', 'status_start' : '2014-02-01', 'status_end' : '2014-04-28', 'service_status' : 'in_progress'},
       {'client_id' : '03', 'service_id': '65', 'status_start' : '2014-01-10', 'status_end' : '2014-03-28', 'service_status' : 'in_progress'}
       ]
In [3]: df = pd.DataFrame(my_data)
In [4]: df
          client_id service_id  status_start    status_end  service_status
-->  0    01        01          2014-01-01      2014-02-13  in_progress
-->  1    01        02          2014-01-01      2014-02-18  stopped
-->  2    01        12          2014-02-14      2014-04-13  in_progress
     3    02        56          2014-03-01      2014-04-13  in_progress
     4    02        58          2014-02-04      2014-04-13  stopped
     5    02        60          2014-02-08      2014-04-23  stopped
     6    03        61          2014-02-10      2014-04-28  in_progress
     7    03        63          2014-02-01      2014-04-28  in_progress
-->  8    03        65          2014-01-10      2014-03-28  in_progress

我想问数据的问题是:每个service_status每月和客户端有多少服务?

也就是说,例如,1 月份的客户端"01"有 1 个服务"in_progress"和 1 个"已停止"。同一个客户端"01"在 2 月份有 2 个"in_progress"(1 月份已经存在,2 月份有一个新的客户端(和 1 个标记为"已停止"的新客户端。但在3月和4月,只有一项服务"in_progress"(services_ids"01"和"02"在2月终止(。遵循相同的规则,客户端"03"在 1 月份有 1 个服务"in_progress"和 0 个"停止"。

因此,最终的数据帧将如下所示(现在您会看到箭头突出显示刚刚注释的示例的行(:

In [5]: summary_df
           client_id    month   status_in_progress  status_stopped
-->    0    01          Jan     1                   1
-->    1    01          Feb     2                   1
-->    2    01          Mar     1                   0
-->    3    01          Apr     1                   0
       4    02          Jan     0                   0
       5    02          Feb     0                   2
       6    02          Mar     1                   2
       7    02          Apr     1                   2
-->    8    03          Jan     1                   0
       9    03          Feb     3                   0
       10   03          Mar     3                   0
       11   03          Apr     2                   0

我尝试使用groupbypivot_table,但没有成功。好吧,我必须说实话:我使用了一个需要 6 小时才能完成的 for 循环(原始数据集有超过 500 万行(。

有人可以帮忙吗?熊猫/蟒蛇的新手,请耐心等待!:)

谢谢!

您必须创建一个每月包含一条记录的新数据集,例如,对于此记录:

          client_id service_id  status_start    status_end  service_status
-->  0    01        01          2014-01-01      2014-02-13  in_progress

我们在新数据集中创建以下两条记录:

          client_id service_id  month    service_status
          01        01          2014-01  in_progress
          01        01          2014-02  in_progress

然后按client_id、月份和service_status分组。

def month_id(s):
  """Convert YYYY-MM-DD to a month id"""
  y = int( s[0:4] )
  m = int( s[5:7] )
  return y*12 + m
def to_yyyymm(mid):
  """Convert a month id to YYYY-MM"""
  y = mid / 12
  m = mid % 12
  return "%04d-%02d" %  (y, m)
# Convert my_data to one record per month.
new_data = []
for r in my_data:
  mstart = month_id(r['status_start'])
  mend = month_id(r['status_end'])
  for mid in range(mstart, mend+1):
    m = to_yyyymm(mid)
    new_data.append( { 'client_id': r['client_id'], 'service_id': r['service_id'], 'service_status': r['service_status'], 'month': m } )
df = pd.DataFrame(new_data)
grouped = df.groupby(['client_id', 'month', 'service_status'])
for name, g in grouped:
  print name, len(g)

输出:

('01', '2014-01', 'in_progress') 1
('01', '2014-01', 'stopped') 1
('01', '2014-02', 'in_progress') 2
('01', '2014-02', 'stopped') 1
('01', '2014-03', 'in_progress') 1
('01', '2014-04', 'in_progress') 1
('02', '2014-02', 'stopped') 2
('02', '2014-03', 'in_progress') 1
('02', '2014-03', 'stopped') 2
('02', '2014-04', 'in_progress') 1
('02', '2014-04', 'stopped') 2
('03', '2014-01', 'in_progress') 1
('03', '2014-02', 'in_progress') 3
('03', '2014-03', 'in_progress') 3
('03', '2014-04', 'in_progress') 2

缺少特定状态的记录意味着该客户端和月份的计数为零。

如果数据位于数据框中,请使用df.itertuples()循环访问行:

i_client_id = 1+df.columns.get_loc('client_id')
i_service_id = 1+df.columns.get_loc('service_id')
...
for r in df.itertuples():
  ... same code except replace r['client_id'] with r[i_client_id], etc.

最新更新