データフレーム間のデータを検索して比較する

山芋パックチン

データフレームのマージについて問題があります。次の2つのデータフレームがあります。

df1:
ID name-group status
1  bob,david  good
2  CC,robben  good
3  jack       bad

df2:
ID  leader   location
2   robben   JAPAN
3   jack     USA
4   bob      UK

結果をフローとして取得したい。

dft
ID  name-group Leader location
1   bob,david   
2   CC,robben  Robben JAPAN
3   jack       Jack   USA

[リーダー]と[場所]は次の場合にマージされます

[leader] in df2 **IN** [name-group] of df1
&
[ID] of df2 **=** [ID] of df1

forループを試しましたが、時間コストが非常に高くなっています。この問題について何かアイデアはありますか?

ありがとう

忘れてください

実行可能なコードについては、投稿の最後を参照してください。提案された解決策は、関数にありusing_tidyます。


ここでの主な問題は、name-groupコンマで区切られた複数の名前が含まれていると、メンバーシップの検索が困難になることです。代わりに、のdf1各メンバーがname-group独自の行にある場合、メンバーシップのテストは簡単です。つまり、次のdf1ようになっているとします

   ID  name-group status
0   1  bob        good
0   1  david      good
1   2  CC         good
1   2  robben     good
2   3  jack       bad

次に、単純にマージdf1してdf2オンにIDし、leader 等しい かどうかをテストできname-groupます...ほぼ(以下の「ほぼ」理由を参照)。

置くdf1きちんとフォーマット(でPDFは)以下の溶液中での主なアイデアです。パフォーマンスが向上する理由は、2つの列間の同等性のテストは、文字列の列が文字列の別の列のサブ文字列であるか、文字列のリストを含む列のメンバーであるかをテストするよりもはるかに高速であるためです。

上記で「ほぼ」と言った理由は、別の問題があるためです。マージしdf1df2からID、次のような一部の行にはリーダーがありませんbob,david

ID  name-group Leader location
1   bob,david   

これらの行を保持したいだけで、この場合は基準#1が当てはまるかどうかをテストしたくないので、これらの行を別の方法で処理する必要があります。展開しないでください。この問題は、リーダーのない行を潜在的なリーダーのある行から分離することで処理できます(以下を参照)。


IDが併合することによって強制することは容易で一致していることを第二の基準、df1及びdf2ID

dft = pd.merge(df1, df2, on='ID', how='left')

最初の基準は、にあることdft['leader']ですdft['name-group']この基準は次のように表すことができます

In [293]: dft.apply(lambda x: pd.isnull(x['leader']) or (x['leader'] in x['name-group'].split(',')), axis=1)
Out[293]: 
0    True
1    True
2    True
dtype: bool

ただし、を使用するdft.apply(..., axis=1)と、行ごとに1回ラムダ関数呼び出されます。に多くの行がある場合、これは非常に遅くなる可能性がありますdft

に多くの行がある場合はdft、最初dftに整頓された形式(PDF)に変換して、各メンバーをdft['name-group']独自の行に配置することで、より良い結果を得ることができますただし、最初に、dftリーダーのあるサブデータフレームとリーダーのないサブデータフレームの2つに分割ましょう

has_leader = pd.notnull(dft['leader'])
leaderless, leaders = dft.loc[~has_leader, :], dft.loc[has_leader, :]

次にleaders、整頓された形式(行ごとに1つのメンバー)を配置します。

member = leaders['name-group'].str.split(',', expand=True)
member = member.stack()
member.index = member.index.droplevel(1)
member.name = 'member'
leaders = pd.concat([member, leaders], axis=1)

このすべての作業の見返りは、基準#1を高速計算で表現できるようになったことです。

# this enforces criteria #1 (leader of df2 is in name-group of df1)
mask = (leaders['leader'] == leaders['member']) 
leaders = leaders.loc[mask, :]
leaders = leaders.drop('member', axis=1)

望ましい結果は次のとおりです。

dft = pd.concat([leaderless, leaders], axis=0)

