2017-06-26 10 views
2

私は2つのパンダデータフレームdf1df2を持っており、それらの "マージされたインデックス"が必要です。効率的にパンダインデックスの和集合を取得する

これは、たとえば、df1.add(df2, fill_value=0).index(基本的には行名の和集合)の場合に得られるインデックスを意味します。この種の計算(ここではadd)は別々のスクリプトで実行されていますが、これらのスクリプトでは「マージされたインデックス」を計算したくありませんが、 "マージされたインデックス"。

これを行うための「直接的な」(うまくいけば効率的な)方法がありますか?

私の目標は、実際には "タグ"をインデックス要素に関連付けることです。私は数組のデータフレームを持っています。各対は、1つの「タグ」に対応し、重複するインデックスを有することができる。異なるペアは、異なるタグを行い、重複するインデックスがないと考えられます。

基本的に、私は次のように働くだろうassociate_tag機能の効率的な実装を探しています:

dfA_1

idA_1 2 0 
idA_2 1 0 
idA_3 0 2 

dfA_2

idA_1 3 2 1 
idA_3 2 6 2 
idA_4 4 0 2 

merge_A = associate_tag((dfA_1, dfA_2), "A")

idA_1 A 
idA_2 A 
idA_3 A 
idA_4 A 
dfB_1

idB_1 2 2 1 
idB_2 3 0 0 
idB_3 3 1 3 

dfB_2

idB_1 0 
idB_2 3 
idB_4 2 
merge_B = associate_tag((dfB_1, dfB_2), "B")

idB_1 B 
idB_2 B 
idB_3 B 
idB_4 B 

total_merge = pd.concat((merge_A, merge_B))

idA_1 A 
idA_2 A 
idA_3 A 
idA_4 A 
idB_1 B 
idB_2 B 
idB_3 B 
idB_4 B 

データフレームのインデックス要素に関連付けるタグを知っていて、associate_tag関数はデータフレーム内の数値を完全に無視するのが理想的です。ここ

は、非理想的な実装である:

from functools import reduce 
from itertools import repeat 

def add_dataframes(df1, df2): 
    return df1.add(df2, fill_value=0) 

def sum_dataframes(dfs): 
    return reduce(add_dataframes, dfs) 

def associate_tag(dfs, tag): 
    return pd.concat((sum_dataframes(dfs).index, repeat(tag)), axis=1) 

def associate_tag(dfs, tag): 
    s = sum_dataframes(dfs) 
    return pd.DataFrame(list(zip(s.index, repeat(tag)))).set_index(0) 

Iが容易インデックス要素の混合物を含むデータフレームに「タグ」欄を追加するには、このtotal_mergeを使用する予定。

df

idA_2 5 4 1 
idB_1 1 0 0 
idB_4 2 1 2 
idA_4 2 3 2 

をそして私は、タグを使用して、余分な列を追加するpd.concat((df, total_merge), join="inner", axis=1)を使用します。たとえば、私が持っている可能性があり

idA_2 5 4 1 A 
idB_1 1 0 0 B 
idB_4 2 1 2 B 
idA_4 2 3 2 A 

はこれを行うには良い方法はありますオペレーションの種類?ここにあなたのコメントに基づいて

答えて

0

私はついにパンダことが判明Indexオブジェクトの実装は__or__でした。

associate_tagのうまくいけば、次のバージョンでは、余計な操作を回避:

from operator import or_ as union 
from itertools import repeat 
from functools import reduce 

def associate_tag(dfs, tag): 
    idx = reduce(union, (df.index for df in dfs)) 
    return pd.DataFrame(list(zip(idx, repeat(tag)))).set_index(0) 
0

が改正ソリューションです:

2部: は、あなたのカラム名に応じて、あなたのデータフレームを組み合わせることで、あなたが確認しましたら、あなただけのデータフレームのあなたの全リストをpd.concatことができ列名が並んでいます。その場合:

 col1 col2 
index    
idA_1  2  0 
idA_2  1  0 
idA_3  0  2 

と dfA_2は次のとおりです: dfA_1があり、その後

 col1 col2 col3 
index     
idA_1  3  2  1 
idA_3  2  6  2 
idA_4  4  0  2 

final = pd.concat([dfA_1,dfA_2]) 

final 
     col1 col2 col3 
index     
idA_1  2  0 NaN 
idA_2  1  0 NaN 
idA_3  0  2 NaN 
idA_1  3  2 1.0 
idA_3  2  6 2.0 
idA_4  4  0 2.0 

ゼロでそれらのNaNを満たすために:

final.fillna(0, inplace=True) 

パート2 、タグ: あなたがタグを作成すると、インデックスのマップを定義するのと同じくらい簡単です、あなたは、簡単な関数を書く辞書をハードコーディング、またはラムダを使用することができますいずれかのことをしたら:

final['tag'] = final.index.map(lambda x: x[2]) 

final 
     col1 col2 col3 tag 
index      
idA_1  2  0 0.0 A 
idA_2  1  0 0.0 A 
idA_3  0  2 0.0 A 
idA_1  3  2 1.0 A 
idA_3  2  6 2.0 A 
idA_4  4  0 2.0 A 
+0

私はなるように、私は何とか、(私はデータフレームを追加するとき、それはそれをしないと仮定)パンダはこれを達成するために、内部で効率的な方法を持っていたことを期待していました除外された索引を「手動で」作成する必要はありません。 – bli

+0

おそらく、タグが分かっているという事実を使って、あなたのソリューションの最後のステップを単純化することができます: 'final [" tag "] =" A "'。さらに、私の実際のケースでは、タグは単に行の名前から推測することはできません。 私の "非理想的な実装"のように、 'concat'を' add'を使うよりも効率的であるかどうか知っていますか? – bli

+0

ええ、3番目の文字にタグをマッピングしたのは、サンプルデータに正しいBタグが与えられているためですが、実際のIDがどのように表示されるかに応じて個別のマッピングまたは関数でdictを作成できます。あなたはちょうどマップにも辞書を渡すことができます。私は、すべてのユースケースでconcatがより効率的であるかどうかはわかりませんが、組み込みの関数を使用すると簡単に実装できます。あなたは速度が制約であるとは言及しなかったが、私はデバッグするには少なくともそれが良いもので、はるかに簡単だと賭けていた。 – tvashtar

関連する問題