【问题标题】:Pandas python: count number of services broken by month and state of projectPandas python:计算按月和项目状态中断的服务数量
【发布时间】:2015-02-11 05:27:34
【问题描述】:

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

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 中每个月和客户有多少服务?

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

所以最终的 DataFrame 看起来像这样(现在您会看到箭头突出显示刚刚注释的示例的行):

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,但没有成功。好吧,我必须说实话:我使用了一个 for 循环,需要 6 个小时才能完成(原始数据集有超过 500 万行)。

有人可以帮忙吗? pandas/python 新手,请耐心等待! :)

谢谢!

【问题讨论】:

  • 这是一个有趣的问题。 非常感谢“我编写了代码,以便您可以复制和粘贴以生成 DataFrame。”:D
  • 我在寻求帮助,所以这是我能做的至少 :)

标签: python pandas


【解决方案1】:

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

          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、month 和 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.

【讨论】:

  • 非常适合 my_data!如果输入是名为 df 的 DataFrame 而不是列表 my_data 怎么办?我刚刚添加了 my_data,所以任何人都可以构建 df。
  • 刚刚再次更新 - 请注意 .get_loc 调用中的 1+
猜你喜欢
  • 2021-04-02
  • 1970-01-01
  • 1970-01-01
  • 2021-06-01
  • 2018-12-11
  • 2022-06-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多