df1きちんとしたフォーマットにするために、私たちはいくつかの作業をしなければなりませんでした基準#1をより速く計算できるようにすることで、その余分な作業を行うコストが報われるかどうかを判断するためにベンチマークを行う必要があります。

ここでは1000行の大きめのデータフレーム使用したベンチマークであるdf1とはdf2

In [356]: %timeit using_tidy(df1, df2)
100 loops, best of 3: 17.8 ms per loop

In [357]: %timeit using_apply(df1, df2)
10 loops, best of 3: 98.2 ms per loop

行数が増えると、using_tidyoverの速度の利点が増えます。using_applypd.merge(df1, df2, on='ID', how='left')


ベンチマークの設定は次のとおりです。

import string
import numpy as np
import pandas as pd


df1 = pd.DataFrame({'name-group':['bob,david', 'CC,robben', 'jack'],
                    'status':['good','good','bad'],
                    'ID':[1,2,3]})
df2 = pd.DataFrame({'leader':['robben','jack','bob'],
                    'location':['JAPAN','USA','UK'],
                    'ID':[2,3,4]})

def using_apply(df1, df2):
    dft = pd.merge(df1, df2, on='ID', how='left')
    mask = dft.apply(lambda x: pd.isnull(x['leader']) or (x['leader'] in x['name-group'].split(',')), axis=1)
    return dft.loc[mask, :]

def using_tidy(df1, df2):
    # this enforces criteria #2 (the IDs are the same)
    dft = pd.merge(df1, df2, on='ID', how='left')

    # split dft into 2 sub-DataFrames, based on rows which have a leader and those which do not.
    has_leader = pd.notnull(dft['leader'])
    leaderless, leaders = dft.loc[~has_leader, :], dft.loc[has_leader, :]

    # expand leaders so each member in name-group has its own row
    member = leaders['name-group'].str.split(',', expand=True)
    member = member.stack()
    member.index = member.index.droplevel(1)
    member.name = 'member'
    leaders = pd.concat([member, leaders], axis=1)

    # this enforces criteria #1 (leader of df2 is in name-group of df1)
    mask = (leaders['leader'] == leaders['member']) 
    leaders = leaders.loc[mask, :]
    leaders = leaders.drop('member', axis=1)

    dft = pd.concat([leaderless, leaders], axis=0)
    return dft

def make_random_str_array(letters=string.ascii_uppercase, strlen=10, size=100):
    return (np.random.choice(list(letters), size*strlen)
            .view('|U{}'.format(strlen)))

def make_dfs(N=1000):
    names = make_random_str_array(strlen=4, size=10)
    df1 = pd.DataFrame({
        'name-group':[','.join(np.random.choice(names, size=np.random.randint(1,10), replace=False)) for i in range(N)],
        'status':np.random.choice(['good','bad'], size=N),
        'ID':np.random.randint(4, size=N)})
    df2 = pd.DataFrame({
        'leader':np.random.choice(names, size=N),
        'location':np.random.randint(10, size=N),
        'ID':np.random.randint(4, size=N)})

    return df1, df2

df1, df2 = make_dfs()

この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。

侵害の場合は、連絡してください[email protected]

編集
0

コメントを追加

0

関連記事

分類Dev

ilocを使用して別のデータフレームからデータフレームを検索する

分類Dev

rを使用してデータフレームの上位値を検索する

分類Dev

データフレーム内の文字列を検索して置換する

分類Dev

R制限を使用してデータフレーム内のデータを検索する

分類Dev

データフレーム内の特定の値の間にあるすべての値を検索する

分類Dev

パンダ間隔を使用して値を検索し、別のデータフレームを埋める方法

分類Dev

2つのデータフレームを比較して別のデータフレームを取得する

分類Dev

grep()を使用して、データフレームの列名を検索します

分類Dev

あるデータフレームを使用して別のデータフレームの値とインデックスを検索する方法

分類Dev

データフレーム内のカスタム値を検索して置換する

分類Dev

値がxとyの間にあるデータフレーム内のセルを検索します

