资讯专栏INFORMATION COLUMN

99%的人都不知道的pandas骚操作(一)

Jonathan Shieber / 1246人阅读

摘要:没错,在中你一样可以这样简单的操作,而不同的是你操作的是一整列的字符串数据。因为对于类型的,字符的操作发生在的非重复值上,而并非原上的所有元素上。下面的这些属性基本都是关于查看和操作数据类型的。

作者:xiaoyu

微信公众号:Python数据科学

知乎:python数据分析师



pandas有一种功能非常强大的方法,它就是accessor,可以将它理解为一种属性接口,通过它可以获得额外的方法。其实这样说还是很笼统,下面我们通过代码和实例来理解一下。

</>复制代码

  1. >>> pd.Series._accessors
  2. {"cat", "str", "dt"}

对于Series数据结构使用_accessors方法,我们得到了3个对象:cat,str,dt

.cat:用于分类数据(Categorical data)

.str:用于字符数据(String Object data)

.dt:用于时间数据(datetime-like data)

下面我们依次看一下这三个对象是如何使用的。

str对象的使用

</>复制代码

  1. Series数据类型:str字符串

</>复制代码

  1. # 定义一个Series序列
  2. >>> addr = pd.Series([
  3. ... "Washington, D.C. 20003",
  4. ... "Brooklyn, NY 11211-1755",
  5. ... "Omaha, NE 68154",
  6. ... "Pittsburgh, PA 15211"
  7. ... ])
  8. >>> addr.str.upper()
  9. 0 WASHINGTON, D.C. 20003
  10. 1 BROOKLYN, NY 11211-1755
  11. 2 OMAHA, NE 68154
  12. 3 PITTSBURGH, PA 15211
  13. dtype: object
  14. >>> addr.str.count(r"d")
  15. 0 5
  16. 1 9
  17. 2 5
  18. 3 5
  19. dtype: int64

关于以上str对象的2个方法说明:

Series.str.upper:将Series中所有字符串变为大写;

Series.str.count:对Series中所有字符串的个数进行计数;

其实不难发现,该用法的使用与Python中字符串的操作很相似。没错,在pandas中你一样可以这样简单的操作,而不同的是你操作的是一整列的字符串数据。仍然基于以上数据集,再看它的另一个操作:

</>复制代码

  1. >>> regex = (r"(?P[A-Za-z ]+), " # 一个或更多字母
  2. ... r"(?P[A-Z]{2}) " # 两个大写字母
  3. ... r"(?Pd{5}(?:-d{4})?)") # 可选的4个延伸数字
  4. ...
  5. >>> addr.str.replace(".", "").str.extract(regex)
  6. city state zip
  7. 0 Washington DC 20003
  8. 1 Brooklyn NY 11211-1755
  9. 2 Omaha NE 68154
  10. 3 Pittsburgh PA 15211

关于以上str对象的2个方法说明:

Series.str.replace:将Series中指定字符串替换;

Series.str.extract:通过正则表达式提取字符串中的数据信息;

这个用法就有点复杂了,因为很明显看到,这是一个链式的用法。通过replace将 " . " 替换为"",即为空,紧接着又使用了3个正则表达式(分别对应city,state,zip)通过extract对数据进行了提取,并由原来的Series数据结构变为了DataFrame数据结构。

当然,除了以上用法外,常用的属性和方法还有rstrip.containssplit等,我们通过下面代码查看一下str属性的完整列表:

