私はdask dataframe
インデックスでグループ化(first_name
)。
import pandas as pd
import numpy as np
from multiprocessing import cpu_count
from dask import dataframe as dd
from dask.multiprocessing import get
from dask.distributed import Client
NCORES = cpu_count()
client = Client()
entities = pd.DataFrame({'first_name':['Jake','John','Danae','Beatriz', 'Jacke', 'Jon'],'last_name': ['Del Toro', 'Foster', 'Smith', 'Patterson', 'Toro', 'Froster'], 'ID':['X','U','X','Y', '12','13']})
df = dd.from_pandas(entities, npartitions=NCORES)
df = client.persist(df.set_index('first_name'))
(明らかに、実際のentities
は数千行です)
グループ化された各データフレームにユーザー定義関数を適用したいと思います。各行をグループ内の他のすべての行と比較したい( パンダは各行をデータフレーム内のすべての行と比較し、結果を各行のリストに保存する )。
以下は私が適用しようとしている関数です:
def contraster(x, DF):
matches = DF.apply(lambda row: fuzz.partial_ratio(row['last_name'], x) >= 50, axis = 1)
return [i for i, x in enumerate(matches) if x]
テストentities
データフレームの場合、通常どおり関数を適用できます。
entities.apply(lambda row: contraster(row['last_name'], entities), axis =1)
そして、期待される結果は次のとおりです。
Out[35]:
0 [0, 4]
1 [1, 5]
2 [2]
3 [3]
4 [0, 4]
5 [1, 5]
dtype: object
entities
が巨大な場合、解決策はdask
を使用することです。 DF
関数のcontraster
は、グループ化されたデータフレームである必要があることに注意してください。
私は以下を使おうとしています:
df.groupby('first_name').apply(func=contraster, args=????)
しかし、グループ化されたデータフレームをどのように指定する必要がありますか(つまり、DF
のcontraster
?)
少し当て推量で、次のことが求められていると思います。
def mapper(d):
def contraster(x, DF=d):
matches = DF.apply(lambda row: fuzz.partial_ratio(row['last_name'], x) >= 50, axis = 1)
return [d.ID.iloc[i] for i, x in enumerate(matches) if x]
d['out'] = d.apply(lambda row:
contraster(row['last_name']), axis =1)
return d
df.groupby('first_name').apply(mapper).compute()
データに適用すると、次のようになります。
ID first_name last_name out
2 X Danae Smith [X]
4 12 Jacke Toro [12]
0 X Jake Del Toro [X]
1 U John Foster [U]
5 13 Jon Froster [13]
3 Y Beatriz Patterson [Y]
つまり、first_nameでグループ化するため、各グループには、それ自体とのみ一致する1つのアイテムのみが含まれます。
ただし、複数の行にあるfirst_name値がある場合は、次のように一致します。
entities = pd.DataFrame(
{'first_name':['Jake','Jake', 'Jake', 'John'],
'last_name': ['Del Toro', 'Toro', 'Smith'
'Froster'],
'ID':['Z','U','X','Y']})
出力:
ID first_name last_name out
0 Z Jake Del Toro [Z, U]
1 U Jake Toro [Z, U]
2 X Jake Smith [X]
3 Y John Froster [Y]
first_nameでexactの一致が必要ない場合は、first_nameでインデックスを並べ替え/設定して使用する必要があります。 map_partitions
似たような方法で。その場合、あなたはあなたの質問を改革する必要があるでしょう。
Groupby-applyに提供する関数は、入力としてPandasデータフレームまたはシリーズを取り、理想的には出力として1つ(またはスカラー値)を返す必要があります。追加のパラメーターは問題ありませんが、セカンダリである必要があります。最初の引数ではありません。これは、PandasとDaskデータフレームの両方で同じです。
def func(df, x=None):
# do whatever you want here
# the input to this function will have all the same first name
return pd.DataFrame({'x': [x] * len(df),
'count': len(df),
'first_name': df.first_name})
その後、通常どおりdf.groupbyを呼び出すことができます
import pandas as pd
import dask.dataframe as dd
df = pd.DataFrame({'first_name':['Alice', 'Alice', 'Bob'],
'last_name': ['Adams', 'Jones', 'Smith']})
ddf = dd.from_pandas(df, npartitions=2)
ddf.groupby('first_name').apply(func, x=3).compute()
これにより、pandasまたはdask.dataframeのいずれかで同じ出力が生成されます
count first_name x
0 2 Alice 3
1 2 Alice 3
2 1 Bob 3