簡體   English   中英

從groupby返回列表的最有效方法

[英]Most efficient way to return list from a groupby

我有一個1.3億行的數據幀,這是一個示例:

    id              id2     date         value
0   33208381500016  1927637 2014-07-31   120.0
1   77874276700016  3418498 2014-11-22   10.5
2   77874276700016  1174018 2014-11-22   8.4
3   77874276700016  1174018 2014-11-20   1.4
4   77874276700016  1643839 2014-06-27   4.2
5   77874276700016  1972929 2014-06-27   6.7
6   77874276700016  1972929 2014-06-27   12.7
7   77874276700016  1588191 2014-02-20   123.4
8   77874276700016  1966627 2014-02-20   973.1
9   77874276700016  1830252 2014-02-20   0.5

我需要在此數據幀(稱為data )上執行groupby 對於簡單的groupby例如sum沒有問題:

data[['id','value']].groupby('id',as_index=False).sum()
time: 11.19s

但是現在我需要檢索另一列中的值列表(或它的長度)。 下面的代碼有效,但是需要很長時間,有沒有更有效的方法呢?

temp = data[['id','date','id2']].drop_duplicates()
temp.groupby('id',as_index = False).agg({'date': lambda x: set(x.tolist()),'id2':lambda x: len(set(x.tolist()))})
time: 159s

第一個問題:

有沒有一種更有效的方法來為每個id計算唯一id2的數量,但仍使用此groupby? 我的意思是我不想將兩個分組方式分開,因為這可能會花費更長的時間(通過2個聚合執行一個分組方式大約需要一個單一grouby的1.5倍)。

第二個問題:

有沒有更有效的方法來檢索唯一日期列表? 我知道這個問題已經解決了,但是我不能簡單地使用.apply(list)

要獲取唯一日期,請使用SeriesGroupBy.unique() 計算不重復的數量id2各組中,使用SeriesGroupBy.nunique()

temp = data[['id', 'date', 'id2']].drop_duplicates()
temp.groupby('id', as_index=False).agg({'date': 'unique', 'id2': 'nunique'})

事先不丟棄重復項可能會更快-熊貓只需要對所有數據進行一次迭代,而不是兩次。

data.groupby('id', as_index=False).agg({'date': 'unique', 'id2': 'nunique'})

編輯:

這是一些基准。 有趣的是, SeriesGroupBy.unique()SeriesGroupBy.nunique()似乎並不比使用集合快。 但之前不能刪除重復項。

import io

import pandas as pd

raw = io.StringIO("""\
id              id2     date         value
0   33208381500016  1927637 2014-07-31   120.0
1   77874276700016  3418498 2014-11-22   10.5
2   77874276700016  1174018 2014-11-22   8.4
3   77874276700016  1174018 2014-11-20   1.4
4   77874276700016  1643839 2014-06-27   4.2
5   77874276700016  1972929 2014-06-27   6.7
6   77874276700016  1972929 2014-06-27   12.7
7   77874276700016  1588191 2014-02-20   123.4
8   77874276700016  1966627 2014-02-20   973.1
9   77874276700016  1830252 2014-02-20   0.5
""")

data = pd.read_csv(raw, delim_whitespace=True)

def using_sets_drop_then_group():
    temp = data[['id', 'date', 'id2']].drop_duplicates()
    temp.groupby('id', as_index=False).agg({'date': lambda x: set(x),
                                            'id2': lambda x: len(set(x))})

def using_sets_drop_just_group():
    data.groupby('id', as_index=False).agg({'date': lambda x: set(x),
                                            'id2': lambda x: len(set(x))})

def using_unique_drop_then_group():
    temp = data[['id', 'date', 'id2']].drop_duplicates()
    temp.groupby('id', as_index=False).agg({'date': 'unique', 'id2': 'nunique'})

def using_unique_just_group():
    data.groupby('id', as_index=False).agg({'date': 'unique', 'id2': 'nunique'})

%timeit using_sets_drop_then_group()   # => 100 loops, best of 3: 4.82 ms per loop
%timeit using_sets_drop_just_group()   # => 100 loops, best of 3: 2.91 ms per loop
%timeit using_unique_drop_then_group() # => 100 loops, best of 3: 5.14 ms per loop
%timeit using_unique_just_group()      # => 100 loops, best of 3: 3.26 ms per loop

編輯:

在評論中,@ ptrj建議如果將日期轉換為datetime64 ,SeriesGroupBy.unique SeriesGroupBy.unique()SeriesGroupBy.nunique()可能會更快。 las,似乎並非如此,至少對於這種小的數據樣本而言。

data['parsed_date'] = pd.to_datetime(data['date'])

def using_sets_and_datetime64():
    data.groupby('id', as_index=False).agg({'parsed_date': lambda x: set(x),
                                            'id2': lambda x: len(set(x))})

def using_unique_and_datetime64():
    data.groupby('id', as_index=False).agg({'parsed_date': 'unique',
                                            'id2': 'nunique'})

%timeit using_sets_and_datetime64()    # => 100 loops, best of 3: 3.2 ms per loop
%timeit using_unique_and_datetime64()  # => 100 loops, best of 3: 3.53 ms per loop

編輯:

@MaxU建議串聯100,000個樣本數據的建議確實導致SeriesGroupBy.unique()SeriesGroupBy.nunique()優於set

large_data = pd.concat([data] * 10**5, ignore_index=True)

def using_sets():
    large_data.groupby('id', as_index=False).agg({'date': lambda x: set(x),
                                                  'id2': lambda x: len(set(x))})

def using_unique():
    large_data.groupby('id', as_index=False).agg({'date': 'unique',
                                                  'id2': 'nunique'})

def using_sets_and_datetime64():
    large_data.groupby('id', as_index=False).agg({'parsed_date': lambda x: set(x),
                                                  'id2': lambda x: len(set(x))})

def using_unique_and_datetime64():
    large_data.groupby('id', as_index=False).agg({'parsed_date': 'unique',
                                                  'id2': 'nunique'})

%timeit using_sets()                   # => 1 loops, best of 3: 295 ms per loop
%timeit using_unique()                 # => 1 loops, best of 3: 327 ms per loop
%timeit using_sets_and_datetime64()    # => 1 loops, best of 3: 5.02 s per loop
%timeit using_unique_and_datetime64()  # => 1 loops, best of 3: 248 ms per loop

暫無
暫無

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

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