[英]Convert Row values of a column into multiple columns by value count with Dask Dataframe
使用 pandas 庫,可以非常快速地執行此操作。
import pandas as pd
import dask.dataframe as dd
df = pd.DataFrame(columns=['name','contry','pet'],
data=[['paul', 'eua', 'cat'],
['pedro', 'brazil', 'dog'],
['paul', 'england', 'cat'],
['paul', 'england', 'cat'],
['paul', 'england', 'dog']])
def pre_transform(data):
return (data
.groupby(['name', 'country'])['pet']
.value_counts()
.unstack()
.reset_index()
.fillna(0)
.rename_axis([None], axis=1)
)
pre_transform(df_exp)
輸出:
| | name | country | cat | dog |
|---|-------|---------|-----|-----|
| 0 | paul | england | 2.0 | 1.0 |
| 1 | paul | eua | 1.0 | 0.0 |
| 2 | pedro | brazil | 0.0 | 1.0 |
但是要在數百 gb 的數據集中應用此操作,沒有 RAM 來使用 Pandas 執行此操作。
一種姑息的替代方法是在讀取數據時通過帶有 chunksize 參數的迭代來使用 pandas。
concat_df = pd.DataFrame()
for chunk in pd.read_csv(path_big_file, chunksize=1_000_000):
concat_df = pd.concat([concat_df, pre_transform(chunk)])
merged_df = concat_df.reset_index(drop=True).groupby(['name', 'country']).sum().reset_index()
display(merged_df)
但為了提高效率,我嘗試用 Dask 庫復制相同的操作。
我的努力使我產生了下面的功能,盡管達到了相同的結果,但在處理時間上效率非常低。
Bad Dask 方法:
def pivot_multi_index(ddf, index_columns, pivot_column):
def get_serie_multi_index(data):
return data.apply(lambda x:"_".join(x[index_columns].astype(str)), axis=1,meta=("str")).astype('category').cat.as_known()
return (dd
.merge(
(ddf[index_columns]
.assign(FK=(lambda x:get_serie_multi_index(x)))
.drop_duplicates()),
(ddf
.assign(FK=(lambda x:get_serie_multi_index(x)))
.assign(**{pivot_column:lambda x: x[pivot_column].astype('category').cat.as_known(),
f'{pivot_column}2':lambda x:x[pivot_column]})
.pivot_table(index='FK', columns=pivot_column, values=f'{pivot_column}2', aggfunc='count')
.reset_index()),
on='FK', how='left')
.drop(['FK'], axis=1)
)
ddf = dd.from_pandas(df_exp, npartitions=3)
index_columns = ['name','country']
pivot_column = 'pet'
merged = pivot_multi_index(ddf, index_columns, pivot_column)
merged.compute()
輸出
| | name | country | cat | dog |
|---|-------|---------|-----|-----|
| 0 | paul | eua | 1.0 | 0.0 |
| 1 | pedro | brazil | 0.0 | 1.0 |
| 2 | paul | england | 2.0 | 1.0 |
但是通過將上述函數應用於大型數據集,運行起來比通過塊大小迭代使用 pandas 慢得多。
問題仍然存在:
鑒於按值計數將一列的行值轉換為多列的操作,使用 Dask 庫實現此目標的最有效方法是什么?
我以前遇到過類似的問題,但我主要關心的是保持擴展的潛力,同時還能在內存不足的情況下工作,而不是在測試期間占用我的 RAM。 在您的情況下,最直接的方法可能是使用 dask 讀取您的數據並將其縮小到一定大小。 然后使用 pandas 操作較小的咬合,同時將其轉儲回 dask 以釋放內存並繼續。 您可以將循環推入一個在組上迭代的 dask apply 函數,但您仍然可以使用非常方便的value_counts()
和unstack()
函數。
import pandas as pd
from dask import dataframe as dd
df = pd.DataFrame(columns=['name','country','pet'],
data=[['paul', 'eua', 'cat'],
['pedro', 'brazil', 'dog'],
['paul', 'england', 'cat'],
['paul', 'england', 'cat'],
['paul', 'england', 'dog']])
#obv read your big data into dask here instead of from_pandas
ddf = dd.from_pandas(df, chunksize=1)
#pull some minimal data in to build some grouper keys
unique = ddf[['name','country']].drop_duplicates().compute()
group_keys = list(zip(unique.name, unique.country))
#out of memory groupby object
groups = ddf.groupby(['name','country'])
#init an empty dask dataframe for concat
ddf_all = dd.from_pandas(pd.DataFrame(), chunksize=1)
#loop each group, pull into memory to manipulate
for each in group_keys:
df = groups.get_group(each).compute()
df = df.value_counts().unstack().reset_index()
#concat back out to release memory
ddf = dd.from_pandas(df, chunksize=1)
ddf_all = dd.concat([ddf_all, ddf])
#do some more manipulation if necessary, then compute
ddf_all.fillna(0).compute()
| | name | country | cat | dog |
|---:|:-------|:----------|------:|------:|
| 0 | paul | eua | 1 | 0 |
| 0 | pedro | brazil | 0 | 1 |
| 0 | paul | england | 2 | 1 |
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.