熊猫匹配多列模式

时间:2017-06-29 07:17:20

标签: python pandas

我有一个由布尔值组成的数据框。我想匹配数据帧中的某些多列模式。模式看起来像:

    bar     foo
0   False   True
1   True    False

预期的输出结果如下:

      foo    bar pattern
0    True  False   False
1    True  False   False
2    True  False    True
3   False   True   False
4   False   True   False
5   False   True   False
6   False  False   False
7   False  False   False
8   False  False   False
9   False   True   False
10  False   True   False
11  False   True   False
12  False   True   False
13  False   True   False
14  False   True   False
15  False   True   False
16   True  False   False
17   True  False   False
18   True  False    True
19  False   True   False
20  False   True   False
21  False   True   False
22   True  False    True
23  False   True   False
24  False   True   False
25  False   True   False

我提出了自己的实现,但我想应该有更好的实现。

def matcher(df, pattern):
    def aggregator(pattern):
        """Returns a dict of columnswith their aggregator function
        which is the partially applied inner in this case"""
        def inner(col, window):
            return (window == pattern[col]).all()
        return {col: partial(inner, col) for col in pattern.columns}

    aggregated = (df
                  # Feed the chunks to aggregator in `len(pattern)` sized windows
                  .rolling(len(pattern))
                  .aggregate(aggregator(pattern))
                  # I'd like it to return True at the beginning of the match
                  .shift(-len(pattern) + 1)
                  # rows consisting of nan return true to `.all()`
                  .fillna(False))
    ret = [row.all() for _, row in aggregated.iterrows()]
    return pd.Series(ret)

我最关心的是处理nan值,以及缺少通配符支持(为了支持不一定是盒形图案)。

有什么建议吗?

2 个答案:

答案 0 :(得分:1)

如果pd.concat()对你来说不是太昂贵,那么下面的代码可以很好地提高效率,因为没有循环也没有嵌套函数。

print(df)  # Original data without 'pattern' column.

df_wide = pd.concat([df, df.shift(-1)], axis=1)
df_wide.columns = ['foo0', 'bar0', 'foo-1', 'bar-1']

pat = ((df_wide['foo0'] == True) & (df_wide['bar-1'] == True)) & \
      ((df_wide['bar0'] == False) & (df_wide['foo-1'] == False)) 

df['pattern'] = False
df.loc[df_wide[pat].index, 'pattern'] = True

print(df)  # Result data with 'pattern' column.

# Original data without 'pattern' column.
      foo    bar
0    True  False
1    True  False
2    True  False
3   False   True
4   False   True
5   False   True
...

# Result data with 'pattern' column.
      foo    bar  pattern
0    True  False    False
1    True  False    False
2    True  False     True
3   False   True    False
4   False   True    False
5   False   True    False
6   False  False    False
7   False  False    False
8   False  False    False
9   False   True    False
10  False   True    False
11  False   True    False
12  False   True    False
13  False   True    False
14  False   True    False
15  False   True    False
16   True  False    False
17   True  False    False
18   True  False     True
19  False   True    False
20  False   True    False
21  False   True    False
22   True  False     True
23  False   True    False
24  False   True    False
25  False   True    False

答案 1 :(得分:1)

假设df1是你的patten df而df2是你的值df,你可以使用apply来检查模式。对于每一行,我们得到当前行和下一行,然后将2 * 2数组与df1元素进行比较,并检查所有元素是否相同。

df2.apply(lambda x: (df2[['foo','bar']].iloc[x.name:x.name+2].values\
                     ==df1[['foo','bar']].values).all(),axis=1)
Out[213]: 
0     False
1     False
2      True
3     False
4     False
5     False
6     False
7     False
8     False
9     False
10    False
11    False
12    False
13    False
14    False
15    False
16    False
17    False
18     True
19    False
20    False
21    False
22     True
23    False
24    False
25    False
dtype: bool