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
此
例如考虑同一个例子:
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