0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

用这么久pandas才知道 category里的这些坑!

数据分析与开发 来源:数据分析与开发 作者:数据分析与开发 2021-05-14 10:30 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

pandas有一个特别的数据类型叫category,如其名一样,是一种分类的数据类型。category很娇气,使用的时候稍有不慎就会进坑,因此本篇将介绍在pandas中,

1. 为什么要使用category?

2. 以及使用category时需要注意的一些坑!

文中使用的pandas版本为1.2.3,于今年2021年3月发布的。

为什么使用category数据类型?

总结一下,使用category有以下一些好处:

内存使用情况:对于重复值很多的字符串列,category可以大大减少将数据存储在内存中所需的内存量;

运行性能:进行了一些优化,可以提高某些操作的执行速度

算法库的适用:在某些情况下,一些算法模型需要category这种类型。比如,我们知道lightgbm相对于xgboost优化的一个点就是可以处理分类变量,而在构建模型时我们需要指定哪些列是分类变量,并将它们调整为category作为超参数传给模型。

一个简单的例子。

df_size = 100_000

df1 = pd.DataFrame(

{

“float_1”: np.random.rand(df_size),

“species”: np.random.choice([“cat”, “dog”, “ape”, “gorilla”], size=df_size),

}

df1_cat = df1.astype({“species”: “category”})

创建了两个DataFrame,其中df1包含了species并且为object类型,df1_cat复制了df1,但指定了species为category类型。

》》 df1.memory_usage(deep=True)

Index 128

float_1 800000

species 6100448

dtype: int64

就内存使用而言,我们可以直接看到包含字符串的列的成本是多高。species列的字符串大约占用了6MB,如果这些字符串较长,则将会更多。

》》 df1_cat.memory_usage(deep=True)

Index 128

float_1 800000

species 100416

dtype: int64

再看转换为category类别后的内存使用情况。有了相当大的改进,使用的内存减少了大约60倍。没有对比,就没有伤害。

这就是使用category的其中一个好处。但爱之深,责之切呀,使用它要格外小心。

使用category的一些坑!

一、category列的操作

好吧,这部分应该才是大家较为关心的,因为经常会遇到一些莫名其妙的报错或者感觉哪里不对,又不知道问题出在哪里。

首先,说明一下:使用category的时候需要格外小心,因为如果姿势不对,它就很可能变回object。而变回object的结果就是,会降低代码的性能(因为强制转换类型成本很高),并会消耗内存。

日常面对category类型的数据,我们肯定是要对其进行操作的,比如做一些转换。下面看一个例子,我们要分别对category和object类型进行同样的字符串大写操作,使用accessor的.str方法。

在非category字符串上:

》》 %timeit df1[“species”].str.upper()

25.6 ms ± 2.07 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

在category字符串上:

》》 %timeit df1_cat[“species”].str.upper()

1.85 ms ± 41.1 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

结果很明显了。在这种情况下,速度提高了大约14倍(因为内部优化会让.str.upper()仅对分类的唯一类别值调用一次,然后根据结果构造一个seires,而不是对结果中的每个值都去调用一次)。

怎么理解?假设现有一个列叫animal,其类别有cat和dog两种,假设样本为10000个,4000个cat和6000个dog。那么如果我用对category本身处理,意味着我只分别对cat和dog两种类别处理一次,一共两次就解决。如果对每个值处理,那就需要样本数量10000次的处理。

尽管从时间上有了一些优化,然而这种方法的使用也是有一些问题的。。。看一下内存使用情况。

》》 df1_cat[“species”].str.upper().memory_usage(deep=True)

6100576

意外的发现category类型丢了。。结果竟是一个object类型,数据压缩的效果也没了,现在的结果再次回到刚才的6MB内存占用。

这是因为使用str会直接让原本的category类型强制转换为object,所以内存占用又回去了,这是我为什么最开始说要格外小心。

解决方法就是:直接对category本身操作而不是对它的值操作。 要直接使用cat的方法来完成转换操作,如下。

%timeit df1_cat[“species”].cat.rename_categories(str.upper)

239 µs ± 13.9 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

可以看到,这个速度就更快了,因为省去了将category类别转换为object的时间,并且内存占用也非常少。因此,这才是最优的做法。

二、与category列的合并

还是上面那个例子,但是这次增加了habitat一列,并且species中增加了sanke。

df2 = pd.DataFrame(

{

“species”: [“cat”, “dog”, “ape”, “gorilla”, “snake”],

“habitat”: [“house”, “house”, “jungle”, “jungle”, “jungle”],

}

df2_cat = df2.astype({“species”: “category”, “habitat”: “category”})

和前面一样,创建该数据集的一个category版本,并创建了一个带有object字符串的版本。如果将两个object列合并在一起的,没什么意思,因为大家都知道会发生什么,object+ object= object而已。

把object列合并到category列上

还是一个例子。

》》 df1.merge(df2_cat, on=“species”).dtypes

float_1 float64

species object

habitat category

dtype: object

左边的df1中species列为object,右边的df2_cat中species列为category。我们可以看到,当我们合并时,在结果中的合并列会得到category+ object= object。

这显然不行了,又回到原来那样了。我们再试下其他情况。

两个category列的合并

》》 df1_cat.merge(df2_cat, on=“species”).dtypes

float_1 float64

species object

habitat category

dtype: object

结果是:category+ category= object?

有点想打人了,但是别急,我们看看为啥。

在合并中,为了保存分类类型,两个category类型必须是完全相同的。 这个与pandas中的其他数据类型略有不同,例如所有float64列都具有相同的数据类型,就没有什么区分。

而当我们讨论category数据类型时,该数据类型实际上是由该特定类别中存在的一组值来描述的,因此一个类别包含[“cat”, “dog”, “mouse”]与类别包含[“cheese”, “milk”, “eggs”]是不一样的。上面的例子之所以没成功,是因为多加了一个snake。

因此,我们可以得出结论:

category1+ category2=object

category1+ category1=category1

因此,解决办法就是:两个category类别一模一样,让其中一个等于另外一个。

》》 df1_cat.astype({“species”: df2_cat[“species”].dtype}).merge(

df2_cat, on=“species”

).dtypes

float_1 float64

species category

habitat category

dtype: object

三、category列的分组

用category类列分组时,一旦误操作就会发生意外,结果是Dataframe会被填成空值,还有可能直接跑死。。

当对category列分组时,默认情况下,即使category类别的各个类不存在值,也会对每个类进行分组。

一个例子来说明。

habitat_df = (

df1_cat.astype({“species”: df2_cat[“species”].dtype})

.merge(df2_cat, on=“species”)

house_animals_df = habitat_df.loc[habitat_df[“habitat”] == “house”]

这里采用habitat_df,从上面例子得到的,筛选habitat为house的,只有dog和cat是house,看下面分组结果。

》》 house_animals_df.groupby(“species”)[“float_1”].mean()

species

ape NaN

cat 0.501507

dog 0.501023

gorilla NaN

snake NaN

Name: float_1, dtype: float64

在groupby中得到了一堆空值。默认情况下,当按category列分组时,即使数据不存在,pandas也会为该类别中的每个值返回结果。略坑,如果数据类型包含很多不存在的,尤其是在多个不同的category列上进行分组,将会极其损害性能。

因此,解决办法是:可以传递observed=True到groupby调用中,这确保了我们仅获取数据中有值的组。

》》 house_animals_df.groupby(“species”, observed=True)[“float_1”].mean()

species

cat 0.501507

dog 0.501023

Name: float_1, dtype: float64

四、category列的索引

仍以上面例子举例,使用groupby-unstack实现了一个交叉表,species作为列,habitat作为行,均为category类型。

》》 species_df = habitat_df.groupby([“habitat”, “species”], observed=True)[“float_1”].mean().unstack()

》》 species_df

species cat ape dog gorilla

habitat

house 0.501507 NaN 0.501023 NaN

jungle NaN 0.501284 NaN 0.501108

这好像看似也没什么毛病,我们继续往下看。为这个交叉表添加一个新列new_col,值为1。

》》 species_df[“new_col”] = 1

TypeError: ‘fill_value=new_col’ is not present in this Categorical‘s categories

正常情况下,上面这段代码是完全可以的,但这里报错了,为什么?

原因是:species和habitat现在均为category类型。使用.unstack()会把species索引移到列索引中(类似pivot交叉表的操作)。而当添加的新列不在species的分类索引中时,就会报错。

虽然平时使用时可能很少用分类作为索引,但是万一恰巧用到了,就要注意一下了。

总结

总结一下,pandas的category类型非常有用,可以带来一些良好的性能优势。但是它也很娇气,使用过程中要尤为小心,确保category类型在整个流程中保持不变,避免变回object。本文介绍的4个点注意点:

category列的变换操作:直接对category本身操作而不是对它的值操作。这样可以保留分类性质并提高性能。

category列的合并:合并时注意,要保留category类型,且每个dataframe的合并列中的分类类型必须完全匹配。

category列的分组:默认情况下,获得数据类型中每个值的结果,即使数据中不存在该结果。可以通过设置observed=True调整。

category列的索引:当索引为category类型的时候,注意是否可能与类别变量发生奇怪的交互作用。

编辑:jq

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 数据
    +关注

    关注

    8

    文章

    7315

    浏览量

    94004
  • 数据存储
    +关注

    关注

    5

    文章

    1016

    浏览量

    52640
  • 算法库
    +关注

    关注

    0

    文章

    5

    浏览量

    1695

原文标题:用了一年 pandas,才知道 category 的这些坑!

文章出处:【微信号:DBDevs,微信公众号:数据分析与开发】欢迎添加关注!文章转载请注明出处。

收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    那些年我OpenCV+Qt趟过哪些?写给视觉应用开发者的避指南

    前阵子,团队里新来的小伙子跑来找我,眉头紧锁。他手里的项目我清楚:一个基于摄像头的简单计数工具。Demo阶段Python+OpenCV,几行代码跑得飞快,准确率也好看。可一旦要打包成给产线工人
    发表于 12-02 09:43

    那些年我OpenCV+Qt趟过哪些?写给视觉应用开发者的避指南

    前阵子,团队里新来的小伙子跑来找我,眉头紧锁。他手里的项目我清楚:一个基于摄像头的简单计数工具。Demo阶段Python+OpenCV,几行代码跑得飞快,准确率也好看。可一旦要打包成给产线工人
    的头像 发表于 12-02 09:40 152次阅读
    那些年我<b class='flag-5'>用</b>OpenCV+Qt趟过哪些<b class='flag-5'>坑</b>?写给视觉应用开发者的避<b class='flag-5'>坑</b>指南

    “智汇潇湘 聚湖南”成都、天津、深圳三城联动,拓维信息引热潮再升级!

    ,掀起一场“跨越千、迎凤归湘”的引热潮。图/拓维信息&TalkwebHouse双通道引模式备受关注面向人工智能引领的产业变革浪潮,TalkwebHouse科创
    的头像 发表于 11-10 18:20 511次阅读
    “智汇潇湘 <b class='flag-5'>才</b>聚湖南”成都、天津、深圳三城联动,拓维信息引<b class='flag-5'>才</b>热潮再升级!

    Hummingbirdv2 E203 仿真排之路

    simulation”部分,中途遇到很多,特来记录一番。 1.环境设置 1.1 强烈建议 ubuntu 18.04,安装时要点“下载更新” 我的是vmware 15.5pro虚拟机
    发表于 10-31 09:22

    以物联网技术助力博物馆智慧安防

    针对博物馆安防与运营两大核心需求,云打造全链条产品解决方案,先进的物联网智能硬件构建无死角防护网 。
    的头像 发表于 10-29 11:00 534次阅读

    光模块的「隐形功臣」:金手指凭什么这么关键?

    知道吗?在光模块的世界,有个不起眼却至关重要的角色 —— 金手指。别看它只是光模块尾部那排金光闪闪的触点,每一根都肩负着 “数据传输桥梁” 的重任。当光模块插入设备时,金手指直接与接口咬合,把电信号稳稳当当传输出去。
    的头像 发表于 09-10 16:31 644次阅读
    光模块<b class='flag-5'>里</b>的「隐形功臣」:金手指凭什么<b class='flag-5'>这么</b>关键?

    茂案例|解决工业物联3大痛点!5G边缘计算网关实战来了!

    在工业4.0落地中,你是否常被这些问题困扰:设备数据传得慢、云端卡顿拖效率?现场电源、网络设备零散,部署运维费工夫?老设备新系统协议不兼容,数据成“孤岛”?厦门茂CM520系列5G边缘计算网关,
    的头像 发表于 08-28 09:54 517次阅读
    <b class='flag-5'>才</b>茂案例|解决工业物联3大痛点!5G边缘计算网关实战来了!

    CSD船变压器铁芯硅钢片,真能扛住盐雾和振动吗?

    “船上的变压器铁芯,为什么老是被盐雾腐蚀?”“振动这么剧烈,硅钢片会不会松散,噪音变大?”这些问题,几乎每天都会出现在船东、船厂和配套工程师的聊天群。大家心里都清楚:铁芯一旦出问题,整台CSD船
    的头像 发表于 08-23 09:44 596次阅读
    CSD船<b class='flag-5'>用</b>变压器铁芯硅钢片,真能扛住盐雾和振动吗?

    【HZ-T536开发板免费体验】2、SDK编译

    文件放置到对应的板级配置目录即可。 接下来,就是按照文档2.1节的内容,按步骤仔细清理一下编译产物,再跟着步骤编译就可以了。 这里我踩了一个,也就是我以前瑞芯微的SDK,还有自己编译Linux
    发表于 07-31 18:37

    购买机器人气密性检测仪:避指南和建议

    家人们,在工业生产中,机器人气密性检测仪是保证产品质量的伟大贡献者。然而,在购买这个东西时,也是一个接一个的。今天,我想谈谈如何避免这些,并成功地购买合适的检测仪。(1)避开精度虚标的
    的头像 发表于 06-23 13:56 367次阅读
    购买机器人气密性检测仪:避<b class='flag-5'>坑</b>指南和建议

    防水变压器安装总踩这些要点不看亏大了!

    变压器时,到底该注意啥?​船防水变压器安装与调试安装船防水变压器,第一步就得把“位置关”。咱都知道船上空间寸土寸金,跟“螺蛳壳里做道场”似的。所以在方案阶段,
    的头像 发表于 06-20 10:23 514次阅读
    船<b class='flag-5'>用</b>防水变压器安装总踩<b class='flag-5'>坑</b>?<b class='flag-5'>这些</b>要点不看亏大了!

    知道变压器有哪些吗?

    在船舶和海洋平台上,电力系统的稳定运行至关重要,而船变压器作为其中的关键设备,其种类繁多,各具特点。你知道变压器有哪些吗?让我们一起来揭开它们的神秘面纱。CSD船变压器是船舶供
    的头像 发表于 06-01 00:00 498次阅读
    你<b class='flag-5'>知道</b>船<b class='flag-5'>用</b>变压器有哪些吗?

    电机产品在水泵行业的应用

    在工业4.0与“双碳”目标的推动下,水泵行业作为流体控制的核心领域,对节能高效的需求日益提升。电机作为水泵设备的心脏,其性能直接决定了水泵系统的效率、可靠性与成本。力电机围绕水泵行业的核心痛点及需求,提供高效电机产品解决方案。
    的头像 发表于 05-17 13:55 1136次阅读

    公路路面病害(如裂缝、槽等)检测

    公路路面病害(如裂缝、槽等)检测
    的头像 发表于 04-10 11:43 693次阅读
    公路路面病害(如裂缝、<b class='flag-5'>坑</b>槽等)检测

    正弦波FOC

    经常在坛看到各种关于正弦波的讨论,川办毕竟也搞电机控制方案和成品产生这么久了,以下文档,希望对大家有帮助。
    发表于 02-27 01:01