如果要计数的值在另一个(以更快的方式)中,如何计算一个熊猫数据框中值的出现?

Posted

技术标签:

【中文标题】如果要计数的值在另一个(以更快的方式)中,如何计算一个熊猫数据框中值的出现?【英文标题】:How to count the occurrence of values in one pandas Dataframe if the values to count are in another (in a faster way)? 【发布时间】:2020-09-23 19:59:25 【问题描述】:

我有一个(非常大的)pandas Dataframe df

country  age  gender
Brazil    10     F
USA       20     F 
Brazil    10     F
USA       20     M
Brazil    10     M
USA       20     M

我有另一个熊猫数据框freq

 age  gender  counting
  10       F         0
  10       M         0
  20       F         0

我想计算 freq 中出现在 df 中的一对值:

 age  gender  counting
  10       F         2
  10       M         1
  20       F         1

我正在使用此代码,但它需要的时间太长:

for row in df.itertuples(index=False):
   freq.loc[np.all(freq['age','gender']==row[2:3],axis=1),'counting'] += 1

有更快的方法吗?

请注意:

我必须使用 freq,因为并非所有组合(例如 20M)都是需要的 df 中的某些列可能无法使用 counting 计算两个值在每行中出现的次数 freq 可能有超过 2 个值需要检查(这只是一个小例子)

【问题讨论】:

【参考方案1】:

您可以使用内部 merge 过滤您不想要的 df 中的组合,然后使用 groupby 年龄和性别以及 count 列计数。只需 reset_index 以适应您的预期输出。

freq = (df.merge(freq, on=['age', 'gender'], how='inner')
          .groupby(['age','gender'])['counting'].size()
          .reset_index())
print (freq)
   age gender  counting
0   10      F         2
1   10      M         1
2   20      F         1

根据您不想要的组合数量,在执行merge 之前,在df 上使用groupby 可能会更快:

freq = (df.groupby(['age','gender']).size()
          .rename('counting').reset_index()
          .merge(freq[['age','gender']])
       )

【讨论】:

【参考方案2】:

NumPy 加入了一些性能的组合(希望如此!),将维度减少到1D,这样我们就可以引入高效的bincount -

agec = np.r_[df.age,freq.age]
genderc = np.r_[df.gender,freq.gender]
aIDs,aU = pd.factorize(agec)
gIDs,gU = pd.factorize(genderc)
cIDs = aIDs*(gIDs.max()+1) + gIDs
count = np.bincount(cIDs[:len(df)], minlength=cIDs.max()+1)
freq['counting'] = count[cIDs[-len(freq):]]

示例运行 -

In [44]: df
Out[44]: 
  country  age gender
0  Brazil   10      F
1     USA   20      F
2  Brazil   10      F
3     USA   20      M
4  Brazil   10      M
5     USA   20      M

In [45]: freq # introduced a missing element as the second row for variety
Out[45]: 
   age gender  counting
0   10      F         2
1   23      M         0
2   20      F         1

具体场景优化#1

如果已知age 标头仅包含整数,我们可以跳过一个factorize。所以,跳过aIDs,aU = pd.factorize(agec) 并计算cIDs 而不是 -

cIDs = agec*(gIDs.max()+1) + gIDs

【讨论】:

【参考方案3】:

另一种方法是使用reindex 过滤到频率列表:

df.groupby(['gender', 'age']).count()\
  .reindex(pd.MultiIndex.from_arrays([df1['gender'], df1['age']]))

输出:

            country
gender age         
F      10         2
M      10         1
F      20         1

【讨论】:

以上是关于如果要计数的值在另一个(以更快的方式)中,如何计算一个熊猫数据框中值的出现?的主要内容,如果未能解决你的问题,请参考以下文章

我的变量的值在另一个文件中发生变化

如何在分配的空间中存储以 ASCII 转换的计数器寄存器中包含的值

如何判断一个List里面的值在另一个List中?

如何使循环计算更快

排序之计数排序

选择一列上的值在另一列上具有相同的一组值