摘要:不為人知的七大實用技巧大家好,我今天勤快地回來了,這一期主要是和大家分享一些的實用技巧,會在日常生活中大大提升效率,希望可以幫助到大家還是老樣子,先給大家奉上這一期的章節目錄自定義選項,設置實用中模塊構建測試數據巧用訪問器合并其他列拼接使用
Pandas不為人知的七大實用技巧
大家好,我今天勤快地回來了,這一期主要是和大家分享一些pandas的實用技巧,會在日常生活中大大提升效率,希望可以幫助到大家,還是老樣子,先給大家奉上這一期的章節目錄:
自定義pandas選項,設置
實用pandas中testing模塊構建測試數據
巧用accessor訪問器
合并其他列拼接DatetimeIndex
使用分類數據(Categorical Data)節省時間和空間
利用Mapping巧妙實現映射
壓縮pandas對象
源碼及GitHub地址
好啦,話不多說,讓我們一個個看吧
1. 自定義pandas選項,設置首先,大家可能不知道,pandas里面有一個方法pd.set_option(),利用它我們可以改變一些pandas中默認的核心設置,
從而適應我們自身的需要,開始前還是老樣子,讓我們先導入numpy和pandas包
import numpy as np import pandas as pd f"Using {pd.__name__}, Version {pd.__version__}"
"Using pandas, Version 0.23.0"
現在讓我們編寫一個start方法來實現自定義pandas設置
def start(): options = { "display": { "max_columns": None, "max_colwidth": 25, "expand_frame_repr": False, # Don"t wrap to multiple pages "max_rows": 14, "max_seq_items": 50, # Max length of printed sequence "precision": 4, "show_dimensions": False }, "mode": { "chained_assignment": None # Controls SettingWithCopyWarning } } for category, option in options.items(): for op, value in option.items(): pd.set_option(f"{category}.{op}", value) # Python 3.6+ if __name__ == "__main__": start() del start # Clean up namespace in the interpreter
大家可以發現,我們在方法的最后調用了pandas的set_option方法,直接利用我們自定義的參數替代了原有的pandas參數,現在讓我們測試一下:
pd.get_option("display.max_rows") Out:14
可以發現max_rows 已經被替換成了我們設置的14,現在用一個真實的例子,我們利用一組公開的鮑魚各項指標的數據來實驗,數據源來自機器學習平臺的公開數據
url = ("https://archive.ics.uci.edu/ml/" "machine-learning-databases/abalone/abalone.data") cols = ["sex", "length", "diam", "height", "weight", "rings"] abalone = pd.read_csv(url, usecols=[0, 1, 2, 3, 4, 8], names=cols) abalone
sex | length | diam | height | weight | rings | |
---|---|---|---|---|---|---|
0 | M | 0.455 | 0.365 | 0.095 | 0.5140 | 15 |
1 | M | 0.350 | 0.265 | 0.090 | 0.2255 | 7 |
2 | F | 0.530 | 0.420 | 0.135 | 0.6770 | 9 |
3 | M | 0.440 | 0.365 | 0.125 | 0.5160 | 10 |
4 | I | 0.330 | 0.255 | 0.080 | 0.2050 | 7 |
5 | I | 0.425 | 0.300 | 0.095 | 0.3515 | 8 |
6 | F | 0.530 | 0.415 | 0.150 | 0.7775 | 20 |
... | ... | ... | ... | ... | ... | ... |
4170 | M | 0.550 | 0.430 | 0.130 | 0.8395 | 10 |
4171 | M | 0.560 | 0.430 | 0.155 | 0.8675 | 8 |
4172 | F | 0.565 | 0.450 | 0.165 | 0.8870 | 11 |
4173 | M | 0.590 | 0.440 | 0.135 | 0.9660 | 10 |
4174 | M | 0.600 | 0.475 | 0.205 | 1.1760 | 9 |
4175 | F | 0.625 | 0.485 | 0.150 | 1.0945 | 10 |
4176 | M | 0.710 | 0.555 | 0.195 | 1.9485 | 12 |
我們可以看到,數據截斷為14行,保留了小數點后4位小數作為精度,和我們剛剛設置的precision=4是一樣的
2. 實用pandas中testing模塊構建測試數據通過pandas.util.testing提供的方法,我們可以很容易的通過幾行代碼就構建出一個簡單的測試數據類型,比如我們現在構建一個DataTime類型的數據,
時間間隔為月:
import pandas.util.testing as tm tm.N, tm.K = 15, 3 # 規定行和列 import numpy as np np.random.seed(444) tm.makeTimeDataFrame(freq="M").head() # 設置時間間隔為月 # tm.makeTimeDataFrame(freq="D").head() 設置時間間隔為天
A | B | C | |
---|---|---|---|
2000-01-31 | 0.3574 | -0.8804 | 0.2669 |
2000-02-29 | 0.3775 | 0.1526 | -0.4803 |
2000-03-31 | 1.3823 | 0.2503 | 0.3008 |
2000-04-30 | 1.1755 | 0.0785 | -0.1791 |
2000-05-31 | -0.9393 | -0.9039 | 1.1837 |
瞎生成一組亂七八糟的數據:
tm.makeDataFrame().head()
A | B | C | |
---|---|---|---|
nTLGGTiRHF | -0.6228 | 0.6459 | 0.1251 |
WPBRn9jtsR | -0.3187 | -0.8091 | 1.1501 |
7B3wWfvuDA | -1.9872 | -1.0795 | 0.2987 |
yJ0BTjehH1 | 0.8802 | 0.7403 | -1.2154 |
0luaYUYvy1 | -0.9320 | 1.2912 | -0.2907 |
關于可以隨機生成的數據類型, 一共大概有30多種,大家如果感興趣可以多試試:
[i for i in dir(tm) if i.startswith("make")]
["makeBoolIndex", "makeCategoricalIndex", "makeCustomDataframe", "makeCustomIndex", "makeDataFrame", "makeDateIndex", "makeFloatIndex", "makeFloatSeries", "makeIntIndex", "makeIntervalIndex", "makeMissingCustomDataframe", "makeMissingDataframe", "makeMixedDataFrame", "makeMultiIndex", "makeObjectSeries", "makePanel", "makePeriodFrame", "makePeriodIndex", "makePeriodPanel", "makePeriodSeries", "makeRangeIndex", "makeStringIndex", "makeStringSeries", "makeTimeDataFrame", "makeTimeSeries", "makeTimedeltaIndex", "makeUIntIndex", "makeUnicodeIndex"]
這樣我們如果有測試的需求,會很容易地構建相對應的假數據來測試。
3. 巧用accessor訪問器accessor(訪問器) 具體就是類似getter和setter,當然,Python里面不提倡存在setter和getter方法,但是這樣可以便于大家理解,pandas Series類型有3類accessor:
pd.Series._accessors Out:{"cat", "dt", "str"}
.cat用于分類數據,
.str用于字符串(對象)數據,
.dt用于類似日期時間的數據。
讓我們從.str開始看:假設現在我們有一些原始的城市/州/ 郵編數據作為Dataframe的一個字段:
addr = pd.Series([ "Washington, D.C. 20003", "Brooklyn, NY 11211-1755", "Omaha, NE 68154", "Pittsburgh, PA 15211" ])
addr.str.upper() # 因為字符串方法是矢量化的,這意味著它們在沒有顯式for循環的情況下對整個數組進行操作
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
如果我們想把每一行分成城市,州,郵編分開,可以用正則;
regex = (r"(?P[A-Za-z ]+), " # One or more letters r"(?P [A-Z]{2}) " # 2 capital letters r"(?P d{5}(?:-d{4})?)") # Optional 4-digit extension addr.str.replace(".", "").str.extract(regex)
city | state | zip | |
---|---|---|---|
0 | Washington | DC | 20003 |
1 | Brooklyn | NY | 11211-1755 |
2 | Omaha | NE | 68154 |
3 | Pittsburgh | PA | 15211 |
第二個訪問器.dt用于類似日期時間的數據。它其實屬于Pandas的DatetimeIndex,如果在Series上調用,它首先轉換為DatetimeIndex
daterng = pd.Series(pd.date_range("2018", periods=9, freq="Q")) # 時間間隔為季度 daterng
0 2018-03-31 1 2018-06-30 2 2018-09-30 3 2018-12-31 4 2019-03-31 5 2019-06-30 6 2019-09-30 7 2019-12-31 8 2020-03-31 dtype: datetime64[ns]
daterng.dt.day_name()
0 Saturday 1 Saturday 2 Sunday 3 Monday 4 Sunday 5 Sunday 6 Monday 7 Tuesday 8 Tuesday dtype: object
daterng[daterng.dt.quarter > 2] # 查看2019年第3季度和第4季度
2 2018-09-30 3 2018-12-31 6 2019-09-30 7 2019-12-31 dtype: datetime64[ns]
daterng[daterng.dt.is_year_end] #查看年末的一天
3 2018-12-31 7 2019-12-31 dtype: datetime64[ns]
最后有關.cat訪問器我們會在第5個技巧中提到
4. 合并其他列拼接DatetimeIndex現在先讓我們構建一個包含時間類型數據的Dataframe:
from itertools import product datecols = ["year", "month", "day"] df = pd.DataFrame(list(product([2017, 2016], [1, 2], [1, 2, 3])), columns=datecols) df["data"] = np.random.randn(len(df)) df
year | month | day | data | |
---|---|---|---|---|
0 | 2017 | 1 | 1 | -0.0767 |
1 | 2017 | 1 | 2 | -1.2798 |
2 | 2017 | 1 | 3 | 0.4032 |
3 | 2017 | 2 | 1 | 1.2377 |
4 | 2017 | 2 | 2 | -0.2060 |
5 | 2017 | 2 | 3 | 0.6187 |
6 | 2016 | 1 | 1 | 2.3786 |
7 | 2016 | 1 | 2 | -0.4730 |
8 | 2016 | 1 | 3 | -2.1505 |
9 | 2016 | 2 | 1 | -0.6340 |
10 | 2016 | 2 | 2 | 0.7964 |
11 | 2016 | 2 | 3 | 0.0005 |
我們可以發現year,month,day是分開的三列,我們如果想要把它們合并為完整的時間并作為df的索引,可以這么做:
df.index = pd.to_datetime(df[datecols]) df.head()
year | month | day | data | |
---|---|---|---|---|
2017-01-01 | 2017 | 1 | 1 | -0.0767 |
2017-01-02 | 2017 | 1 | 2 | -1.2798 |
2017-01-03 | 2017 | 1 | 3 | 0.4032 |
2017-02-01 | 2017 | 2 | 1 | 1.2377 |
2017-02-02 | 2017 | 2 | 2 | -0.2060 |
我們可以扔掉沒用的列并把這個df壓縮為Series:
df = df.drop(datecols, axis=1).squeeze() df.head()
2017-01-01 -0.0767 2017-01-02 -1.2798 2017-01-03 0.4032 2017-02-01 1.2377 2017-02-02 -0.2060 Name: data, dtype: float64
type(df)
pandas.core.series.Series
df.index.dtype_str
"datetime64[ns]"5. 使用分類數據(Categorical Data)節省時間和空間
剛剛我們在第3個技巧的時候提到了訪問器,現在讓我們來看最后一個.cat
pandas中Categorical這個數據類型非常強大,通過類型轉換可以讓我們節省變量在內存占用的空間,提高運算速度,不過有關具體的pandas加速實戰,我會在
下一期說,現在讓我們來看一個小栗子:
colors = pd.Series([ "periwinkle", "mint green", "burnt orange", "periwinkle", "burnt orange", "rose", "rose", "mint green", "rose", "navy" ]) 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
我們首先創建了一個Series,填充了各種顏色,接著查看了每個地址對應的顏色所占內存的大小
注意這里我們使用sys.getsizeof()來獲取占內存大小,但是實際上空格也是占內存的,sys.getsizeof("")返回的是49bytes
接下來我們想把每種顏色用占內存更少的數字來表示(機器學習種非常常見),這樣可以減少占用的內存,首先讓我們創建一個mapper字典,給每一種顏色指定
一個數字
mapper = {v: k for k, v in enumerate(colors.unique())} mapper
{"periwinkle": 0, "mint green": 1, "burnt orange": 2, "rose": 3, "navy": 4}
接著我們把剛才的colors數組轉化為int類型:
# 也可以通過 pd.factorize(colors)[0] 實現 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
現在可以觀察到我們的內存占用的空間幾乎是之前的一半,其實,剛剛我們做的正是模擬Categorical Data的轉化原理。現在讓我們直接調用一下:
colors.memory_usage(index=False, deep=True) Out:650
colors.astype("category").memory_usage(index=False, deep=True) Out: 495
大家可能感覺節省的空間并不是非常大對不對? 因為目前我們這個數據根本不是真實場景,我們僅僅把數據容量增加10倍,現在再讓我們看看效果:
manycolors = colors.repeat(10) len(manycolors) / manycolors.nunique() # Much greater than 2.0x Out:20.0
f"Not using category : { manycolors.memory_usage(index=False, deep=True)}"
"Not using category : 6500"
f"Using category : { manycolors.astype("category").memory_usage(index=False, deep=True)}"
"Using category : 585"
這回內存的占用量差距明顯就出來了,現在讓我們用.cat來簡化一下剛剛的工作:
new_colors = colors.astype("category") new_colors
0 periwinkle 1 mint green 2 burnt orange 3 periwinkle 4 burnt orange 5 rose 6 rose 7 mint green 8 rose 9 navy dtype: category Categories (5, object): [burnt orange, mint green, navy, periwinkle, rose]
new_colors.cat.categories # 可以使用.cat.categories查看代表的顏色
Index(["burnt orange", "mint green", "navy", "periwinkle", "rose"], dtype="object")
現在讓我們查看把顏色代表的數字:
new_colors.cat.codes
0 3 1 1 2 0 3 3 4 0 5 4 6 4 7 1 8 4 9 2 dtype: int8
我們如果不滿意順序也可以從新排序:
new_colors.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
有關cat其他的方法,我們還是可以通過遍歷dir來查看:
[i for i in dir(new_colors.cat) if not i.startswith("_")]
["add_categories", "as_ordered", "as_unordered", "categories", "codes", "ordered", "remove_categories", "remove_unused_categories", "rename_categories", "reorder_categories", "set_categories"]
Categorical 數據通常不太靈活,比如我們不能直接在new_colors上新增一個新的顏色,要首先通過
.add_categories來添加
ccolors.iloc[5] = "a new color"
--------------------------------------------------------------------------- NameError Traceback (most recent call last)in () ----> 1 ccolors.iloc[5] = "a new color" NameError: name "ccolors" is not defined
new_colors = new_colors.cat.add_categories(["a new color"])
new_colors.iloc[5] = "a new color" # 不會報錯
new_colors.values # 成功添加6. 利用Mapping巧妙實現映射
假設現在我們有存貯國家的一組數據,和一組用來映射國家所對應的大洲的數據:
countries = pd.Series([ "United States", "Canada", "Mexico", "Belgium", "United Kingdom", "Thailand" ]) groups = { "North America": ("United States", "Canada", "Mexico", "Greenland"), "Europe": ("France", "Germany", "United Kingdom", "Belgium") }
我們可以通過下面的方法來實現簡單的映射:
from typing import Any def membership_map(s: pd.Series, groups: dict, fillvalue: Any=-1) -> pd.Series: # Reverse & expand the dictionary key-value pairs groups = {x: k for k, v in groups.items() for x in v} return s.map(groups).fillna(fillvalue)
membership_map(countries, groups, fillvalue="other")
很簡單對不對,現在讓我們看一下最關鍵的一行代碼,groups = {x: k for k, v in groups.items() for x in v},這個是我之前提到過的字典推導式:
test = dict(enumerate(("ab", "cd", "xyz"))) {x: k for k, v in test.items() for x in v}7. 壓縮pandas對象
如果你的pandas版本大于0.21.0,那么都可以直接把pandas用壓縮形式寫入,常見的類型有gzip, bz2, zip,這里我們直接用剛才鮑魚的數據集:
abalone.to_json("df.json.gz", orient="records",lines=True, compression="gzip") # 壓縮為gz類型 abalone.to_json("df.json", orient="records", lines=True) #壓縮為json
import os.path os.path.getsize("df.json") / os.path.getsize("df.json.gz") #壓縮大小差了10倍,還是gz更厲害8. 源碼及GitHub地址
這一期為大家總結了很多pandas實用的小技巧,希望大家喜歡
我把這一期的ipynb文件和py文件放到了Github上,大家如果想要下載可以點擊下面的鏈接:
Github倉庫地址: https://github.com/yaozeliang/pandas_share
這一期就到這里啦,希望大家能夠繼續支持我,完結,撒花
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/43390.html
摘要:下面讓我們開始提速假設我們現在的電價是定值,不根據用電時間段來改變,那么中最快的方法那就是采用,這就是一個簡單的矢量化操作示范。它基本是在中運行最快的方式。 Pandas 加速 大家好,今天我們來看有關pandas加速的小技巧,不知道大家在剛剛接觸pandas的時候有沒有聽過如下的說法 pandas太慢了,運行要等半天 其實我想說的是,慢不是pandas的錯,大家要知道pandas本身...
為什么你需要pandas 大家好,今天想和大家分享一下有關pandas的學習新的,我因工作需要,從去年12月開始接觸這個非常好用的包,到現在為止也是算是熟悉了一些,因此發現了它的強大之處,特意想要和朋友們分享,特別是如果你每天和excel打交道,總是需要編寫一些vba函數或者對行列進行groupby啊,merge,join啊之類的,相信我,pandas會讓你解脫的。 好啦,閑話少說,這篇文章的基礎...
摘要:有關字符串基本方法大家好,我又回來了之前的幾期我們已經簡單了解了的基礎操作,但是只要涉及到數據,最常見的就是字符串類型,所以很多時候我們其實都在和字符串打交道,所以今天,我會把我自己總結的,有關字符串的常用方法分享給大家,希望能夠幫到各位小 有關字符串基本方法 大家好,我又回來了! 之前的幾期我們已經簡單了解了pandas的基礎操作,但是只要涉及到數據,最常見的就是String(字符串...
摘要:基于上的我們還可以實現幾個基于的,還是老樣子,先讓我們創建兩個好了,現在我們想要實現兩個的,但是條件是通過的和的這樣我們也可以得到結果。 Merge, Join, Concat 大家好,我有回來啦,這周更新的有點慢,主要是因為我更新了個人簡歷哈哈,如果感興趣的朋友可以去看看哈: 我的主頁 個人認為還是很漂亮的~,不得不說,很多時候老外的設計能力還是很強。 好了,有點扯遠了,這一期我想和...
摘要:主頁暫時下線社區暫時下線知識庫自媒體平臺微博知乎簡書博客園合作侵權,請聯系請抄送一份到特色項目中文文檔和教程與機器學習實用指南人工智能機器學習數據科學比賽系列項目實戰教程文檔代碼視頻數據科學比賽收集平臺,,劍指,經典算法實現系列課本課本描述 【主頁】 apachecn.org 【Github】@ApacheCN 暫時下線: 社區 暫時下線: cwiki 知識庫 自媒體平臺 ...
閱讀 1772·2023-04-25 21:50
閱讀 2419·2019-08-30 15:53
閱讀 767·2019-08-30 13:19
閱讀 2743·2019-08-28 17:58
閱讀 2464·2019-08-23 16:21
閱讀 2700·2019-08-23 14:08
閱讀 1374·2019-08-23 11:32
閱讀 1439·2019-08-22 16:09