我有3种事件类型的数据,我想估计转移概率Pij(1)。假设事件i发生(因此我需要条件概率),这些表示某事件i跟随事件j的概率。我也想知道Pij(2)和Pij(3),这是事件i之后第二个(第三个)事件是事件j的条件概率。
看看一些模拟数据:
import pandas as pd
import numpy as np
np.random.seed(5)
strings=list('ABC')
events=[strings[i] for i in np.random.randint(0,3,20)]
groups=[1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2]
index=pd.date_range('2/2/2012',periods=20,freq='T')
dfm=pd.DataFrame(data={'event':events,'group':groups},index=index)
dfm.head()
event group
2012-02-02 00:00:00 C 1
2012-02-02 00:01:00 B 1
2012-02-02 00:02:00 C 1
2012-02-02 00:03:00 C 1
2012-02-02 00:04:00 A 1
到目前为止,我遵循了一个非常不优雅和天真的策略,并使用shift
来查看下一期间发生的事件:
#Create new columns containing the shifted values
for i in range(1,4):
dfm['event_t%i'%i]=dfm.event.groupby(dfm.group).shift(-i)
#Combine the columns with current and shifted values into one
for i in range(1,4):
dfm['NEWevent_t%i'%i]=dfm['event']+' '+dfm['event_t%i'%i]
dfm = dfm.drop('event_t%i'%i, 1)
#Count the number of times each combination occurs
A=dfm['NEWevent_t1'].groupby(dfm.group).value_counts()
B=dfm['NEWevent_t2'].groupby(dfm.group).value_counts()
C=dfm['NEWevent_t3'].groupby(dfm.group).value_counts()
merged=pd.concat([A, B, C], axis=1)
这确实给出了每个组发生特定事件组合(例如AA,AB,..)的次数。继续这一步,我可以使用组变量和两个字母对中的第一个字母作为分组变量来进行分组。这个暴力解决方案可能看起来像:
merged=merged.reset_index()
merged['first']=merged['level_1'].apply(lambda x: x[0])
merged.columns=['group','i j','t1','t2','t3','first']
merged.groupby(['group','first'])['t1','t2','t3'].sum()
sums=merged.groupby(['group','first'])['t1','t2','t3'].sum()
merged=pd.merge(merged,sums,left_on=['group','first'],right_index=True)
merged['Pij(1)']=merged.t1_x/merged.t1_y
merged['Pij(2)']=merged.t2_x/merged.t2_y
merged['Pij(3)']=merged.t3_x/merged.t3_y
merged[['group','i j','Pij(1)','Pij(2)','Pij(3)']]
merged.head()
group i j Pij(1) Pij(2) Pij(3)
0 1 A A 0.25 0.666667 0.666667
1 1 A B 0.25 NaN NaN
2 1 A C 0.50 0.333333 0.333333
3 1 B A 0.50 0.500000 0.500000
4 1 B C 0.50 0.500000 0.500000
我相信必须有一种更简单的方法来实现这一目标吗?关于如何提高效率的任何建议?
注意:我的实际数据集包含500万行,10种事件类型和100个组。
答案 0 :(得分:5)
呈现转移概率的最佳方式是在转移矩阵中,其中T(i,j)是Ti到达Tj的概率。让我们从您的数据开始:
import pandas as pd
import numpy as np
np.random.seed(5)
strings=list('ABC')
events=[strings[i] for i in np.random.randint(0,3,20)]
groups=[1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2]
index=pd.date_range('2/2/2012',periods=20,freq='T')
dfm=pd.DataFrame(data={'event':events,'group':groups},index=index)
for i in range(1,4):
dfm['event_t%i'%i]=dfm.event.groupby(dfm.group).shift(-i)
我认为你的轮班命令是可以的,但那只是我。无论如何,从这里你限制为'group' == 1
并填充转换矩阵。最后,除以列以获得转换概率。
trans = pd.DataFrame(columns=strings, index=strings)
g_dfm = dfm[dfm['group']==1]
for s1 in strings:
for s2 in strings:
events = g_dfm[(g_dfm['event']==s1) & (g_dfm['event_t1']==s2)]
trans.ix[s1, s2] = len(events)
trans = trans.astype(float).div(trans.sum(axis=1), axis=0)
trans = trans.fillna(0)
从那里,您可以制作热图:
import matplotlib.pyplot as plt
fig, ax = plt.subplots(figsize=(3,3))
ax.pcolormesh(trans.values, cmap=plt.get_cmap('Blues'), vmin=0, vmax=1)
ax.invert_yaxis()
ax.set_yticks(np.arange(0, len(trans.index))+0.5)
ax.set_xticks(np.arange(0, len(trans.columns))+0.5)
ax.set_yticklabels(trans.index, fontsize=16, color='k')
ax.set_xticklabels(trans.columns, fontsize=16, color='k')
ax.tick_params(direction='out', pad=10)
ax.set_frame_on(True)
for tk1, tk2 in zip(ax.xaxis.get_major_ticks(), ax.yaxis.get_major_ticks()):
tk1.tick1On, tk2.tick1On, tk1.tick2On, tk2.tick2On = [False]*4
plt.show()
冲洗并重复所有组以及第二次和第三次过渡。