</>复制代码

  1. >>> [i for i in dir(pd.Series.str) if not i.startswith("_")]
  2. ["capitalize",
  3. "cat",
  4. "center",
  5. "contains",
  6. "count",
  7. "decode",
  8. "encode",
  9. "endswith",
  10. "extract",
  11. "extractall",
  12. "find",
  13. "findall",
  14. "get",
  15. "get_dummies",
  16. "index",
  17. "isalnum",
  18. "isalpha",
  19. "isdecimal",
  20. "isdigit",
  21. "islower",
  22. "isnumeric",
  23. "isspace",
  24. "istitle",
  25. "isupper",
  26. "join",
  27. "len",
  28. "ljust",
  29. "lower",
  30. "lstrip",
  31. "match",
  32. "normalize",
  33. "pad",
  34. "partition",
  35. "repeat",
  36. "replace",
  37. "rfind",
  38. "rindex",
  39. "rjust",
  40. "rpartition",
  41. "rsplit",
  42. "rstrip",
  43. "slice",
  44. "slice_replace",
  45. "split",
  46. "startswith",
  47. "strip",
  48. "swapcase",
  49. "title",
  50. "translate",
  51. "upper",
  52. "wrap",
  53. "zfill"]

属性有很多,对于具体的用法,如果感兴趣可以自己进行摸索练习。

dt对象的使用

</>复制代码

  1. Series数据类型:datetime

因为数据需要datetime类型,所以下面使用pandas的date_range()生成了一组日期datetime演示如何进行dt对象操作。

</>复制代码

  1. >>> daterng = pd.Series(pd.date_range("2017", periods=9, freq="Q"))
  2. >>> daterng
  3. 0 2017-03-31
  4. 1 2017-06-30
  5. 2 2017-09-30
  6. 3 2017-12-31
  7. 4 2018-03-31
  8. 5 2018-06-30
  9. 6 2018-09-30
  10. 7 2018-12-31
  11. 8 2019-03-31
  12. dtype: datetime64[ns]
  13. >>> daterng.dt.day_name()
  14. 0 Friday
  15. 1 Friday
  16. 2 Saturday
  17. 3 Sunday
  18. 4 Saturday
  19. 5 Saturday
  20. 6 Sunday
  21. 7 Monday
  22. 8 Sunday
  23. dtype: object
  24. >>> # 查看下半年
  25. >>> daterng[daterng.dt.quarter > 2]
  26. 2 2017-09-30
  27. 3 2017-12-31
  28. 6 2018-09-30
  29. 7 2018-12-31
  30. dtype: datetime64[ns]
  31. >>> daterng[daterng.dt.is_year_end]
  32. 3 2017-12-31
  33. 7 2018-12-31
  34. dtype: datetime64[ns]

以上关于dt的3种方法说明:

Series.dt.day_name():从日期判断出所处星期数;

Series.dt.quarter:从日期判断所处季节;

Series.dt.is_year_end:从日期判断是否处在年底;

其它方法也都是基于datetime的一些变换,并通过变换来查看具体微观或者宏观日期。

cat对象的使用

</>复制代码

  1. Series数据类型:Category

在说cat对象的使用前,先说一下Category这个数据类型,它的作用很强大。虽然我们没有经常性的在内存中运行上g的数据,但是我们也总会遇到执行几行代码会等待很久的情况。使用Category数据的一个好处就是:可以很好的节省在时间和空间的消耗。下面我们通过几个实例来学习一下。

</>复制代码

  1. >>> colors = pd.Series([
  2. ... "periwinkle",
  3. ... "mint green",
  4. ... "burnt orange",
  5. ... "periwinkle",
  6. ... "burnt orange",
  7. ... "rose",
  8. ... "rose",
  9. ... "mint green",
  10. ... "rose",
  11. ... "navy"
  12. ... ])
  13. ...
  14. >>> import sys
  15. >>> colors.apply(sys.getsizeof)
  16. 0 59
  17. 1 59
  18. 2 61
  19. 3 59
  20. 4 61
  21. 5 53
  22. 6 53
  23. 7 59
  24. 8 53
  25. 9 53
  26. dtype: int64

</>复制代码

  1. 上面我们通过使用sys.getsizeof来显示内存占用的情况,数字代表字节数。
    还有另一种计算内容占用的方法:memory_usage(),后面会使用。

现在我们将上面colors的不重复值映射为一组整数,然后再看一下占用的内存。

