簡體   English   中英

讀取進程並與 dask 並行連接 Pandas 數據幀

[英]read process and concatenate pandas dataframe in parallel with dask

我正在嘗試並行讀取和處理 csv 文件列表,並將輸出連接到單個pandas dataframe框中以進行進一步處理。

我的工作流程包括 3 個步驟:

  • 通過讀取 csv 文件列表(都具有相同的結構)創建一系列 Pandas 數據框

    def loadcsv(filename): df = pd.read_csv(filename) return df

  • 通過處理 2 個現有列為每個數據框創建一個新列

    def makegeom(a,b): return 'Point(%s %s)' % (a,b)

    def applygeom(df): df['Geom']= df.apply(lambda row: makegeom(row['Easting'], row['Northing']), axis=1) return df

  • 連接單個數據幀中的所有數據幀

    frames = [] for i in csvtest: df = applygeom(loadcsv(i)) frames.append(df) mergedresult1 = pd.concat(frames)

在我的工作流程中,我使用 Pandas(每個 csv (15) 文件有超過 >> 2*10^6 個數據點),因此需要一段時間才能完成。 我認為這種工作流程應該利用一些並行處理(至少對於read_csvapply步驟),所以我嘗試了 dask,但我無法正確使用它。 在我的嘗試中,我沒有在速度上獲得任何改進。

我制作了一個簡單的筆記本,以便復制我正在做的事情:

https://gist.github.com/epifanio/72a48ca970a4291b293851ad29eadb50

我的問題是......使用 dask 來完成我的用例的正確方法是什么?

熊貓

在 Pandas 中,我會使用 apply 方法

In [1]: import pandas as pd

In [2]: df = pd.DataFrame({'a': [1, 2, 3], 'b': [3, 2, 1]})

In [3]: def makegeom(row):
   ...:      a, b = row
   ...:      return 'Point(%s %s)' % (a, b)
   ...: 

In [4]: df.apply(makegeom, axis=1)
Out[4]: 
0    Point(1 3)
1    Point(2 2)
2    Point(3 1)
dtype: object

Dask.dataframe

在 dask.dataframe 你可以做同樣的事情

In [5]: import dask.dataframe as dd

In [6]: ddf = dd.from_pandas(df, npartitions=2)

In [7]: ddf.apply(makegeom, axis=1).compute()
Out[7]: 
0    Point(1 3)
1    Point(2 2)
2    Point(3 1)

添加新系列

在任何一種情況下,您都可以將新系列添加到數據框中

df['geom'] = df[['a', 'b']].apply(makegeom)

創建

如果您有 CSV 數據,那么我將使用 dask.dataframe.read_csv 函數

ddf = dd.read_csv('filenames.*.csv')

如果您有其他類型的數據,那么我會使用dask.delayed

與此同時,我發現了其他方法(Dask 的替代方法),在我看來相對更容易,可以在 Pandas 數據幀上並行執行函數func 在這兩種情況下,我都利用了numpy.array_split方法。

一個使用 python multiprocessing.Poolnumpy.array_splitpandas.concat的組合,並將以這種方式工作:

import numpy as np

def func(array):
    # do some computation on the given array
    pass

def parallelize_dataframe(df, func, n_cores=72):
    df_split = np.array_split(df, n_cores)
    pool = Pool(n_cores)
    df = pd.concat(pool.map(func, df_split))
    pool.close()
    pool.join()
    return df

另一種方法是使用強大但簡單的ray集群(如果您可以在多台機器上運行代碼,這將非常有用):

# connect to a ray cluster
# 

import ray

ray.init(address="auto", redis_password="5241590000000000")

import numpy as np


@ray.remote
def func(df):
    # do some computation on the given dataframe
    pass

df_split = np.array_split(df, 288)
result = pd.concat(ray.get([func.remote(i) for i in df_split]))

上面的方法對於簡單的方法func工作得很好,其中可以使用 numpy 進行計算,並且返回的產品可以連接回parmap.map數據框 - 對於進行更簡單的文件操作的方法,我還發現了有用的parmap.map - 但這對於這個 SO 問題來說是題外話。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM