全部文章

将分组ID转换为分类编码

场景说明:例如我们在处理游戏数据的时候,经常会有“队伍ID”,“每局游戏ID”等等这些“分组ID”特征,这些ID有两个特点:

  1. 存在大量重复
  2. 字符串类型(object类型),长度一般很长(比较占内存)

下面以《绝地求生》游戏数据为例,讲解分组ID数据的处理办法:

# 导入数据基本处理阶段需要用到的api
import pandas as pd
import numpy as np
data = pd.read_csv(r'D:\learn\000人工智能数据大全\黑马数据\机器学习\pubg(竞赛)参考模型绝地求生案例\data\train_V2.csv')
data.head()
  Id groupId matchId assists boosts damageDealt DBNOs headshotKills heals killPlace ... revives rideDistance roadKills swimDistance teamKills vehicleDestroys walkDistance weaponsAcquired winPoints winPlacePerc
0 7f96b2f878858a 4d4b580de459be a10357fd1a4a91 0 0 0.00 0 0 0 60 ... 0 0.0000 0 0.00 0 0 244.80 1 1466 0.4444
1 eef90569b9d03c 684d5656442f9e aeb375fc57110c 0 0 91.47 0 0 0 57 ... 0 0.0045 0 11.04 0 0 1434.00 5 0 0.6400
2 1eaf90ac73de72 6a4a42c3245a74 110163d8bb94ae 1 0 68.00 0 0 0 47 ... 0 0.0000 0 0.00 0 0 161.80 2 0 0.7755
3 4616d365dd2853 a930a9c79cd721 f1f1f4ef412d7e 0 0 32.90 0 0 0 75 ... 0 0.0000 0 0.00 0 0 202.70 3 0 0.1667
4 315c96c26c9aac de04010b3458dd 6dc8ff871e21e6 0 0 100.00 0 0 0 45 ... 0 0.0000 0 0.00 0 0 49.75 2 0 0.1875
data.groupby('matchId')['matchId'].count()
matchId
0000a43bce5eec     95
0000eb01ea6cdd     98
0002912fe5ed71     95
0003b92987589e    100
0006eb8c17708d     93
                 ... 
fffd74b5150cb4     97
fffe53015be300     97
fffe562611d981     94
fffe721f841f85     97
fffe92232706aa     93
Name: matchId, Length: 47964, dtype: int64

例如上面的groupId,matchId这类型数据,虽然也是类别型数据。但是它们的数据量特别多,从上面的分组聚合数据可以看出,一共有47964个ID,每个ID对应90~100条数据,如果你使用one-hot编码,无异于自杀。

但是如果不处理的话,模型训练时会占用较多内存空间。

在这儿我们​groupIdmatchId列转换为数值化的类别编码​​,这是分类特征预处理的核心步骤:并且不影响我们正常使用。

# 转换groupId
data['groupId'] = data['groupId'].astype('category')  # 转换为分类类型
data["groupId_cat"] = data["groupId"].cat.codes      # 生成数值编码列

# 转换matchId
data['matchId'] = data['matchId'].astype('category')
data['matchId_cat'] = data['matchId'].cat.codes

# 查看新产生列
data[['groupId_cat', 'matchId_cat']].head()

 

  groupId_cat matchId_cat
0 613591 30085
1 827580 32751
2 843271 3143
3 1340070 45260
4 1757334 20531

 

🎯 逐步解析:

1. ​​转换为分类类型 (astype('category'))​

data['groupId'] = data['groupId'].astype('category')
 作用​​:将原始的groupId(可能是字符串、数字等类型)转换为Pandas的​​分类数据类型 (Categorical)​
  • ​内部机制​​:
    • 自动提取所有唯一的分组ID作为"类别"
    • 建立原始值 → 类别索引的映射表
    • ​例如​​:将['Alpha','Beta','Alpha','Gamma']转换成3个类别的分类数据

2. ​​生成数值编码列 (.cat.codes)

data["groupId_cat"] = data["groupId"].cat.codes
  • 作用​​:基于分类类型创建对应的​​整数编码列​
  • ​编码规则​​:
    • 每个唯一groupId分配一个唯一整数
    • 编码从0开始连续分配(0, 1, 2,...)
    • ​例如​​:
'Alpha'  → 0
'Beta'   → 1
'Gamma'  → 2

📊 原始数据 vs 转换后数据示例:

原始 groupId groupId (分类类型) groupId_cat (编码)
"Alpha" "Alpha" 0
"Beta" "Beta" 1
"Alpha" "Alpha" 0
"Gamma" "Gamma" 2

✅ 关键意义与优势:

  1. ​内存优化​

    • 分类类型平均​​减少内存占用60-90%​​(用整数索引代替原始值)
    • 尤其当groupID是长字符串时效果显著
  2. ​提速利器​

    • 分组操作提速3-10倍(如groupby,pivot_table等)
    • 机器学习训练速度显著提升(算法更擅长处理数值数据)
  3. ​数据分析友好

# 统计分析更高效
data.groupby('groupId_cat')['kills'].mean()
  1. ​模型兼容性​

    • 机器学习模型要求数值输入(SVM、神经网络等)
    • 避免字符串导致的模型错误或崩溃
  2. ​保持数据关联​

    • 原始列保留(用于展示)
    • 数值编码列独立存储(用于计算)

⚠️ 注意事项:

  1. ​顺序依赖​
    编码顺序按首字母排序(sorted(groupId.unique())
    如需特定顺序需提前声明:

data['groupId'] = pd.Categorical(
    data['groupId'], 
    categories=['custom','order','here']
)
  1. ​新增组处理​
    新增未定义的groupId会被识别为缺失值(NaN)
    可用add_categories()动态扩展

  2. ​可逆性​
    原始值可通过映射还原:

# 查看编码映射表
mapping = dict(enumerate(data['groupId'].cat.categories))
# {0: 'Alpha', 1: 'Beta', 2: 'Gamma'}

🌟 应用场景推荐:

​游戏数据分析

# 计算每组的击杀均值(毫秒级完成)
data.groupby('groupId_cat')['kills'].mean()

​机器学习特征工程 

# 直接作为模型输入特征
from sklearn.ensemble import RandomForestClassifier
model = RandomForestClassifier()
model.fit(data[['groupId_cat']], data['win'])

 高效数据存储

# 内存占用对比
print(f"原始列: {data['groupId'].nbytes/1e6:.2f} MB")
print(f"编码列: {data['groupId_cat'].nbytes/1e6:.2f} MB")

📊 ​​内存优化案例​​:当有100万行5000个唯一groupID时

  • 字符串列:约100MB
  • 分类编码:约1MB(节省99%内存)

 

posted @ 2025-06-23 10:48  指尖下的世界  阅读(19)  评论(0)    收藏  举报