</>复制代码

  1. >>> mapper = {v: k for k, v in enumerate(colors.unique())}
  2. >>> mapper
  3. {"periwinkle": 0, "mint green": 1, "burnt orange": 2, "rose": 3, "navy": 4}
  4. >>> as_int = colors.map(mapper)
  5. >>> as_int
  6. 0 0
  7. 1 1
  8. 2 2
  9. 3 0
  10. 4 2
  11. 5 3
  12. 6 3
  13. 7 1
  14. 8 3
  15. 9 4
  16. dtype: int64
  17. >>> as_int.apply(sys.getsizeof)
  18. 0 24
  19. 1 28
  20. 2 28
  21. 3 24
  22. 4 28
  23. 5 28
  24. 6 28
  25. 7 28
  26. 8 28
  27. 9 28
  28. dtype: int64

</>复制代码

  1. 注:对于以上的整数值映射也可以使用更简单的pd.factorize()方法代替。

我们发现上面所占用的内存是使用object类型时的一半。其实,这种情况就类似于Category data类型内部的原理。

</>复制代码

  1. 内存占用区别:Categorical所占用的内存与Categorical分类的数量和数据的长度成正比,相反,object所占用的内存则是一个常数乘以数据的长度。

下面是object内存使用和category内存使用的情况对比。

</>复制代码

  1. >>> colors.memory_usage(index=False, deep=True)
  2. 650
  3. >>> colors.astype("category").memory_usage(index=False, deep=True)
  4. 495

上面结果是使用objectCategory两种情况下内存的占用情况。我们发现效果并没有我们想象中的那么好。但是注意Category内存是成比例的,如果数据集的数据量很大,但不重复分类(unique)值很少的情况下,那么Category的内存占用可以节省达到10倍以上,比如下面数据量增大的情况:

</>复制代码

  1. >>> manycolors = colors.repeat(10)
  2. >>> len(manycolors) / manycolors.nunique()
  3. 20.0
  4. >>> manycolors.memory_usage(index=False, deep=True)
  5. 6500
  6. >>> manycolors.astype("category").memory_usage(index=False, deep=True)
  7. 585

可以看到,在数据量增加10倍以后,使用Category所占内容节省了10倍以上。

除了占用内存节省外,另一个额外的好处是计算效率有了很大的提升。因为对于Category类型的Series,str字符的操作发生在.cat.categories的非重复值上,而并非原Series上的所有元素上。也就是说对于每个非重复值都只做一次操作,然后再向与非重复值同类的值映射过去。

对于Category的数据类型,可以使用accessor的cat对象,以及相应的属性和方法来操作Category数据。

</>复制代码

  1. >>> ccolors = colors.astype("category")
  2. >>> ccolors.cat.categories
  3. Index(["burnt orange", "mint green", "navy", "periwinkle", "rose"], dtype="object")

实际上,对于开始的整数类型映射,我们可以先通过reorder_categories进行重新排序,然后再使用cat.codes来实现对整数的映射,来达到同样的效果。

</>复制代码

  1. >>> ccolors.cat.reorder_categories(mapper).cat.codes
  2. 0 0
  3. 1 1
  4. 2 2
  5. 3 0
  6. 4 2
  7. 5 3
  8. 6 3
  9. 7 1
  10. 8 3
  11. 9 4
  12. dtype: int8

dtype类型是Numpyint8(-127~128)。可以看出以上只需要一个单字节就可以在内存中包含所有的值。我们开始的做法默认使用了int64类型,然而通过pandas的使用可以很智能的将Category数据类型变为最小的类型。

让我们来看一下cat还有什么其它的属性和方法可以使用。下面cat的这些属性基本都是关于查看和操作Category数据类型的。

</>复制代码

  1. >>> [i for i in dir(ccolors.cat) if not i.startswith("_")]
  2. ["add_categories",
  3. "as_ordered",
  4. "as_unordered",
  5. "categories",
  6. "codes",
  7. "ordered",
  8. "remove_categories",
  9. "remove_unused_categories",
  10. "rename_categories",
  11. "reorder_categories",
  12. "set_categories"]

