首頁  >  文章  >  後端開發  >  1%的人知道的pandas騷操作,傳授給你

1%的人知道的pandas騷操作,傳授給你

coldplay.xixi
coldplay.xixi轉載
2020-10-09 16:55:112505瀏覽

python教學欄位今天介紹pandas的操作。 1%的人知道的pandas騷操作,傳授給你

pandas有一種功能非常強大的方法,它就是accessor,可以將它理解為一種屬性接口,透過它可以獲得額外的方法。其實這樣說還是很籠統,下面我們透過程式碼和實例來理解一下。

>>> pd.Series._accessors
{'cat', 'str', 'dt'}复制代码

對於Series資料結構使用_accessors方法,我們得到了3個物件:cat,str,dt

  • .cat:用於分類資料(Categorical data)
  • .str:用於字元資料(String Object data)
  • .dt:用於時間資料(datetime-like data)

下面我們依序看一下這三個物件是如何使用的。

str物件的使用

Series資料型別:str字串

# 定义一个Series序列
>>> addr = pd.Series([
...     'Washington, D.C. 20003',
...     'Brooklyn, NY 11211-1755',
...     'Omaha, NE 68154',
...     'Pittsburgh, PA 15211'
... ]) 

>>> addr.str.upper()
0     WASHINGTON, D.C. 20003
1    BROOKLYN, NY 11211-1755
2            OMAHA, NE 68154
3       PITTSBURGH, PA 15211
dtype: object

>>> addr.str.count(r'\d') 
0    5
1    9
2    5
3    5
dtype: int64复制代码

關於上述str物件的2個方法說明:

  • Series.str.upper:將Series中所有字串變成大寫;
  • Series.str.count:對Series中所有字符字串的個數進行計數;

其實不難發現,該用法的使用與Python中字串的運算很相似。沒錯,在pandas中你一樣可以這樣簡單的操作,而不同的是你操作的是一整列的字串資料。仍然基於上述資料集,再看它的另一個操作:

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

關於以上str物件的2個方法說明:

  • Series.str.replace:將Series中指定字串替換;
  • Series.str.extract:透過正規表示式提取字串中的資料資訊;

這個用法就有點複雜了,因為很明顯看到,這是一個鍊式的用法。透過replace將" . " 替換為"",即為空,緊接著又使用了3個正規表示式(分別對應city,state,zip)透過extract對資料進行了提取,並由原來的Series資料結構變成DataFrame資料結構。

當然,除了上述用法外,常用的屬性和方法還有.rstrip,.contains,split等,我們透過下面程式碼查看一下str屬性的完整清單:

