以下是我的数据集的样子:
Name | Country
---------------
Alex | USA
Tony | DEU
Alex | GBR
Alex | USA
我试图得到这样的东西,基本上是分组和计数:
Name | Country
---------------
Alex | {USA:2,GBR:1}
Tony | {DEU:1}
这是我的代码,它可以在较小的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())
有没有什么可以加速内部逻辑(除了运行多处理)?
答案 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