Pandas - 查找与行序列模式匹配的行并将其编入索引

时间:2018-02-09 17:05:38

标签: pandas indexing row

我想在分类变量的数据框中找到一个向下行的模式。我可以看到如何使用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)

返回此内容:enter image description here

我可以通过这个找到模式的开头(虽然没有分组):

# 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)

enter image description here

我无法弄清楚的是,如何仅使用“group_var”执行此操作,而不是在模式的开头返回True,对于作为模式一部分的所有行都返回true。

感谢有关如何解决此问题的任何提示!

谢谢...

2 个答案:

答案 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')