用类别替换频率较低的标签



我有一个很长的数据框架,包含数字列和分类列。

id       dur    proto       state   att_cat
0   1   0.121460    tcp         FIN     Normal
1   2   0.649902    tcp         FIN     Normal
2   3   1.623047    tcp         FIN     Normal
3   4   1.681641    tcp         FIN     Normal
4   5   0.449463    tcp         CON     Normal
5   6   0.000009    udp         INT     Generic
6   7   0.505859    udp         CON     Normal
7   8   0.000009    udp         INT     Generic
8   9   0.000009    udp         INT     Generic
9   10  0.000009    tcp         INT     Generic
10  11  0.222761    unas        ECO     Normal
11  12  1.461278    tcp         CON     Normal
12  13  1.065289    arp         FIN     Normal
13  14  2.782646    udp         CON     Normal
14  15  1.457923    tcp         FIN     Normal
15  16  0.000009    udp         INT     Generic
17  18  0.125550    arp         INT     Generic
18  19  0.000009    tcp         INT     Generic
19  20  0.000009    tcp         CON     Generic

在att_cat列中,我要对不同的标签进行分组。当我这样做时,然后我观察到,例如,列proto有一些标签比其他标签出现得更频繁,例如,对于att_cat=Normal, tcp比udp和其他更频繁(不显示在数据框中);对于Generic,最常见的是udp。

我想,对于att_cat中的每个标签,在proto(或任何分类列)中保留n更频繁的标签,其余的,用'att_cat_proto'代替。

例如,对于特性proto:

Normal = {tcp: 7, udp: 2, arp: 1, unas: 1}
Generic = {udp: 4, tcp: 3, arp: 1, unas: 0}

对于特性'state'

Normal = {FIN: 5, CON: 4, INT: 1, ECO: 1}
Generic = {INT: 6, CON: 1, FIN: 1, ECO: 0}
如果我将proto特性的Normal和Generic的n=2Normal的n=2Generic的n=1

固定为,那么期望的结果应该是:

id       dur    proto          state            att_cat
0   1   0.121460    tcp            FIN              Normal
1   2   0.649902    tcp            FIN              Normal
2   3   1.623047    tcp            FIN              Normal
3   4   1.681641    tcp            Normal_State     Normal
4   5   0.449463    tcp            CON              Normal
5   6   0.000009    udp            INT              Generic
6   7   0.505859    udp            CON              Normal
7   8   0.000009    udp            INT              Generic
8   9   0.000009    udp            INT              Generic
9   10  0.000009    tcp            Generic_State    Generic
10  11  0.222761    Normal_Proto   Normal_State     Normal
11  12  1.461278    tcp            CON              Normal
12  13  1.065289    Normal_Proto   FIN              Normal
13  14  2.782646    udp            CON              Normal
14  15  1.457923    tcp            FIN              Normal
15  16  0.000009    udp            INT              Generic
17  18  0.125550    Generic_Proto  INT              Generic
18  19  0.000009    tcp            INT              Generic
19  20  0.000009    tcp            Generic_State    Generic

到目前为止,我已经尝试了如下操作:

def rare_labels(df,target,cat_var,n):
df = df.copy()
# Selects the low frequency labels
cat_frame = df[cat_var]
most_freq = cat_frame.value_counts().index[:n].to_list()
less_freq = np.setdiff1d(cat_frame.unique(),most_freq)
# Substitute the low frequency labels by a common label
df[cat_var] = df.groupby(target).******* 
# Returns the dataframe
return df

但是我被分配的部分卡住了。

在执行大量操作时,有一种方便的处理groupby赋值的方法。尽管apply类似于一个基本循环,但对于groupby,它只对每个组(在本例中为2 "Generic")和"Normal"),而不是每行

修正了变量n.的问题(一开始没有发现)

import pandas as pd 
import numpy as np
def renamer(grp, restrictions):
cat = grp.att_cat.iloc[0]
for column in ["proto", "state"]:
n = restrictions.loc[cat, column]
unique_labels = grp[column].unique()
value_count = grp[column].value_counts()
most_freq = value_count.index[:n].to_list()
least_freq = np.setdiff1d(unique_labels, most_freq)
mask = np.zeros(len(grp), dtype=bool)
for label in least_freq:
mask |= (grp[column] == label)
grp[column][mask] = f"{cat}_{column}"
return grp
restrictions = {
"proto": [2, 2],
"state": [2, 1]
}
restrictions = pd.DataFrame(restrictions, index=["Normal", "Generic"])
df = pd.read_csv("data.csv")
df.groupby('att_cat').apply(renamer, restrictions).to_markdown()

输出:

|    |   id |      dur | proto         | state         | att_cat   |
|---:|-----:|---------:|:--------------|:--------------|:----------|
|  0 |    1 | 0.12146  | tcp           | FIN           | Normal    |
|  1 |    2 | 0.649902 | tcp           | FIN           | Normal    |
|  2 |    3 | 1.62305  | tcp           | FIN           | Normal    |
|  3 |    4 | 1.68164  | tcp           | Normal_state  | Normal    |
|  4 |    5 | 0.449463 | tcp           | CON           | Normal    |
|  5 |    6 | 9e-06    | udp           | INT           | Generic   |
|  6 |    7 | 0.505859 | udp           | CON           | Normal    |
|  7 |    8 | 9e-06    | udp           | INT           | Generic   |
|  8 |    9 | 9e-06    | udp           | INT           | Generic   |
|  9 |   10 | 9e-06    | tcp           | Generic_state | Generic   |
| 10 |   11 | 0.222761 | Normal_proto  | Normal_state  | Normal    |
| 11 |   12 | 1.46128  | tcp           | CON           | Normal    |
| 12 |   13 | 1.06529  | Normal_proto  | FIN           | Normal    |
| 13 |   14 | 2.78265  | udp           | CON           | Normal    |
| 14 |   15 | 1.45792  | tcp           | FIN           | Normal    |
| 15 |   16 | 9e-06    | udp           | INT           | Generic   |
| 16 |   18 | 0.12555  | Generic_proto | INT           | Generic   |
| 17 |   19 | 9e-06    | tcp           | INT           | Generic   |
| 18 |   20 | 9e-06    | tcp           | Generic_state | Generic   |

相关内容

  • 没有找到相关文章

最新更新