分類Dev

列数が異なる2つのデータフレーム間の差を減算/検索します

分類Dev

1つのデータフレーム出力を使用して、別のデータフレームで一致する行を検索する

分類Dev

列データフレームの値を使用して列インデックスを検索する

分類Dev

あるデータフレームから別のデータフレームで欠落している値を検索する正しい方法

分類Dev

データフレーム列の各要素でgrplを使用して、異なるデータフレーム内の文字列を検索します

分類Dev

applyを使用した2つのデータフレーム間のすべての比較とすべての比較

分類Dev

Rデータフレーム-ある列の共通値を使用して別の列の値を検索する

分類Dev

パンダのデータフレームは、異なるデータフレームの値を検索し、値を割り当てます

分類Dev

他の行の値を検索して、新しいpandasデータフレーム列を作成する

分類Dev

pandasデータフレーム内の重複するすべての行を検索します

分類Dev

データフレームのリストでアイテムを検索してカウントする方法

分類Dev

別のデータフレームで新しい名前を検索して列名を変更する

分類Dev

Pythonでデータフレーム全体の一致する値を検索して置換する

分類Dev

別のデータフレームのデータフレーム列を検索する

分類Dev

文字列のベクトルを使用してデータフレーム内の文字列を検索する

分類Dev

リスト内包表記を使用してデータフレーム内の単一の値を検索する

分類Dev

行番号のリストを使用してデータフレーム列の値を検索する方法

分類Dev

パンダのデータフレーム検索を高速化する方法を探しています

Related 関連記事

  1. 1

    ilocを使用して別のデータフレームからデータフレームを検索する

  2. 2

    rを使用してデータフレームの上位値を検索する

  3. 3

    データフレーム内の文字列を検索して置換する

  4. 4

    R制限を使用してデータフレーム内のデータを検索する

  5. 5

    データフレーム内の特定の値の間にあるすべての値を検索する

  6. 6

    パンダ間隔を使用して値を検索し、別のデータフレームを埋める方法

  7. 7

    2つのデータフレームを比較して別のデータフレームを取得する

  8. 8

    grep()を使用して、データフレームの列名を検索します

  9. 9

    あるデータフレームを使用して別のデータフレームの値とインデックスを検索する方法

  10. 10

    データフレーム内のカスタム値を検索して置換する

  11. 11

    値がxとyの間にあるデータフレーム内のセルを検索します

  12. 12

    列数が異なる2つのデータフレーム間の差を減算/検索します

  13. 13

    1つのデータフレーム出力を使用して、別のデータフレームで一致する行を検索する

  14. 14

    列データフレームの値を使用して列インデックスを検索する

  15. 15

    あるデータフレームから別のデータフレームで欠落している値を検索する正しい方法

  16. 16

    データフレーム列の各要素でgrplを使用して、異なるデータフレーム内の文字列を検索します

  17. 17

    applyを使用した2つのデータフレーム間のすべての比較とすべての比較

  18. 18

    Rデータフレーム-ある列の共通値を使用して別の列の値を検索する

  19. 19

    パンダのデータフレームは、異なるデータフレームの値を検索し、値を割り当てます

  20. 20

    他の行の値を検索して、新しいpandasデータフレーム列を作成する

  21. 21

    pandasデータフレーム内の重複するすべての行を検索します

  22. 22

    データフレームのリストでアイテムを検索してカウントする方法

  23. 23

    別のデータフレームで新しい名前を検索して列名を変更する

  24. 24

    Pythonでデータフレーム全体の一致する値を検索して置換する

  25. 25

    別のデータフレームのデータフレーム列を検索する

  26. 26

    文字列のベクトルを使用してデータフレーム内の文字列を検索する

  27. 27

    リスト内包表記を使用してデータフレーム内の単一の値を検索する

  28. 28

    行番号のリストを使用してデータフレーム列の値を検索する方法

  29. 29

    パンダのデータフレーム検索を高速化する方法を探しています

ホットタグ

アーカイブ