Python:合并低频因子/类别计数

11

有一个在 R 中的很好的解决方案

我的 df.column 看起来像:

Windows
Windows
Mac
Mac
Mac
Linux
Windows
...
我希望在这个 df.column 向量中用“其他”替换低频类别。例如,我需要我的 df.column 看起来像这样
Windows
Windows
Mac
Mac
Mac
Linux -> Other
Windows
...

我想要重新命名这些稀有类别,以减少回归中的因素数量。这就是为什么我需要原始向量。在Python中,运行获取频率表的命令后,我得到了:

pd.value_counts(df.column)


Windows          26083
iOS              19711
Android          13077
Macintosh         5799
Chrome OS          347
Linux              285
Windows Phone      167
(not set)           22
BlackBerry          11

我想知道是否有一种方法可以将“Chrome OS”、“Linux”(低频数据)重命名为另一个类别(例如“其他”类别),并且以高效的方式实现。


如何在这里定义低频数据的术语。您的意思是小于400吗? - Bharath M Shetty
你想做什么?你从哪里获取因素/频率? - mrCarnivore
从总和阈值到任何给定值都可以。以百分比表示的值会更加健壮。 - GRS
@mrCarnivore 我正在尝试将所有 Macintosh 下的类别合并为一个名为“其他”的类别。 - GRS
请告诉我们您的阈值。这是问题的一个重要部分。 - mrCarnivore
我假设阈值可以调整,因为它是一个常数,但400/65k略小于1%。 - GRS
2个回答

24

通过找到占用百分比进行口罩着装:

series = pd.value_counts(df.column)
mask = (series/series.sum() * 100).lt(1)
# To replace df['column'] use np.where I.e 
df['column'] = np.where(df['column'].isin(series[mask].index),'Other',df['column'])

将索引更改为总和:

new = series[~mask]
new['Other'] = series[mask].sum()

Windows      26083
iOS          19711
Android      13077
Macintosh     5799
Other          832
Name: 1, dtype: int64

如果你想替换索引:

series.index = np.where(series.index.isin(series[mask].index),'Other',series.index)

Windows      26083
iOS          19711
Android      13077
Macintosh     5799
Other          347
Other          285
Other          167
Other           22
Other           11
Name: 1, dtype: int64

说明

(series/series.sum() * 100) # This will give you the percentage i.e 

Windows          39.820158
iOS              30.092211
Android          19.964276
Macintosh         8.853165
Chrome OS         0.529755
Linux             0.435101
Windows Phone     0.254954
(not set)         0.033587
BlackBerry        0.016793
Name: 1, dtype: float64

.lt(1) 相当于小于1。这将为您提供一个基于该掩码的布尔掩码,然后可以使用该掩码索引并分配数据


1
谢谢,但这只会改变表格的输出,而不会改变列本身。我想遍历df.column中的每个值,并重新分配低频类别为其他值。 - GRS
1
创建一个字典并将其替换回去。 - BENY
1
@Bharath 谢谢你,但我想在原始向量中替换它们,而不是在频率表中。频率表是从向量数据中获取的。(我在问题中展示了向量的样子) - GRS
@Bharath 这仅更改了频率表,我想改变数据框列。请查看我的编辑,我详细说明了它。 - GRS
你在更新后没有从头开始阅读答案。我已经发布了那个答案。代码的第三行是你需要的。 - Bharath M Shetty
显示剩余2条评论

7
这是对你问题的(迟到)补充;它应用了将低频类别(比例小于min_freq)合并到整个数据框的列中的理论。它基于@Bharath的回答。
def condense_category(col, min_freq=0.01, new_name='other'):
    series = pd.value_counts(col)
    mask = (series/series.sum()).lt(min_freq)
    return pd.Series(np.where(col.isin(series[mask].index), new_name, col))

一个简单的应用实例:

df_toy = pd.DataFrame({'x': [1, 2, 3, 4] + [5]*100, 'y': [5, 6, 7, 8] + [0]*100})
df_toy = df_toy.apply(condense_category, axis=0)
print(df_toy)

#          x      y
# 0    other  other
# 1    other  other
# 2    other  other
# 3    other  other
# 4        5      0
# ..     ...    ...
# 99       5      0
# 100      5      0
# 101      5      0
# 102      5      0
# 103      5      0
# 
# [104 rows x 2 columns]

我是一个新手,我像这样使用您的函数:df['server_type_'] = df['server_type'].apply(condense_category),但它报错了:'str' object has no attribute 'isin',您能给予一些建议吗? - 罗文浩
我的函数使用了 .apply 方法处理 pandas DataFrame,而你却在一个 pandas Series 上使用它。我建议你查看上面的答案,该答案是针对 Series 而非 DataFrame 进行这个过程的。 - Ric S
谢谢,那是我的疏忽,再次感谢您的回答。 - 罗文浩

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接