使用项目计数进行高效分组

时间:2018-03-02 23:48:39

标签: python pandas

以下是我的数据集的样子:

Name | Country
---------------
Alex | USA
Tony | DEU
Alex | GBR
Alex | USA

我试图得到这样的东西,基本上是分组和计数:

Name | Country
---------------
Alex | {USA:2,GBR:1}
Tony | {DEU:1}

正常工作,但LARGE数据集速度慢

这是我的代码,它可以在较小的dfs上运行,但需要永久使用更大的dfs(我的代码大约为1400万行)。我也使用多处理模块加速,但它没有多大帮助:

def countNames(x):
    return dict(Counter(x))

def aggregate(df_full,nameList):
    df_list = []
    for q in nameList:
        df = df_full[df_full['Name']==q]
        df_list.append(df.groupby('Name')['Country'].apply(lambda x: str(countNames(x))).to_frame().reset_index()) 
    return pd.concat(df_list)

df = pd.DataFrame({'Name':['Alex','Tony','Alex','Alex'], 
                'Country':['USA','GBR','USA','DEU']})[['Name','Country']]

aggregate(df,df.Name.unique())

有没有什么可以加速内部逻辑(除了运行多处理)?

2 个答案:

答案 0 :(得分:3)

这实际上是一个交叉表。你说“像这样的东西”意味着你不太确定输出应该是什么。

选项1
分组依据和value_counts

df.groupby('Name').Country.value_counts()

Name  Country
Alex  USA        2
      GBR        1
Tony  DEU        1
Name: Country, dtype: int64

获取指定的输出:

pd.Series({
    name: pd.value_counts(d).to_dict()
    for name, d in df.groupby('Name').Country
}).rename_axis('Name').reset_index(name='Country')

   Name               Country
0  Alex  {'USA': 2, 'GBR': 1}
1  Tony            {'DEU': 1}

选项2
但是,我更喜欢这些陈述。我们可以在the answer to question # 9 in this answer

中看到多种方法
pd.crosstab(df.Name, df.Country)

Country  DEU  GBR  USA
Name                  
Alex       0    1    2
Tony       1    0    0

答案 1 :(得分:0)

对于O( n )复杂度解决方案,请使用ios-snapshot-test-case

from collections import Counter, defaultdict
import pandas as pd

df = pd.DataFrame({'Name':['Alex','Tony','Alex','Alex'], 
                   'Country':['USA','GBR','USA','DEU']})[['Name','Country']]

c = Counter(map(tuple, df.values))

# Counter({('Alex', 'DEU'): 1, ('Alex', 'USA'): 2, ('Tony', 'GBR'): 1})

字典结果

然后你可以得到一个名字 - >通过collections.Counter进行国家字典映射。我不会将字典放在pandas数据框中,它不是为此而设计的。

tree = lambda: defaultdict(tree)
d = tree()

for k, v in c.items():
    d[k[0]][k[1]] = v

for k, v in d.items():
    print(k, v)

# Alex defaultdict(<function <lambda>>, {'USA': 2, 'DEU': 1})
# Tony defaultdict(<function <lambda>>, {'GBR': 1})

数据框结果

出于显示目的,您可以直接从defaultdict

构建数据框
res_df = pd.DataFrame.from_dict(d, orient='index').fillna(0)

#       USA  DEU  GBR
# Alex  2.0  1.0  0.0
# Tony  0.0  0.0  1.0