【问题标题】:Dask groupby over each column separately gives out wrong resultDask groupby 在每列上分别给出错误的结果
【发布时间】:2019-12-17 13:08:59
【问题描述】:

我在这里用虚拟数据模拟我真正想做的事情。我需要执行的步骤:

  1. 分别对每一列进行一些转换。
  2. 执行 groupby 操作以针对目标列聚合每列的一些指标。

我模拟的代码。

import dask.dataframe as dd
from dask.distributed import Client, as_completed, LocalCluster

cluster = LocalCluster(processes=False)

client = Client(cluster, asynchronous=True)

csv_loc = '/Users/apple/Downloads/iris.data'
df = dd.read_csv(csv_loc) # ofcourse, u need to give aws creds here. Omitting it. Assuming u can read from s3 or otherwise.
client.persist(df)
cols = ['sepal_length', 'sepal_width' ,'petal_length' ,'petal_width', 'species']

# This is needed because I am doing some custom operation on actual data
for c in cols:
    if c != 'species':
        df[c] = df[c].map(lambda x: x*10)
client.persist(df) # Is this the trouble?

def agg_bivars(col_name):
    agg_df = df.groupby('species')[col_name].sum().compute()
    return {col_name : agg_df}

agg_futures = client.map(agg_bivars, ['sepal_length', 'sepal_width' ,'petal_length' ,'petal_width'])

for batch in as_completed(agg_futures, with_results=True).batches():
   for future, result in batch:
       print('result: {}'.format(result))


client.restart()
client.close()
cluster.close()

您可以从此link 下载数据。这是一个非常标准的在线流行数据。

我得到的结果:不同列的分组结果相同。

预期结果:不同列需要不同的 groupby 结果。

结果:

result: {'sepal_width': species
Iris-setosa        2503.0
Iris-versicolor    2968.0
Iris-virginica     3294.0
Name: sepal_length, dtype: float64}
result: {'sepal_length': species
Iris-setosa        2503.0
Iris-versicolor    2968.0
Iris-virginica     3294.0
Name: sepal_length, dtype: float64}
result: {'petal_width': species
Iris-setosa        2503.0
Iris-versicolor    2968.0
Iris-virginica     3294.0
Name: sepal_length, dtype: float64}
result: {'petal_length': species
Iris-setosa        2503.0
Iris-versicolor    2968.0
Iris-virginica     3294.0
Name: sepal_length, dtype: float64}

Process finished with exit code 0

如果我只在 df 上进行 groupby,它可以正常工作。但是,这里的问题是我必须在每个列的 groupby 之前对整个 df 进行一些转换。注意我在做client.persist(df) 两次。我做了第二次,因为无论我做了什么新的转换,我都希望它们能够持续存在,以便我可以快速查询。

【问题讨论】:

  • 第二个client.persist是不必要的,第一个应该被称为df = client.persist(df)

标签: python pandas dask dask-distributed


【解决方案1】:

问题在于agg_bivars 函数中的compute()

试试下面的代码:

def agg_bivars(col_name):
    agg_df = df.groupby('species')[col_name].sum()  #.compute()
    return {col_name : agg_df}

agg_futures = client.map(agg_bivars, ['sepal_length', 'sepal_width' ,'petal_length' ,'petal_width'])

for batch in as_completed(futures=agg_futures, with_results=True).batches():    
    for future, result in batch:        
        print(f'result: {list(result.values())[0].compute()}')

结果:

result: species
setosa        2503.0
versicolor    2968.0
virginica     3294.0
Name: sepal_length, dtype: float64
result: species
setosa        1709.0
versicolor    1385.0
virginica     1487.0
Name: sepal_width, dtype: float64
result: species
setosa         732.0
versicolor    2130.0
virginica     2776.0
Name: petal_length, dtype: float64
result: species
setosa         122.0
versicolor     663.0
virginica     1013.0
Name: petal_width, dtype: float64

【讨论】:

  • 最后一行print(f'result: {list(result.values())[0].compute()}') 不会阻塞直到计算?整个操作是连续的,因为在第一个 compute() 完成之前,不能转到第二个。
  • 如果你将time.sleep(5) 添加到agg_bivars 你会发现它不是连续的。
【解决方案2】:

在我看来你把事情复杂化了。

熊猫

import pandas as pd
df = pd.read_csv("iris.csv")

df[df.columns[:-1]] = df[df.columns[:-1]] * 10

df.groupby("species").sum()

            sepal_length  sepal_width  petal_length  petal_width
species                                                         
setosa            2503.0       1709.0         732.0        122.0
versicolor        2968.0       1385.0        2130.0        663.0
virginica         3294.0       1487.0        2776.0       1013.0

黎明

import dask.dataframe as dd

df = dd.read_csv("iris.csv")
for col in df.columns[:-1]:
    df[col] = df[col]*10

df.groupby("species").sum().compute()

            sepal_length  sepal_width  petal_length  petal_width
species                                                         
setosa            2503.0       1709.0         732.0        122.0
versicolor        2968.0       1385.0        2130.0        663.0
virginica         3294.0       1487.0        2776.0       1013.0

那么,如果您希望结果为dict,您只需将to_dict() 添加到输出中。

【讨论】:

  • 我的意思不是做Groupby-sum,而是对每一列做运算。在此示例中,它仅位于 species 列上。我可能有不止一列要分组但分开。我想更正我的实际代码。
猜你喜欢
  • 2017-11-20
  • 1970-01-01
  • 2017-08-19
  • 2022-10-05
  • 1970-01-01
  • 1970-01-01
  • 2020-03-16
  • 2014-09-16
  • 2013-11-08
相关资源
最近更新 更多