我想在分类变量的数据框中找到一个向下行的模式。我可以看到如何使用Series.shift()来查找/关闭并使用布尔逻辑来查找模式,但是,我想用分组变量执行此操作,并且还标记作为模式一部分的所有行,而不仅仅是起始行。
代码:
import pandas as pd
from numpy.random import choice, randn
import string
# df constructor
n_rows = 1000
df = pd.DataFrame({'date_time': pd.date_range('2/9/2018', periods=n_rows, freq='H'),
'group_var': choice(list(string.ascii_uppercase), n_rows),
'row_pat': choice([0, 1, 2, 3], n_rows),
'values': randn(n_rows)})
# sorting
df.sort_values(by=['group_var', 'date_time'], inplace=True)
df.head(10)
我可以通过这个找到模式的开头(虽然没有分组):
# the row ordinal pattern to detect
p0, p1, p2, p3 = 1, 2, 2, 0
# flag the row at the start of the pattern
df['pat_flag'] = \
df['row_pat'].eq(p0) & \
df['row_pat'].shift(-1).eq(p1) & \
df['row_pat'].shift(-2).eq(p2) & \
df['row_pat'].shift(-3).eq(p3)
df.head(10)
我无法弄清楚的是,如何仅使用“group_var”执行此操作,而不是在模式的开头返回True,对于作为模式一部分的所有行都返回true。
感谢有关如何解决此问题的任何提示!
谢谢...
答案 0 :(得分:1)
这很有用。
它的工作原理如下:
a)对于每个组,它需要一个大小为4的窗口并扫描列,直到它找到确切顺序的组合(1,2,2,0)。一旦找到序列,它就会用1填充新列'pat_flag'的相应索引值
b)如果找不到组合,则用0填充列。
pattern = [1,2,2,0]
def get_pattern(df):
df = df.reset_index(drop=True)
df['pat_flag'] = 0
get_indexes = []
temp = []
for index, row in df.iterrows():
mindex = index +1
# get the next 4 values
for j in range(mindex, mindex+4):
if j == df.shape[0]:
break
else:
get_indexes.append(j)
temp.append(df.loc[j,'row_pat'])
# check if sequence is matched
if temp == pattern:
df.loc[get_indexes,'pat_flag'] = 1
else:
# reset if the pattern is not found in given window
temp = []
get_indexes = []
return df
# apply function to the groups
df = df.groupby('group_var').apply(get_pattern)
## snippet of output
date_time group_var row_pat values pat_flag
41 2018-03-13 21:00:00 C 3 0.731114 0
42 2018-03-14 05:00:00 C 0 1.350164 0
43 2018-03-14 11:00:00 C 1 -0.429754 1
44 2018-03-14 12:00:00 C 2 1.238879 1
45 2018-03-15 17:00:00 C 2 -0.739192 1
46 2018-03-18 06:00:00 C 0 0.806509 1
47 2018-03-20 06:00:00 C 1 0.065105 0
48 2018-03-20 08:00:00 C 1 0.004336 0
答案 1 :(得分:1)
您可以通过定义自定义聚合函数,然后在group_by语句中使用它,最后将其合并回原始数据帧。像这样:
聚合功能:
def pattern_detect(column):
# define any other pattern to detect here
p0, p1, p2, p3 = 1, 2, 2, 0
column.eq(p0) & \
column.shift(-1).eq(p1) & \
column.shift(-2).eq(p2) & \
column.shift(-3).eq(p3)
return column.any()
接下来按功能分组:
grp = df.group_by('group_var').agg([patter_detect])['row_pat']
现在将其合并回原始数据框:
df = df.merge(grp, left_on='group_var',right_index=True, how='left')