但是Category数据的使用不是很灵活。例如,插入一个之前没有的值,首先需要将这个值添加到.categories的容器中,然后再添加值。

</>复制代码

  1. >>> ccolors.iloc[5] = "a new color"
  2. # ...
  3. ValueError: Cannot setitem on a Categorical with a new category,
  4. set the categories first
  5. >>> ccolors = ccolors.cat.add_categories(["a new color"])
  6. >>> ccolors.iloc[5] = "a new color"

</>复制代码

  1. 如果你想设置值或重塑数据,而非进行新的运算操作,那么Category类型不是那么有用。

以上就是本次骚操作的介绍,你get到了没有?

关注微信公众号:Python数据科学,发现更多精彩内容。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/19804.html

相关文章

  • 99%都不知道pandas操作

    摘要:没错,在中你一样可以这样简单的操作,而不同的是你操作的是一整列的字符串数据。因为对于类型的,字符的操作发生在的非重复值上,而并非原上的所有元素上。下面的这些属性基本都是关于查看和操作数据类型的。 作者:xiaoyu 微信公众号:Python数据科学 知乎:python数据分析师 showImg(https://segmentfault.com/img/remote/146000001...

    ShevaKuilin 评论0 收藏0
  • 99%都不知道春节抢票背后云计算在加持

    摘要:春节抢票应该是每个在外游子的必修课,还有不足一个月就要过春节了,现在的你,是不是还奋战在抢票一线呢说到抢票,之所以现在大家能享受到流畅的移动互联网购票服务,其实背后都是云计算在加持,没想到吧,原来看似高深的云计算离我们如此之近。春节抢票应该是每个在外游子的必修课,还有不足一个月就要过春节了,现在的你,是不是还奋战在抢票一线呢?说到抢票,之所以现在大家能享受到流畅的移动互联网购票服务,其实背后...

    megatron 评论0 收藏0
  • 深拷贝终极探索(99%都不知道

    摘要:划重点,这是一道面试必考题,我靠这道题刷掉了多少面试者嘿嘿首先这是一道非常棒的面试题,可以考察面试者的很多方面,比如基本功,代码能力,逻辑能力,而且进可攻,退可守,针对不同级别的人可以考察不同难度,比如漂亮妹子就出题,要是个帅哥那就得上了, 划重点,这是一道面试必考题,我靠这道题刷掉了多少面试者✧(≖ ◡ ≖✿)嘿嘿 首先这是一道非常棒的面试题,可以考察面试者的很多方面,比如基本功,代...

    qingshanli1988 评论0 收藏0
  • HTTP中GET与POST区别 99%错误认识

    摘要:不会产生动作意味着和的请求不会在服务器上产生任何结果。对长度的限制是字节。起限制作用的是服务器的处理程序的处理能力。很可能受到中文名称跨站请求伪造攻击。而数据大小,则是因为浏览器的限制造成的。请开始你的表演参考文章的人都理解错了中与的区别 本篇文章分两部分,第一部分可以列为初为新人的装逼失败模式,第二部分列为修炼低调模式。装逼失败模式:99%的人对GET和POST的认识修炼低调模式:1...

    Bowman_han 评论0 收藏0
  • HTTP中GET与POST区别 99%错误认识

    摘要:不会产生动作意味着和的请求不会在服务器上产生任何结果。对长度的限制是字节。起限制作用的是服务器的处理程序的处理能力。很可能受到中文名称跨站请求伪造攻击。而数据大小,则是因为浏览器的限制造成的。请开始你的表演参考文章的人都理解错了中与的区别 本篇文章分两部分,第一部分可以列为初为新人的装逼失败模式,第二部分列为修炼低调模式。装逼失败模式:99%的人对GET和POST的认识修炼低调模式:1...

    isaced 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<