>>> [i for i in dir(pd.Series.str) if not i.startswith(&#39;_&#39;)]
[&#39;capitalize&#39;,
 &#39;cat&#39;,
 &#39;center&#39;,
 &#39;contains&#39;,
 &#39;count&#39;,
 &#39;decode&#39;,
 &#39;encode&#39;,
 &#39;endswith&#39;,
 &#39;extract&#39;,
 &#39;extractall&#39;,
 &#39;find&#39;,
 &#39;findall&#39;,
 &#39;get&#39;,
 &#39;get_dummies&#39;,
 &#39;index&#39;,
 &#39;isalnum&#39;,
 &#39;isalpha&#39;,
 &#39;isdecimal&#39;,
 &#39;isdigit&#39;,
 &#39;islower&#39;,
 &#39;isnumeric&#39;,
 &#39;isspace&#39;,
 &#39;istitle&#39;,
 &#39;isupper&#39;,
 &#39;join&#39;,
 &#39;len&#39;,
 &#39;ljust&#39;,
 &#39;lower&#39;,
 &#39;lstrip&#39;,
 &#39;match&#39;,
 &#39;normalize&#39;,
 &#39;pad&#39;,
 &#39;partition&#39;,
 &#39;repeat&#39;,
 &#39;replace&#39;,
 &#39;rfind&#39;,
 &#39;rindex&#39;,
 &#39;rjust&#39;,
 &#39;rpartition&#39;,
 &#39;rsplit&#39;,
 &#39;rstrip&#39;,
 &#39;slice&#39;,
 &#39;slice_replace&#39;,
 &#39;split&#39;,
 &#39;startswith&#39;,
 &#39;strip&#39;,
 &#39;swapcase&#39;,
 &#39;title&#39;,
 &#39;translate&#39;,
 &#39;upper&#39;,
 &#39;wrap&#39;,
 &#39;zfill&#39;]复制代码

屬性有很多,對於具體的用法,如果有興趣可以自己進行摸索練習。

dt物件的使用

Series資料類型:datetime

因為資料需要datetime類型,所以下面使用pandas的date_range()產生了一群組日期datetime示範如何進行dt物件操作。

>>> daterng = pd.Series(pd.date_range(&#39;2017&#39;, periods=9, freq=&#39;Q&#39;))
>>> daterng
0   2017-03-31
1   2017-06-30
2   2017-09-30
3   2017-12-31
4   2018-03-31
5   2018-06-30
6   2018-09-30
7   2018-12-31
8   2019-03-31
dtype: datetime64[ns]

>>>  daterng.dt.day_name()
0      Friday
1      Friday
2    Saturday
3      Sunday
4    Saturday
5    Saturday
6      Sunday
7      Monday
8      Sunday
dtype: object

>>> # 查看下半年
>>> daterng[daterng.dt.quarter > 2]
2   2017-09-30
3   2017-12-31
6   2018-09-30
7   2018-12-31
dtype: datetime64[ns]

>>> daterng[daterng.dt.is_year_end]
3   2017-12-31
7   2018-12-31
dtype: datetime64[ns]复制代码

以上關於dt的3種方法說明:

  • Series.dt.day_name():從日期判斷出所處星期數;
  • Series.dt.quarter:從日期判斷所處季節;
  • Series.dt.is_year_end:從日期判斷是否處在年底;

其它方法也都是基於datetime的一些變換,並透過變換來查看具體微觀或宏觀日期。

cat物件的使用

Series資料類型:Category

在說cat物件的使用前,先說Category這個資料類型,它的作用很強。雖然我們沒有經常性的在記憶體中運行上g的數據,但是我們也總是會遇到執行幾行程式碼會等待很久的情況。使用Category資料的一個好處是:可以很好的節省在時間和空間的消耗。 下面我們透過幾個實例來學習一下。

>>> colors = pd.Series([
...     &#39;periwinkle&#39;,
...     &#39;mint green&#39;,
...     &#39;burnt orange&#39;,
...     &#39;periwinkle&#39;,
...     &#39;burnt orange&#39;,
...     &#39;rose&#39;,
...     &#39;rose&#39;,
...     &#39;mint green&#39;,
...     &#39;rose&#39;,
...     &#39;navy&#39;
... ])
...
>>> import sys
>>> colors.apply(sys.getsizeof)
0    59
1    59
2    61
3    59
4    61
5    53
6    53
7    59
8    53
9    53
dtype: int64复制代码

上面我們透過使用sys.getsizeof來顯示記憶體佔用的情況,數字代表位元組數。
還有另一種計算內容佔用的方法:memory_usage(),後面會使用。

現在我們將上面colors的不重複值對應到一組整數,然後再看一下佔用的記憶體。

>>> mapper = {v: k for k, v in enumerate(colors.unique())}
>>> mapper
{&#39;periwinkle&#39;: 0, &#39;mint green&#39;: 1, &#39;burnt orange&#39;: 2, &#39;rose&#39;: 3, &#39;navy&#39;: 4}

>>> as_int = colors.map(mapper)
>>> as_int
0    0
1    1
2    2
3    0
4    2
5    3
6    3
7    1
8    3
9    4
dtype: int64

>>> as_int.apply(sys.getsizeof)
0    24
1    28
2    28
3    24
4    28
5    28
6    28
7    28
8    28
9    28
dtype: int64复制代码

註:對於以上的整數值映射也可以使用更簡單的pd.factorize()方法來代替。

我們發現上面所佔用的記憶體是使用object類型時的一半。其實,這種情況就類似Category data類型內部的原理。

記憶體佔用區別:Categorical所佔用的記憶體與Categorical分類的數量和資料的長度成正比,相反,object所佔用的記憶體則是一個常數乘以數據的長度。

以下是object記憶體使用和category記憶體使用的情況比較。

>>> colors.memory_usage(index=False, deep=True)
650
>>> colors.astype(&#39;category&#39;).memory_usage(index=False, deep=True)
495复制代码

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

>>> manycolors = colors.repeat(10)
>>> len(manycolors) / manycolors.nunique() 
20.0

>>> manycolors.memory_usage(index=False, deep=True)
6500
>>> manycolors.astype(&#39;category&#39;).memory_usage(index=False, deep=True)
585复制代码

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

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

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

>>> ccolors = colors.astype(&#39;category&#39;)
>>> ccolors.cat.categories
Index([&#39;burnt orange&#39;, &#39;mint green&#39;, &#39;navy&#39;, &#39;periwinkle&#39;, &#39;rose&#39;], dtype=&#39;object&#39;)复制代码

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

>>> ccolors.cat.reorder_categories(mapper).cat.codes
0    0
1    1
2    2
3    0
4    2
5    3
6    3
7    1
8    3
9    4
dtype: int8复制代码

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

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

>>> [i for i in dir(ccolors.cat) if not i.startswith(&#39;_&#39;)]
[&#39;add_categories&#39;,
 &#39;as_ordered&#39;,
 &#39;as_unordered&#39;,
 &#39;categories&#39;,
 &#39;codes&#39;,
 &#39;ordered&#39;,
 &#39;remove_categories&#39;,
 &#39;remove_unused_categories&#39;,
 &#39;rename_categories&#39;,
 &#39;reorder_categories&#39;,
 &#39;set_categories&#39;]复制代码

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

>>> ccolors.iloc[5] = &#39;a new color&#39;
# ...
ValueError: Cannot setitem on a Categorical with a new category,
set the categories first

>>> ccolors = ccolors.cat.add_categories([&#39;a new color&#39;])
>>> ccolors.iloc[5] = &#39;a new color&#39;  
复制代码

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

相关免费学习推荐:python教程(视频)

以上是1%的人知道的pandas騷操作,傳授給你的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:juejin.im。如有侵權,請聯絡admin@php.cn刪除