我有一个测试数据集,它显示了每个客户端、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
我尝试使用groupby
和pivot_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.