繁体   English   中英

将函数应用于Dask中的分组数据框:如何在函数中将分组的Dataframe指定为参数?

[英]Apply function to grouped data frame in Dask: How do you specify the grouped Dataframe as argument in the function?

我有一个按索引( first_name )分组的dask dataframe

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在现实生活中是几千行)

我想将用户定义的函数应用于每个分组的数据帧。 我想将每一行与组中的所有其他行进行比较 (类似于Pandas将每一行与数据帧中的所有行进行比较,并将结果保存在每行的列表中 )。

以下是我尝试应用的功能:

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 请注意, contraster函数中的DF必须是分组数据帧。

我想使用以下内容:

df.groupby('first_name').apply(func=contraster, args=????)

但是,我应该如何指定分组数据框(即contraster框中的DF ?)

您为groupby-apply提供的函数应将Pandas数据帧或系列作为输入,并理想地返回一个(或标量值)作为输出。 额外的参数很好,但它们应该是次要的,而不是第一个参数。 在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

通过一些猜测,我认为以下是你所追求的。

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分组,每个组只包含一个项目,该项目仅与自身匹配。

但是,如果您有多个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上的完全匹配,那么您可能需要按first_name排序/设置索引并以类似的方式使用map_partitions 在这种情况下,您需要改革您的问题。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM