2016-02-22 8 views
8
  1. これを行うには、より速く、もっとpythonicな方法がありますか?
  2. この警告を生成する とは何ですか?UserWarning: Boolean Series key will be reindexed to match DataFrame index. "DataFrame index.", UserWarning 私はそれに気を付ける必要がありますか?

私はcsvファイルにorg、month、personの3つの列があります。私はpandas.core.frame.DataFrameに読んだPython 3.5でサブセットを簡単に比較できるように、データテーブルを構造化してアクセスするにはどうすればよいですか?

| org | month | person | 
| --- | ---------- | ------ | 
| 1 | 2014-01-01 | 100 | 
| 1 | 2014-01-01 | 200 | 
| 1 | 2014-01-02 | 200 | 
| 2 | 2014-01-01 | 300 | 

data = pd.read_csv('data_base.csv', names=['month', 'org', 'person'], skiprows=1) 

最終目標は、最初の期間中の人物のセットで2期連続の間に人々の共通部分を比較することです。

org: 1, month: 2014-01-01, count(intersection((100, 200), 200))/len(set(100, 200)) == 0.5 

編集:

このような出力を生成し
import pandas as pd 
import sys 

data = pd.read_csv('data_base.csv', names=['month', 'org', 'person'], skiprows=1) 
data.sort_values(by=['org', 'month', 'person']) 

results = {} 
for _org in set(data.org): 
    results[_org] = {} 
    months = sorted(list(set(data[data.org == _org].month))) 
    for _m1, _m2 in zip(months, months[1:]): 
     _s1 = set(data[data.org == _org][data.month == _m1].person) 
     _s2 = set(data[data.org == _org][data.month == _m2].person) 
     results[_org][_m1] = float(len(_s1 & _s2)/len(_s1)) 
     print(str(_org) + '\t' + str(_m1) + '\t' + str(_m2) + '\t' + str(round(results[_org][_m1], 2))) 
     sys.stdout.flush() 

::私はそれはで動作するようになった

UserWarning: Boolean Series key will be reindexed to match DataFrame index. "DataFrame index.", UserWarning 
5640 2014-01-01 2014-02-01 0.75 
5640 2014-02-01 2014-03-01 0.36 
5640 2014-03-01 2014-04-01 0.6 
... 

しかし、それは本当に遅いと醜いのようなものだ...で、エンベロープ計算の現在のレートは、2年間のデータバッチで約22時間と見積もっています。

+1

パンダは完全な操作に適しており、スライシングには適していません。1つの要素にアクセスする時間は、10〜100マイクロ秒のオーダーで、辞書ルックアップ(50 ns未満)の場合の1000倍になります。 pandasは、大規模なデータを含むフルデータフレームまたは列方向の計算に最適です。長い開始時間は、非常に高速でベクトル化された計算とうまく相殺されます。 ここでは、要素ごとの計算とPandasタイプからの変換を効果的に行っています.Pandasは優れていますが、このタスクに適したライブラリではありません。 –

答えて

3

確かに、私はパンダを一度も使用していないので、これは慣用的ではありません。これは基本的なPython構造体を使用するだけです。

import collections 
org_month_dict = collections.defaultdict(set) 

# put the data into a simple, indexed data structure 
for index, row in data.iterrows(): 
    org_month_dict[row['org'], row['month']].add(row['person']) 

orgs = set(data.org) 
months = sorted(set(data.months)) 
for org in orgs: 
    for mindex in range(len(months)-1): 
     m1 = months[mindex] 
     m2 = months[mindex+1] 
     print org_month_dict[org, m2] & org_month_dict[org, m1] # persons in common between month 1 and 2 

これはあなたの内側のループで高価なdata[data.org == _org][data.month == _m1]検索を行うことからあなたを節約、組織や月ごとにインデックス化されorg_month_dictで「キャッシュされた」ルックアップテーブルを作成します。元のコードよりもはるかに高速に実行する必要があります。

+0

とにかくここでパンダを使ってはいけません(上の私のコメントを見てください)、これは正しいアプローチを使った素晴らしい答えです。 –

+0

パンダのスライス速度の欠点に関する情報をありがとう。私はcsvファイルをPythonに読み込む方法を調べました。例はPandasのread_csv関数を使用していました。 – zhespelt

1

私はここでパンダを却下するとは限りません。それはいくつかのことに依存します。私はパンダがあなたのデータを保存する本当にコンパクトな方法であるとは思わないが、それは主にこれを軽減する自動圧縮と疎ストレージオプションを持っている。私は速度がかなり妥当であると期待していますが、実際にあなたのデータをテストして確実に言う必要があります。

私の意見では、データを保存する便利な方法を提供していますし、日付を処理する便利な方法も提供しています。完了したら、結果を表形式で出力することができます。

まず、問題をよりよく説明するためにデータを少し拡張します。

org  month person 
0  1 2014-01-01  100 
1  1 2014-01-01  200 
2  1 2014-01-02  200 
3  1 2014-01-03  300 
4  1 2014-01-03  100 
5  1 2014-01-04  200 
6  1 2014-01-04  100 
7  1 2014-01-04  300 
8  2 2014-01-01  100 
9  2 2014-01-01  200 
10 2 2014-01-02  300 
11 2 2014-01-02  400 
12 2 2014-01-03  100 
13 2 2014-01-04  200 
14 2 2014-01-04  100 

その後、あなたはこのような何か行うことができます:

df['one'] = 1 
df = df.set_index(['org','month','person']).unstack('person') 
numer = ((df==df.shift(-1)) & (df.notnull())).sum(axis=1) 
denom = df.notnull().sum(axis=1) 

df['numer'] = numer 
df['denom'] = denom 
df['ratio'] = numer/denom 

       one    numer denom  ratio 
person   100 200 300 400      
org month           
1 2014-01-01 1 1 NaN NaN  1  2 0.500000 
    2014-01-02 NaN 1 NaN NaN  0  1 0.000000 
    2014-01-03 1 NaN 1 NaN  2  2 1.000000 
    2014-01-04 1 1 1 NaN  2  3 0.666667 
2 2014-01-01 1 1 NaN NaN  0  2 0.000000 
    2014-01-02 NaN NaN 1 1  0  2 0.000000 
    2014-01-03 1 NaN NaN NaN  1  1 1.000000 
    2014-01-04 1 1 NaN NaN  0  2 0.000000 

を私はORG 1と2を組織間のブレークポイントのように、ここでいくつかの詳細を無視していますが、あなたはこれに対処するためにGROUPBYを追加することができます。同様に、人がいない日を処理するためのコードを追加することもできますし、それに対処する方法もあります。

+0

'(df == df.shift(-1))'行について説明できますか? – zhespelt

+0

これは、どのセルが上記のセルと一致するかを示すブール値です。それは何をしているのかをよりよく理解するために、 '数値'行を取り出して個々の部分をプリントアウトするだけです。 – JohnE

関連する問題