2017-07-13 9 views
1

パンダ:マージ行は、私はこのようになりますパンダのデータフレーム持っているデータフレーム

df =pd.DataFrame([[0,10,0,'A','A',6,7],[11,21,1,'A','A',8,9],[0,13,1,'B','B',11,13],[0,12,1,'C','C',14,15],[13,14,0,'C','C',16,18]],columns=['Start Sample','End Sample','Value','Start Name','End Name','Start Time','End Time']) 

df 
Out[18]: 
    Start Sample End Sample Value Start Name End Name Start Time End Time 
0    0   10  0   A  A   6   7 
1   11   21  1   A  A   8   9 
2    0   13  1   B  B   11  13 
3    0   12  1   C  C   14  15 
4   13   14  0   C  C   16  18 

が、私はグループと同じValueを持つ連続した行をしたいのであれば、行iの行i+1と終了時間の開始時間の間の差< 3

たとえば、1,2,3行は同じ値を持つ連続する行です。

df['Start Time'].iloc[2] - df['End Time'].iloc[1] is = 2 
df['Start Time'].iloc[3] - df['End Time'].iloc[2] is = 1 

だから、それらはすべてマージする必要があります。 私はこれらの行になることを希望:

df2 
Out[25]: 
    Start Sample End Sample Value Start Name End Name Start Time End Time 
0    0   10  0   A  A   6   7 
1   11   12  1   A  C   8  15 
2   13   14  0   C  C   16  18 

マージされた新しい行が持つべきであることに注意してください:

1) Start Sample = to the Start Sample of the first row merged 
2) End Sample = to the End Sample of the last row merged 
3) Value = to the common value 
4) Start Name = to the Start Name of the first row merged 
5) End Name = to the End Name of the last row merged 
6) Start Time = to the Start Name of the first row merged 
7) End Name = to the End Name of the last row merged 

答えて

2

最初にいくつかの説明を考えてください。ここでのアプローチは、 "Value"に基づいてサブセットに分割し、それらのサブデータフレームを処理することです。

def agg(series): 
    if series.name.startswith('Start'): 
     return series.iloc[0] 
    return series.iloc[-1] 

subsets = [subset.apply(agg) for _, subset in 
      df.groupby((df['Value']!=df['Value'].shift(1)).cumsum())] 

pd.concat(subsets, axis=1).T 

「トリッキーな」部分はdf['Value']!=df['Value'].shift(1)).cumsum()です。これは、「値」が変更されたときに検出されます。私たちはグループ化しますが、最初にcumsum()が一意の値を与えます。

groupbyの後には、興味のあるデータフレームのサブセットを繰り返しています。ここからは、これが柔軟な理由がたくさんあります。

各サブセットについて、apply関数が各シリーズ(列)に適用されます。あなたのケースでは、列名に基づいて2つの値のいずれかを探しているので、各シリーズに1つの関数(aggここ)を適用できます。

編集:上記の変更のテストには、OPで指定された2つの基準のいずれかが含まれていました。両方を含めると簡単ですが、ロジックが拡張されて少し分けてください。私はすでにその論理のために不合理なオンライナーの範囲を押していました。 groupby条件は次のようになります。

val_chg = df['Value'] != df['Value'].shift(1) 
time_chg = df['Start Time']-df['End Time'].shift(1) >=3 

df.groupby((val_chg | time_chg).cumsum()) 
+0

こんにちは、ありがとうございます。しかし、行iの開始時間と行iの終了時間の差が<3である場合にのみ行をグループ化したいと思います。この条件をどこに追加できますか? – gabboshow

+0

@ gabboshow oops。そのロジックで編集を追加しました。ブーリアンをミックスして一致させると、変更を見つけて、クマをグループ化します。 –

0

があり、それを行うためのより良い方法は、おそらくですが、ここでiterrows()アプローチです:

df =pd.DataFrame([[0,10,0,'A','A',6,7],[11,21,1,'A','A',8,9],[0,13,1,'B','B',11,13],[0,12,1,'C','C',14,15],[13,14,0,'C','C',16,18]],columns=['Start Sample','End Sample','Value','Start Name','End Name','Start Time','End Time']) 
df['keep'] = '' 

active_row = None 

for i, row in df.iterrows(): 
    if active_row is None: 
     active_row = i 
     df.loc[i,'keep'] = 1 
     continue 

    if row['Value'] != df.loc[active_row,'Value']: 
     active_row = i 
     df.loc[i,'keep'] = 1 
     continue 
    elif row['Start Time'] - df.loc[active_row,'End Time'] >= 3: 
     active_row = i 
     df.loc[i,'keep'] = 1 
     continue 

    df.loc[active_row,'End Time'] = row['End Time'] 
    df.loc[active_row,'End Sample'] = row['End Sample'] 
    df.loc[active_row,'End Name'] = row['End Name'] 
    df.loc[i,'keep'] = 0 

final_df=df[df.keep == 1].drop('keep',axis=1) 

最後の意味のある行を記憶してループ中に更新します。各ループは行をkeep(1)またはkeep(0)として分類し、最後に手作業でフィルタリングするために使用します。