2016-10-16 3 views
4

私は 'data'と 'cond'( - ition)列を持つpandas Dataframeを持っています。私は 'cond'にCONTINUOUS Trueオブジェクトの数が最も多い行の平均値(データ列の)が必要です。CONTINUOUSの最高数cond = Trueの 'data'の平均値を決定します。

Example DataFrame: 

     cond data 
    0 True 0.20 
    1 False 0.30 
    2 True 0.90 
    3 True 1.20 
    4 True 2.30 
    5 False 0.75 
    6 True 0.80 

    Result = 1.466, which is the mean value of row-indexes 2:4 with 3 True 

グループバイピック方式では、「ベクトル化」ソリューションを見つけることができませんでした。だから私は行をループする関数を書いた。残念ながら、これは1ミリオンラインで約1時間かかります。残念なことに、@ jitデコレーションは持続時間を測定可能に減少させません。

私が分析したいデータは、1年以上の監視プロジェクトからのもので、1ミリオンのデータフレームを3時間ごとに持っています。したがって、約3000のそのようなファイル。

効率的な解決策が非常に重要です。私はnumpyの解決策にも非常に感謝しています。

+1

既存のコードは何ですか? – kindall

+2

[この質問](http://stackoverflow.com/q/29142487/2285236)を見てください。 – ayhan

答えて

2

ここでnumpyのベースのアプローチだ -

# Extract the relevant cond column as a 1D NumPy array and pad with False at 
# either ends, as later on we would try to find the start (rising edge) 
# and stop (falling edge) for each interval of True values 
arr = np.concatenate(([False],df.cond.values,[False])) 

# Determine the rising and falling edges as start and stop 
start = np.nonzero(arr[1:] > arr[:-1])[0] 
stop = np.nonzero(arr[1:] < arr[:-1])[0] 

# Get the interval lengths and determine the largest interval ID 
maxID = (stop - start).argmax() 

# With maxID get max interval range and thus get mean on the second col 
out = df.data.iloc[start[maxID]:stop[maxID]].mean() 

ランタイムテスト関数として

アプローチ -

​​

タイミング -

In [208]: # Setup dataframe 
    ...: N = 1000 # Datasize 
    ...: df = pd.DataFrame(np.random.rand(N),columns=['data']) 
    ...: df['cond'] = np.random.rand(N)>0.3 # To have 70% True values 
    ...: 

In [209]: %timeit pandas_based(df) 
100 loops, best of 3: 2.61 ms per loop 

In [210]: %timeit numpy_based(df) 
1000 loops, best of 3: 215 µs per loop 

In [211]: # Setup dataframe 
    ...: N = 10000 # Datasize 
    ...: df = pd.DataFrame(np.random.rand(N),columns=['data']) 
    ...: df['cond'] = np.random.rand(N)>0.3 # To have 70% True values 
    ...: 

In [212]: %timeit pandas_based(df) 
100 loops, best of 3: 4.12 ms per loop 

In [213]: %timeit numpy_based(df) 
1000 loops, best of 3: 331 µs per loop 
+0

私が行ったテストはすべて正しいです。私はあなたが書いたことを理解しようとします。どうもありがとう。 –

+0

@StiviBここにコメントがいくつか追加されました。 – Divakar

+0

非常に高速なソリューションです。私はnumpyを更新しなければなりませんでしたが、今は完全に動作します。私はパンダのDataFramesでほとんどの計算を実行します。私は一般的にもっとnumpyを使うべきかどうか疑問に思います。私はこれを確認します。ありがとう。 –

3

Calculating the number of specific consecutive equal values in a vectorized way in pandasからのアプローチを使用して:

df['data'].groupby((df['cond'] != df['cond'].shift()).cumsum()).agg(['count', 'mean'])[lambda x: x['count']==x['count'].max()] 
Out: 
     count  mean 
cond     
3   3 1.466667 

呼び出し可能なことで、インデックスは、以前のバージョンのために、あなたが行うことができ、0.18.0が必要です。

res = df['data'].groupby((df['cond'] != df['cond'].shift()).cumsum()).agg(['count', 'mean']) 

res[res['count'] == res['count'].max()] 
Out: 
     count  mean 
cond     
3   3 1.466667 

仕組み:

を最初の部分、 df['cond'] != df['cond'].shift()はブール値配列を返します。

df['cond'] != df['cond'].shift() 
Out: 
0  True 
1  True 
2  True 
3 False 
4 False 
5  True 
6  True 
Name: cond, dtype: bool 

行が上記と同じであれば、値はFalseです。 GROUPBYは(列を渡す必要はありません上のグループに任意のシリーズを受け付けているので

(df['cond'] != df['cond'].shift()).cumsum() 
Out: 
0 1 
1 2 
2 3 
3 3 
4 3 
5 4 
6 5 
Name: cond, dtype: int32 

、あなたが渡すことができます:それはあなたが累積和を取る場合、これらの行(連続したもの)は同じ番号を持つことを意味します任意のリスト)、これを使用して結果をグループ化できます。 .agg(['count', 'mean']の部分は、各グループのそれぞれのカウントと手段を与え、最後に最も高いカウントを持つものを選択します。

これは、連続するFalseをまとめてグループ化することに注意してください。あなただけの連続した真のを検討したい場合は、あなたがグループ化シリーズを変更することができます:我々は条件がTrueのときはFalseだたいので

((df['cond'] != df['cond'].shift()) | (df['cond'] != True)).cumsum() 

、条件が「真OR下の行に等しいではないではない」となりました。元の行は次のように変更されます:

df['data'].groupby(((df['cond'] != df['cond'].shift()) | (df['cond'] != True)).cumsum()).agg(['count', 'mean'])[lambda x: x['count']==x['count'].max()] 
+0

素晴らしい!これは本当に難しい行です:)今まで私はあなたがしたことを完全に理解していませんが、コードは必要なものを正確に行います。どうもありがとう。 –

+0

@StiviBいくつかの説明を追加しました。下のメモも確認してください。 – ayhan

+0

追加説明をありがとう。 –

関連する問題