2016-12-14 16 views
4

私は私が何をしたいのですがこれは何パンダ - 基準

>>> a_df 
    state 
1 A 
2 B 
3 A 
4 B 
5 C 

のように見えるのデータフレームを持っているに一致する連続した行のペアを選択するには、特定の順序に一致するすべての連続した行を返すことです。たとえば、このシーケンスが['A', 'B']の場合、状態がAで直後にBの行が戻されます。上記の例では:

>>> cons_criteria(a_df, ['A', 'B']) 
    state 
1 A 
2 B 
3 A 
4 B 

または選択した配列は、['A', 'B', 'C']であれば、出力は

>>> cons_criteria(a_df, ['A', 'B', 'C']) 
    state 
3 A 
4 B 
5 C 

なければならない私は、現在の状態、ならびに次の状態を記憶することによってこれを行うことを決めました。

>>> df2 = a_df.copy() 
>>> df2['state_0'] = a_df['state'] 
>>> df2['state_1'] = a_df['state'].shift(-1) 

今、私はstate_0state_1に関して一致させることができます。しかし、これは最初のエントリだけを返します:

>>> df2[(df2['state_0'] == 'A') & (df2['state_1'] == 'B')] 
    state 
1 A 
3 A 

ここでロジックを修正して、すべての連続する行が返されるようにしますか?パンダでこれにアプローチするより良い方法はありますか?

答えて

2

ここでは、私にとっては効果的な解決策がありますが、数値の行インデックスの場合にのみ適用されます。私はもう少し面白いあなたのデータフレームを作った、今では2つのABCのパターンがあります。

pattern = ['A','B','C'] 

この式は、各パターンの開始行のセットを検索します。

a_df=pd.DataFrame(['A','B','A','B','C','D','A','A','B','C','E'], 
        columns=["state"]) 

そしてここでは、マッチパターンです:一般的に

starts = set(a_df[a_df['state']   =='A'].index) & 
     set(a_df[a_df['state'].shift(-1)=='B'].index) & 
     set(a_df[a_df['state'].shift(-2)=='C'].index) 
print(starts) 
# {2, 7} 

starts = set.intersection(
      *[set(a_df[a_df['state'].shift(-i)==value].index) 
      for i,value in enumerate(pattern)]) 

この式は、3行の範囲に開始行番号を変換し、行範囲を選択:一般に

result = [a_df.ix[range(i, i+3)] for i in starts] 
print(result) 
# [ state 
# 2  A 
# 3  B 
# 4  C, state 
# 7  A 
# 8  B 
# 9  C] 

result = [a_df.ix[range(i, i+len(pattern))] for i in starts] 
3

Iこの

def match_slc(s, seq): 
    # get list, makes zip faster 
    l = s.values.tolist() 
    # count how many in sequence 
    k = len(seq) 
    # generate numpy array of rolling values 
    a = np.array(list(zip(*[l[i:] for i in range(k)]))) 
    # slice an array from 0 to length of a - 1 with 
    # the truth values of wether all 3 in a sequence match 
    p = np.arange(len(a))[(a == seq).all(1)] 
    # p tracks the beginning of a match, get all subsequent 
    # indices of the match as well. 
    slc = np.unique(np.hstack([p + i for i in range(k)])) 
    return s.iloc[slc] 
ような機能を使用したいです

デモンストレーション

s = pd.Series(list('ABABC')) 

print(match_slc(s, list('ABC')), '\n') 
print(match_slc(s, list('AB')), '\n') 

2 A 
3 B 
4 C 
dtype: object 

0 A 
1 B 
2 A 
3 B 
dtype: object 
+0

これは良いアプローチですが、numpyのために行くと(私はnumpyの中でその熟練していないんだと、私は、私は完全には従わないと思います)読み、それは少し難しいことができます。私が気づいたのは、 '(df2 ['state_0'] == 'A')&(df2 ['state_1'] == 'B')'という行はすべての初期点に対してバイナリ系列を返します。 このシリーズが「真」であるインデックスを得ることができれば、これらの数字に1を加えて次の行を得て、それらの和集合をa_dfから引っ張って、正しい答えを得るでしょう。 バイナリシリーズをインデックスに変換する方法はありますか? – user1496984

+0

@ user1496984はい!代わりに 's.iloc [slc]'を返す代わりに 's.index [slc]'を返します。 – piRSquared

+0

ああ、インデックスが文字列の場合(これは他の答えと同じように)、これは機能しません。代わりに、代わりにSeriesの各True要素の「整数位置」を取得することはできますか?最終的な要素を選択するのに '.iloc'を使わなければならないと思います。 – user1496984