我有这个测试数据集,显示每个客户端,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中有多少服务,每月和每个客户?
也就是说,例如,1月份的客户'01'有1个服务'in_progress'和1'停止'。同一个客户'01',在二月有2'in_progress'(已经在1月份和2月份新的那个)和1个新标记为'已停止'。但是在3月和4月只有一个服务'in_progress'(services_ids'01'和'02'在2月终止)。按照同样的规则,1月份的客户'03'有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
我尝试使用groupby
和pivot_table
,但我没有成功。好吧,我必须诚实:我使用了一个for
循环,需要6个小时才能完成(原始数据集的行数超过500万)。
有人可以帮忙吗?熊猫/蟒蛇新手,请耐心等待! :)
谢谢!
答案 0 :(得分:0)
您必须创建一个每月有一条记录的新数据集,例如为此记录:
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.