Pandas技巧:利用 category 类型节省内存

我们用最通俗易懂的方式,向初学者讲清楚:


🎯 Pandas 的 category 数据类型:为什么用?怎么用?如何节省内存?


🧩 一、什么是 category 类型?

Pandas 的 category 是一种专门为"重复文本"设计的数据类型

👉 想象你有一个"城市"列,里面只有:北京、上海、广州、深圳,但重复了 100 万行。

  • 默认是 object 类型(本质是字符串),每一行都存完整字符串 → 很占内存!
  • 如果转成 category,Pandas 只存一次"北京、上海、广州、深圳",然后每行只存一个数字编号(比如 0,1,2,3)→ 内存暴降!

💾 二、为什么 category 能省内存?

🆚 对比:object vs category

假设我们有这样一列:

python 复制代码
import pandas as pd

cities = ['北京', '上海', '广州', '深圳'] * 250000  # 总共 100 万行
df = pd.DataFrame({'city': cities})

✅ 查看内存占用:

python 复制代码
print(df['city'].memory_usage(deep=True))  # 单位:字节
默认 object 类型 → ❌ 占用约 48MB
python 复制代码
df['city'].dtype  # dtype('O') → object
转成 category → ✅ 占用约 1MB
python 复制代码
df['city'] = df['city'].astype('category')
print(df['city'].memory_usage(deep=True))  # 瞬间降到 1MB 左右!

💡 节省了 98% 的内存!


📊 三、category 是怎么做到的?

它内部用了两个结构:

  1. categories(字典) :存储所有不重复的值 → ['北京', '上海', '广州', '深圳']
  2. codes(编码) :每一行存的是这个值在字典中的索引 → [0, 1, 2, 3, 0, 1, ...]

📌 就像把"北京"压缩成"0","上海"压缩成"1",以此类推。


✅ 四、什么时候该用 category?

记住这个口诀:

🔁 值少、重复多 → 用 category!

典型场景:

  • 性别:男 / 女
  • 省份、城市、国家
  • 产品类别:手机、电脑、家电
  • 订单状态:待支付、已发货、已完成
  • 星级评分:1星、2星、3星、4星、5星

⚠️ 不适合的场景:

  • 每行都是唯一的值(如用户ID、姓名、地址)
  • 值非常多(比如 > 50% 不重复),反而可能更占内存!

🛠️ 五、怎么转换成 category?

方法1:创建时指定

python 复制代码
df = pd.DataFrame({
    'city': pd.Categorical(['北京', '上海', '北京', '广州'])
})

方法2:事后转换(最常用)

python 复制代码
df['city'] = df['city'].astype('category')

方法3:批量转换(适合多列)

python 复制代码
cat_cols = ['city', 'gender', 'status']
df[cat_cols] = df[cat_cols].astype('category')

🧪 六、实际内存对比演示

我们来跑个真实例子:

python 复制代码
import pandas as pd
import numpy as np

# 生成 100 万行数据
np.random.seed(42)
cities = np.random.choice(['北京', '上海', '广州', '深圳', '杭州'], size=1000000)
df = pd.DataFrame({'city': cities})

# 查看 object 类型内存
mem_before = df['city'].memory_usage(deep=True)
print(f"object 类型内存: {mem_before / 1024**2:.2f} MB")

# 转成 category
df['city'] = df['city'].astype('category')

# 查看 category 类型内存
mem_after = df['city'].memory_usage(deep=True)
print(f"category 类型内存: {mem_after / 1024**2:.2f} MB")

# 节省比例
print(f"节省了: {100 * (1 - mem_after / mem_before):.1f}%")

✅ 输出示例:

csharp 复制代码
object 类型内存: 47.68 MB
category 类型内存: 1.00 MB
节省了: 97.9%

🚀 七、额外好处:不止省内存!

除了节省内存,category 还有这些优势:

优势 说明
计算更快 排序、分组、去重等操作更快(因为内部是数字编码)
📈 排序可控 可以自定义顺序,比如:['低', '中', '高'],而不是按字母排序
🧮 统计友好 .value_counts() 更快更准
🖥️ 节省磁盘空间 保存为 parquet/feather 时体积更小

🎨 八、自定义排序(bonus!)

默认 category 是按字母排序,但你可以指定顺序:

python 复制代码
from pandas.api.types import CategoricalDtype

# 定义有序 category
size_order = CategoricalDtype(['小', '中', '大'], ordered=True)
df['size'] = df['size'].astype(size_order)

# 现在可以正确排序:
df.sort_values('size')  # 小 → 中 → 大,而不是 中→大→小(按拼音)

📌 九、初学者常见误区

❌ 误区1:所有文本列都转 category

→ 不!如果每行都不同(如"用户评论"),转 category 会更占内存!

❌ 误区2:转了 category 不能改值

→ 可以改!但新增"没见过的值"会变成 NaN,需手动添加:

python 复制代码
df['city'] = df['city'].cat.add_categories(['成都'])
df.loc[0, 'city'] = '成都'  # 现在可以了

❌ 误区3:category 是字符串

→ 不是!它是独立类型,不能直接做字符串操作(如 .str.upper()),需要先 .astype(str)


✅ 十、总结:一张表记住 category

项目 说明
适用场景 重复文本、枚举值、分类变量
核心原理 存字典 + 存编号,避免重复存储字符串
节省内存 重复越多,省得越多(可达 90%+)
转换方法 .astype('category')
额外优势 运算快、排序可控、统计高效
注意事项 不适合唯一值多的列;新增值要手动添加

💡 终极建议

下次你看到一列文本数据,先问自己:

"这列有多少种不同的值?" "是不是大量重复?"

如果是 → 立刻 .astype('category'),内存和性能双提升!


🎯 现在你已经完全掌握 Pandas 的 category 类型了!快去优化你的数据集吧!

相关推荐
跟橙姐学代码3 小时前
Python时间处理秘籍:别再让日期时间卡住你的代码了!
前端·python·ipython
mortimer4 小时前
Python 文件上传:一个简单却易犯的错误及解决方案
人工智能·python
Juchecar5 小时前
NumPy编程:鼓励避免 for 循环
python
Java陈序员6 小时前
直播录制神器!一款多平台直播流自动录制客户端!
python·docker·ffmpeg
c8i6 小时前
drf 在django中的配置
python·django
这里有鱼汤8 小时前
【花姐小课堂】新手也能秒懂!用「风险平价」打造扛造的投资组合
后端·python
databook21 小时前
Manim实现闪光轨迹特效
后端·python·动效
Juchecar1 天前
解惑:NumPy 中 ndarray.ndim 到底是什么?
python
用户8356290780511 天前
Python 删除 Excel 工作表中的空白行列
后端·python