Large Pandas Dataframe 中一小部分值的频率

Frequency of a small subset of values in a Large Pandas Dataframe

提供了一个示例,说明如何使用 pd.get_dummies + 聚合从 pandas 数据帧中获取给定行的频率计数。但是,如果您只想从非常大的数据框中提取一小部分术语,这就无法扩展。

例如考虑同一个例子:

import pandas as pd

df = pd.DataFrame({'ID': ['xyz_1', 'xyz_2', 'xyz_3', 'xyz_4', 'xyz_400'],
                   'class1': ['yes_1', 'no_2', pd.NA, 'no_3', 'no_7'],
                   'class2': ['no_8', 'yes_15', 'yes_16', 'no_18', 'no_21'],
                   'class3': [pd.NA, 'no_51', 'yes_1', 'no_3', 'no_4'],
                   'class100': ['yes_3', 'no_5', pd.NA, 'yes_6', 'no_7']})

        ID class1  class2 class3 class100
0    xyz_1  yes_1    no_8   <NA>    yes_3
1    xyz_2   no_2  yes_15  no_51     no_5
2    xyz_3   <NA>  yes_16  yes_1     <NA>
3    xyz_4   no_3   no_18   no_3    yes_6
4  xyz_400   no_7   no_21   no_4     no_7

不是值在是和否的集合中,它们可以是许多不同的分类变量之一。如果您只想要 yes_1、no_51 的频率项,则需要进行大量额外计算。

到目前为止我找到的最佳解决方案是将其他值预处理为 NAN

set = ['yes_1', 'no_51']
df[~df.isin(set)] = pd.NA

     ID class1 class2 class3 class100
0  <NA>  yes_1   <NA>   <NA>     <NA>
1  <NA>   <NA>   <NA>  no_51     <NA>
2  <NA>   <NA>   <NA>  yes_1     <NA>
3  <NA>   <NA>   <NA>   <NA>     <NA>
4  <NA>   <NA>   <NA>   <NA>     <NA>

对于大约 100 万个条目的大型数据帧,这仍然非常慢。有没有办法更好地扩展它。

我不知道它是否比您的技术更好,但我建议将其作为测试解决方案:

(
    pd
    .melt(df,id_vars=['ID'])
    .assign(yes_1 = lambda x: np.where(x['value']=='yes_1',1,0))
    .assign(no_51 = lambda x: np.where(x['value']=='no_51',1,0))
    .sum()
)

在链接的问题中,性能更高的解决方案是:

df.apply(lambda row: row.value_counts(dropna=False), axis=1).fillna(0)

这可能已经足够满足您的需要;但是,如果您只需要几个值,则可能更快:

counts = pd.Series({(df == key).values.sum() for key in ['yes_1', 'no_51']}) 
df.set_index('ID', inplace=True)#Set ID as index
df[~df.isin(['yes_1', 'no_51'])] = np.nan#Set anything not in the set as nan
pd.get_dummies(df.stack().unstack())#get dummies from a datframe that has dropped anycolumns with NaNS

      

              class1_yes_1  class3_no_51  class3_yes_1
ID                                             
xyz_1             1             0             0
xyz_2             0             1             0
xyz_3             0             0             1