Pandas 模組
Pandas 模組
前言
pandas 是Python程式語言的用於數據操縱和分析的軟體庫。特別是,它提供操縱數值表格和時間序列的資料結構和運算操作。
Pandas 套件全名 Panel DataFrame Series,很多人常用熊貓作為暱稱,但實際上命名的意義和緣由與熊貓八竿子打不著關係。Pandas 套件提供了新的資料結構類別 Index、Series、DataFrame 與 Panel(其中 Panel 資料結構類別在 0.20.0 停止開發維護,)扮演著 Python 在資料分析中的「最後一塊拼圖」;當使用者有表格式資料(Tabular data)的運算處理需求時,就可以透過她達成目的,另外她也提供了豐富的表格式資料載入、整併清理、轉換外型與視覺化的函式。
本文 實例 使用 Python Shell 做演示。
大綱
- 安裝
- Pandas 的 Series 資料型態
- 使用串列 list 建立 Series 物件
- 使用 python 字典建立 Series 物件
- 使用 Numpy 的 ndarray 建立 Series 物件
- 建立含索引的 Series 物件
- 使用純量建立 Series 物件
- 列出 Series 物件索引與值
- Series的運算
- DataFrame
- 建立 DataFrame 使用 Series
- 欄位 columns 屬性
- Series 物件的屬性
- 使用元素是字典的串列建立 DataFrame
- 使用字典建立 DataFrame
- index屬性
- 將 columns 欄位當作 DataFrame 物件的 index
- 基本 Pandas 資料分析與處理
- 檔案的輸入與輸出
- Pandas 繪圖
- 時間序列(Time Series)
- 專題 : 鳶尾花
- 專題 : 匯入網頁 stockq 之全球貨幣匯率表格資料
安裝
- 安裝指令 : pip install pandas
- 導入 : import pandas as pd
- 了解版本 : pd.__version__
Pandas 的 Series 資料型態
Series 是一種一維的陣列資料結構,在這個陣列內可以存放整數、浮點數、字串、Python 物件(例如 : 字串 list、字典 dict….) Numpy 的 ndarray,純量....等等。雖然是一維陣列資料,可是看起來卻好像是二維陣列資料,因為一個是索引 index 或稱為 標籤 label,另一個是實際的資料。
Series 結構與 Python 的 list 類似,不過程式設計師可以為 Series 的每個元素自行命名。可以使用 pd.Series() 建立 Series 物件,語法如下:
pandas.Series(data=None, index=None, dtype=None, name=None, options, .....)
使用串列 list 建立 Series 物件
最簡單的建立 Series 物件的方式是在 Data 參數使用串列。
實例 1 : 在 Data 參數使用串列建立 Series 物件 s1 ,然後列出結果。
>>> import pandas as pd >>> s1 = pd.Series([11,22,33,44,55]) >>> s1 0 11 1 22 2 33 3 44 4 55 dtype: int64
我們只有建立 Series 物件 s1 內容,可是列印時看到左邊欄位有系統自建的索引, Pandas 的索引也是從 0 開始計數的,這也是為什麼我們說 Series 是一個一維陣列,可是看起來像二維陣列的原因。有了這個索引,我們可以使用索引存取物件內容。上述最後一個列出 "dtype : int64" 指出資料在 Pandas 是以64位元整數儲存與處理的。
實例 2 : 延續先前 實例 1 ,列出 Series 特定索引內容與修改內容
>>> s1[1] 22 >>> s1[1]=20 >>> s1 0 11 1 20 2 33 3 44 4 55 dtype: int64
使用 python 字典建立 Series 物件
如果我們使用 Python 的字典建立 Series 物件,字典的 鍵(key) 就會被視為 Series 物件的索引,字典的 鍵(key) 的值(value) 就會被視為物件的值。
實例 1 : 使用 python 字典建立 Series 物件同時列出結果。
>>> import pandas as pd
>>> mydict = {'台北':'Taipei','東京':'Tokyo'}
>>> s2 = pd.Series(mydict)
>>> s2
台北 Taipei
東京 Tokyo
dtype: object
使用 Numpy 的 ndarray 建立 Series 物件
實例 1 : 使用 Numpy 的 ndarray 建立 Series 物件同時列出結果
>>> import pandas as pd >>> import numpy as np >>> s3 = pd.Series(np.arange(0,7,2)) >>> s3 0 0 1 2 2 4 3 6 dtype: int32
以上使用 numpy 模組,這也是一個數據科學常用的模組,使用前他需導入此模組
import numpy as np
上述 np.arrange(0,7,2) 可以產生 "0 - 6(=7-1)” 之間的序列,數字每次 增加 2 所以可以得到 (0,2,4,6)。
建立含索引的 Series 物件
目前為止,我們了解在建立 Series 物件時,預設情況索引是從 0 開始計數,若是我們使用字典建立 Series 物件,字典的 鍵(key) 就是索引,其實在建立 Series 物件時,也可以使用 index 參數自行建立索引。
上述有時候也可以用下列方式建立一樣的 Series 物件
實例 1 : 建立索引不是從 0 開始。
>>> import pandas as pd >>> import numpy as np >>> myindex = [3,5,7] >>> price = [100,200,300] >>> s4 = pd.Series(price, index=myindex) >>> s4 3 100 5 200 7 300 dtype: int64
實例 2 : 建立含自訂索引的 Series 物件,同時列出結果。
>>> import pandas as pd >>> fruit = ['Orange', 'Apple', 'Grape'] >>> price = [30, 50, 70] >>> s5 = pd.Series(price, index=fruit) >>> s5 Orange 30 Apple 50 Grape 70 dtype: int64
上述有時候也可以用下列方式建立一樣的 Series 物件。
s5 = pd.Series([30,50,70], index=['Orange', 'Apple', 'Grape'])
由上述讀者應該體會到, Series 物件有一個很大的特色,是可以使用任一方式的索引。
使用純量建立 Series 物件
實例 1 :使用純量建立 Series 物件,同時列出結果
>>> import pandas as pd >>> s6 = pd.Series(9, index=[1,2,3]) >>> s6 1 9 2 9 3 9 dtype: int64
雖然只有一個純量搭配 3 個索引,Pandas 會主動將所有索引值用純量補上。
列出 Series 物件索引與值
從前面實例,可以知道我們可以直接用 print (物件名稱) 列印 Series 物件,其實也可以使用下列方式得到 Series 物件索引。
- obj.values #假設物件名稱是 obj ,Series 物件值
- obj.index #假設物件名稱是 obj ,Series 物件索引值
實例 1 : 列印 Series 物件索引和值
>>> import pandas as pd >>> s5 = pd.Series([30,50,80], index=['Orange', 'Apple', 'Grape']) >>> print(s5.values) [30 50 80] >>> print(s5.index) Index(['Orange', 'Apple', 'Grape'], dtype='object')
Series的運算
Series 運算方式許多和 Numpy 的 ndarray 或是 Python 的串列相同,但有一些擴充更好用的功能。
實例 1 : 可以將切片觀念應用到 Series 物件
>>> import pandas as pd >>> s = pd.Series([0,1,2,3,4,5]) >>> s[2:4] 2 2 3 3 dtype: int64 >>> s[:3] 0 0 1 1 2 2 dtype: int64 >>> s[2:] 2 2 3 3 4 4 5 5 dtype: int64 >>> s[-1:] 5 5 dtype: int64
四則運算與求餘數的觀念也可以應用在 Series 物件。
實例 2 : Series 物件相加
>>> import pandas as pd >>> x = pd.Series([1, 2]) >>> y = pd.Series([3, 4]) >>> x + y 0 4 1 6 dtype: int64
實例 3 : Series 物件相乘
>>> import pandas as pd >>> x = pd.Series([1, 2]) >>> y = pd.Series([3, 4]) >>> x * y 0 3 1 8 dtype: int64
邏輯運算的觀念也可以應用在 Series 物件。
實例 4 : 邏輯運算應用在 Series 物件
>>> import pandas as pd >>> x = pd.Series([1, 5, 9]) >>> y = pd.Series([2, 4, 8]) >>> x > y 0 False 1 True 2 True dtype: bool
實例 5 : Series 物件有相同索引,執行相加應用
>>> import pandas as pd >>> Fruit = ['Orange', 'Apple', 'Grape'] >>> x1 = pd.Series([30,50,80], index=Fruit) >>> x2 = pd.Series([35,55,85], index=Fruit) >>> y = x1 + x2 >>> y Orange 65 Apple 105 Grape 165 dtype: int64
在執行相加時,如果2個索引不相同也可以執行相加,這時不同的索引的索引內容值會填上 NaN(Not a Number) ,可以解釋為非數字或無定義數字。
實例 6 : Series 物件有不相同索引,執行相加應用
>>> import pandas as pd >>> Fruit1 = ['Orange', 'Apple', 'Grape'] >>> Fruit2 = ['Orange', 'Banana', 'Grape'] >>> x1 = pd.Series([30,50,80], index=Fruit1) >>> x2 = pd.Series([25,55,85], index=Fruit2) >>> y = x1 + x2 >>> y Apple NaN Banana NaN Grape 165.0 Orange 55.0 dtype: float64
當索引是非數值而是字串時,可以使用下列方式取得元素內容
實例 7 : Series 的索引是字串,取得元素內容的應用
>>> import pandas as pd >>> Fruit = ['Orange', 'Apple', 'Grape'] >>> x = pd.Series([30,50,80], index=Fruit) >>> print(x['Apple']) 50
我們也可以將純量與 Series 物件做運算,甚至也可以將函數應用在 Series 物件
實例 8 : 將純量與函數應用在 Series 物件上
>>> import pandas as pd >>> Fruit = ['Orange', 'Apple', 'Grape'] >>> x = pd.Series([30,50,80], index=Fruit) >>> print((x+12)*2) Orange 84 Apple 124 Grape 184 dtype: int64
上述有列出 float64 表示模組是使用 64位元的浮點數處理此數據 。
Dataframe
Dataframe 是一種二維的陣列資料結構,邏輯上而言可以視為是類似 Excel 的工作表,在這個二維陣列內可以存放整數、浮點數、字串、 Python 物件(例如 : 字串 list、 字典 dict …) 、Numpy 的 ndarray、純量....等。
可以使用 Dataframe() 建立 Dataframe 物件,語法如下:
pandas.Dataframe(data=None, index=None, dtype=None, name=None)
建立 DataFrame 使用 Series
我們可以使用組合 Series 物件成為二維陣列的 DataFrame。組合的方式是使用:
pandas.concat([Series1,Series2,.....], axis=1)
範例 pythonPandas-01.py : 建立 Beijing Hongkong Singapre 2020-2022年3月平均溫度,成為3個 Series 物件,這裡設定 concat() 方法不設定 axis,結果不是我們預期的。
# pythonPandas-01.py import pandas as pd years = range(2020, 2023) beijing = pd.Series([20, 21, 19], index = years) hongkong = pd.Series([25, 26, 27], index = years) singapore = pd.Series([30, 29, 31], index = years) citydf = pd.concat([beijing, hongkong, singapore]) # 預設axis=0 print(type(citydf)) print(citydf)
執行結果
<class 'pandas.core.series.Series'> 2020 20 2021 21 2022 19 2020 25 2021 26 2022 27 2020 30 2021 29 2022 31 dtype: int64
很明顯上述不是我們的預期經過,concat() 方法組合後, citydf 資料型態仍是 Series 物件,問題出現在使用 concat() 組合 Series 物件時, axis 預設為 0 ,如果將第 7 行改為增加 axis=1 參數即可。
範例 pythonPandas-02.py : 重新設計 pythonPandas-01.py 建立 DataFrame 物件。
# pythonPandas-02.py import pandas as pd years = range(2020, 2023) taipei = pd.Series([20, 21, 19], index = years) hongkong = pd.Series([25, 26, 27], index = years) singapore = pd.Series([30, 29, 31], index = years) citydf = pd.concat([taipei, hongkong, singapore],axis=1) # axis=1 print(type(citydf)) print(citydf)
執行結果
<class 'pandas.core.frame.DataFrame'>
0 1 2
2020 20 25 30
2021 21 26 29
2022 19 27 31
上述結果是我們所要的 DataFrame 物件了。
欄位 columns 屬性
上述 pythonPandas-02.py 的執行結果並不完美,是因為欄位 columns 並沒有名稱,在 pandas 中可以使用 columns 屬性設定欄位名稱。
範例 pythonPandas-03.py : 擴充 pythonPandas-02.py 使用 columns 屬性設定欄位名稱。
# pythonPandas-03.py import pandas as pd years = range(2020, 2023) taipei = pd.Series([20, 21, 19], index = years) hongkong = pd.Series([25, 26, 27], index = years) singapore = pd.Series([30, 29, 31], index = years) citydf = pd.concat([taipei, hongkong, singapore],axis=1) # axis=1 cities = ["Taipei", "HongKong", "Singapore"] citydf.columns = cities print(citydf)
執行結果
Taipei HongKong Singapore 2020 20 25 30 2021 21 26 29 2022 19 27 31
Series 物件的屬性
Series 物件有 name 屬性,我們可以在建立物件時,在 Series() 內建立此屬性,也可以物件建立好了以後再設定此屬性。如果有 name 屬性,列印 Series 物件時,就可以看到此屬性。
實例 1 : 建立 Series 物件時同時建立 name。
>>> import pandas as pd >>> taipei = pd.Series([20,23,19], name='Taipei') >>> taipei 0 20 1 23 2 19 Name: Taipei, dtype: int64
範例 pythonPandas-04.py : 更改 pythonPandas-03.py 設計方式,使用 name 屬性設定 DataFrame 的 columns欄位名稱。
# pythonPandas-04.py import pandas as pd years = range(2020, 2023) taipei = pd.Series([20, 21, 19], index = years) hongkong = pd.Series([25, 26, 27], index = years) singapore = pd.Series([30, 29, 31], index = years) taipei.name = "Taipei" hongkong.name = "HongKong" singapore.name = "Singapore" citydf = pd.concat([taipei, hongkong, singapore],axis=1) print(citydf)
執行結果
Taipei HongKong Singapore 2020 20 25 30 2021 21 26 29 2022 19 27 31
使用元素是字典的串列建立 DataFrame
有一個串列他的元素是字典,可以使用此串列建立 DataFrame
範例 pythonPandas-05.py : 使用元素是字典的串列建立 DataFrame物件
# pythonPandas-05.py
import pandas as pd
data = [{'apple':50,'Orange':30,'Grape':80},{'apple':50,'Grape':80}]
fruits = pd.DataFrame(data)
print(fruits)
執行結果
apple Orange Grape 0 50 30.0 80 1 50 NaN 80
上述如果碰上字典 鍵(key) 沒有對應,該位置將填入NaN。
使用字典建立 DataFrame
一個字典 鍵(key)的值(value) 是串列時,也可以很方便用於建立 DataFrame。
範例 pythonPandas-06.py : 使用字典鍵(key)的值(value) 是串列建立 DataFrame 物件
# pythonPandas-06.py
import pandas as pd
cities = {'country':['Taiwan', 'Japan', 'Singapore'],
'town':['Taipei','Tokyo','Singapore'],
'population':[400, 1600, 600]}
citydf = pd.DataFrame(cities)
print(citydf)
執行結果
country town population 0 Taiwan Taipei 2000 1 Japan Tokyo 1600 2 Singapore Singapore 600
index屬性
對於 DataFrame 物件而言,我們可以使用 index 屬性 設定物件的 row 標籤,例如,若是以 範例 pythonPandas-06.py 這個的執行結果而言,0,1,2 索引就是 row 標籤。
範例 pythonPandas-07.py : 重新設計 範例 pythonPandas-06.py 將 row 標籤改為 first, second, third
# pythonPandas-07.py
import pandas as pd
cities = {'country':['Taiwan', 'Japan', 'Singapore'],
'town':['Taipei','Tokyo','Singapore'],
'population':[400, 1600, 600]}
rowindex = ['first', 'second', 'third']
citydf = pd.DataFrame(cities, index=rowindex)
print(citydf)
執行結果
country town population first Taiwan Taipei 400 second Japan Tokyo 1600 third Singapore Singapore 600
將 columns 欄位當作 DataFrame 物件的 index
另外,以字典方式建立 DataFrame,如果字典內某個元素被當作 index 時,這個元素就不會在 DataFrame 的欄位 columns 上出現
範例 pythonPandas-08.py : 重新設計 範例 pythonPandas-07.py ,這個程式會將 country 當作 index
# pythonPandas-08.py
import pandas as pd
cities = {'country':['Taiwan', 'Japan', 'Singapore'],
'town':['Taipei','Tokyo','Singapore'],
'population':[400, 1600, 600]}
citydf = pd.DataFrame(cities, columns=["town","population"],
index=cities["country"])
print(citydf)
執行結果
town population Taiwan Taipei 400 Japan Tokyo 1600 Singapore Singapore 600
基本 Pandas 資料分析與處理
Series 和 DataFrame 物件建立完成後,下一步就是執行資料分析與處理,pandas 提供許多函數或方法,使用者可以針對此執行許多資料分析與處理。本節將講解基本觀念,讀者若想更進一步學習,可以參考 pandas專門的書籍,或是參考 : pandas 官方網站。
索引參照屬性
本節將說明下列屬性的用法
- at : 使用 index 和 columns 內容取得或設定單一元素內容或陣列內容。
- iat : 使用 index 和 columns 編號取得或設定單一元素內容。
- loc : 使用 index 和 columns 內容取得或設定整個 row 或 columns 資料和陣列內容。
- iloc : 使用index和 columns 編號取得或設定整個 row 或 columns 資料 。
範例 pythonPandas-09.py : 在說明上述屬性用法前,先建立一個 DataFrame 物件,然後用此物件做解說。
# pythonPandas-09.py
import pandas as pd
cities = {'Country':['China','China','Thailand','Japan','Singapore'],
'Town':['Beijing','Shanghai','Bangkok', 'Tokyo','Singapore'],
'Population':[2000, 2300, 900, 1600, 600]}
df = pd.DataFrame(cities, columns=["Town","Population"],
index=cities["Country"])
print(df)
執行結果
Town Population China Beijing 2000 China Shanghai 2300 Thailand Bangkok 900 Japan Tokyo 1600 Singapore Singapore 600
下列是 Python Shell 視窗的執行結果,下列實例請在此視窗執行
實例 1 : 使用 at 屬性 row 是 'japan' 和 column 是 ‘Town’ 並列出結果。
>>> df.at['Japan','Town'] 'Tokyo'
如果觀察,可以看到有 2 個索引,是 "China",如果是這時可以獲得陣列資料可以參考下列實例
實例 2 : 使用屬性 at 取得 row 是 “China” 和 columns 是 "Town" 並列印出結果。
>>> df.at['China','Town'] China Beijing China Shanghai Name: Town, dtype: object
實例 3 : 使用屬性 iat 取得 row 是 “2” 和 columns 是 "0" 並列印出結果。
>>> df.iat[2,0] 'Bangkok'
實例 4 : 使用屬性 loc 取得 row 是 “Singapore” 並列印出結果。
>>> df.loc['Singapore'] Town Singapore Population 600 Name: Singapore, dtype: object
實例 5 : 使用屬性 loc 取得 row 是 “Japan” 和 "Tailand" 並列印出結果。
>>> df.loc[['Japan','Tailand']]
實例 6 : 使用屬性 loc 取得 row 是 “China”:"Tailand",column 是 "Town":”Population” 並列印出結果。
>>> df.loc['China':'Tailand','Town':'Population']
實例 7 : 使用屬性 iloc 取得 row 是 “0” 的資料, 並列印出結果。
>>> df.iloc[0] Town Beijing Population 2000 Name: China, dtype: object
直接索引
除了上節的方法可以取得 DataFrame 物件內容,也可以使用直接索引方式取內容,在此將沿用 範例 pythonPandas-09.py 建立的 DataFrame 物件 df。
實例 1 : 直接取得索引 'Town' 的資料並列出結果。
>>> df['Town'] China Beijing China Shanghai Thailand Bangkok Japan Tokyo Singapore Singapore Name: Town, dtype: object
實例 2 : 取得 column 是 'Town' ,row 是 'Japan' 的資料並列出結果。
>>> df['Town']['Japan'] 'Tokyo'
>>> df[['Town','Population']]
Town Population
China Beijing 2000
China Shanghai 2300
Thailand Bangkok 900
Japan Tokyo 1600
Singapore Singapore 600>>> df[:3]
Town Population
China Beijing 2000
China Shanghai 2300
Thailand Bangkok 900
>>> df[df['Population'] > 1000]
Town Population
China Beijing 2000
China Shanghai 2300
Japan Tokyo 1600四則運算方法
- add() : 加法運算
- sub() : 減法運算
- mul() : 乘法運算
- div() : 除法運算
>>> import pandas as pd >>> s1 = pd.Series([1,2,3]) >>> s2 = pd.Series([4,5,6]) >>> x = s1.add(s2) >>> print(x) 0 5 1 7 2 9 dtype: int64 >>> y = s1.sub(s2) >>> print(y) 0 -3 1 -3 2 -3 dtype: int64
>>> data1 = [{'a':10,'b':20},{'a':30,'b':40}]
>>> df1 = pd.DataFrame(data1)
>>> data2 = [{'a':1,'b':2},{'a':3,'b':4}]
>>> df2 = pd.DataFrame(data2)
>>> x = df1.mul(df2)
>>> print(x)
a b
0 10 40
1 90 160
>>> y = df1.div(df2)
>>> print(y)
a b
0 10.0 10.0
1 10.0 10.0邏輯運算方法
- gt()、lt() : 大於、小於運算
- ge()、le() : 大於或等於、小於或等於運算
- eq()、ne() : 等於、不等於運算
>>> s1 = pd.Series([1,3,9]) >>> s2 = pd.Series([2,4,6]) >>> x = s1.gt(s2) >>> print(x) 0 False 1 False 2 True dtype: bool >>> y = s1.eq(s2) >>> print(y) 0 False 1 False 2 False dtype: bool
Numpy 的函數應用在 Pandas
>>> import numpy as np >>> import pandas as pd >>> s = pd.Series([1,2,3]) >>> x = np.square(s) >>> print(x) 0 1 1 4 2 9 dtype: int64
範例 pythonPandas-10.py : 將 Numpy 的隨機值函數 randint() 應用在建立 DataFrame 物件元素內容,假設有一個課程,第一次 first、第二次 second、和最後一次成績 final 皆是使用隨機數給予,分數介於 60 -99 之間。程式第6行 np.random.randint(60,100,size=(3,3)) 方法可以建立 (3,3) 陣列,每格的的數據是在 60-99 分之間。
# pythonPandas-10.py
import pandas as pd
import numpy as np
name = ['Frank', 'Peter', 'John']
score = ['first', 'second', 'final']
df = pd.DataFrame(np.random.randint(60,100,size=(3,3)),
columns=name,
index=score)
print(df)
執行結果
Frank Peter John first 82 80 69 second 60 96 90 final 98 75 95
NaN 相關的運算
在大數據的資料蒐集中,常常因為執行者的疏忽,漏了收集某一段時間的資料,這些可用 NaN 代替。在先前四則運算,我們沒有對 NaN 的值做運算實例,其實凡與 NaN 作運算所獲得的結果也是 NaN。
>>> s1 = pd.Series([1,np.nan,5]) >>> s2 = pd.Series([np.nan,6,8]) >>> x = s1.add(s2) >>> print(x) 0 NaN 1 NaN 2 13.0 dtype: float64
NaN 的處理
下列是適合處理 NaN 的方法
- dropna() : 將 NaN 刪除,然後傳回新的 Series 和 DataFrame 物件
- fillna(value) : 將 NaN 由特定 value值 取代,然後傳回新的 Series 和DataFrame 物件
- isna() : 判斷是否為 NaN ,如果是傳回 True,如果否傳回 False
- notna() : 判斷是否為 NaN,如果是傳回False,如果否傳回 True
>>> df = pd.DataFrame([[1,2,3],[4,np.nan,6],[7,8,np.nan]])
>>> df
0 1 2
0 1 2.0 3.0
1 4 NaN 6.0
2 7 8.0 NaN
>>> x = df.isna()
>>> print(x)
0 1 2
0 False False False
1 False True False
2 False False True
>>> x = df.notna()
>>> print(x)
0 1 2
0 True True True
1 True False True
2 True True False>>> z = df.fillna(0) >>> print(z) 0 1 2 0 1 2.0 3.0 1 4 0.0 6.0 2 7 8.0 0.0
>>> a = df.dropna() >>> print(a) 0 1 2 0 1 2.0 3.0
>>> b = df.dropna(axis='columns') >>> print(b) 0 0 1 1 4 2 7
幾個簡單的統計函數
cummax(axis=None) : 傳回指定軸累計的最大值
cummin(axis=None) : 傳回指定軸累計的最小值
cumsum(axis=None) : 傳回指定軸累計的總和
max(axis=None) : 傳回指定軸的最大值
min(axis=None) : 傳回指定軸的最小值
sum(axis=None) : 傳回指定軸的總和
mean(axis=None) : 傳回指定軸的平均數
median(axis=None) : 傳回指定軸的中位數
std(axis=None) : 傳回指定軸的標準差
>>> print(df)
Town Population
China Beijing 2000
China Shanghai 2300
Thailand Bangkok 900
Japan Tokyo 1600
Singapore Singapore 600
>>> x = df['Population'].sum()
>>> print(x)
7400
>>> y = df['Population'].cumsum()
>>> print(y)
China 2000
China 4300
Thailand 5200
Japan 6800
Singapore 7400
Name: Population, dtype: int64>>> df['Cum_Population']=y
>>> print(df)
Town Population Cum_Population
China Beijing 2000 2000
China Shanghai 2300 4300
Thailand Bangkok 900 5200
Japan Tokyo 1600 6800
Singapore Singapore 600 7400>>> df['Population'].max() 2300 >>> df['Population'].min() 600
範例 pythonPandas-11.py : 有幾位學生的大學學測分數,請建立此 DataFrame 物件,並列印。
# pythonPandas-11.py
import pandas as pd
course = ['Chinese', 'English', 'Math', 'Natural', 'Society']
chinese = [14, 12, 13, 10, 13]
eng = [13, 14, 11, 10, 15]
math = [15, 9, 12, 8, 15]
nature = [15, 10, 13, 10, 15]
social = [12, 11, 14, 9, 14]
df = pd.DataFrame([chinese, eng, math, nature, social],
columns = course,
index = range(1,6))
print(df)
執行結果
Chinese English Math Natural Society 1 14 12 13 10 13 2 13 14 11 10 15 3 15 9 12 8 15 4 15 10 13 10 15 5 12 11 14 9 14
>>> total = [df.iloc[i].sum() for i in range(0,5)] >>> print(total) [62, 63, 59, 63, 60]
>>> df['Total']=total >>> print(df) Chinese English Math Natural Society Total 1 14 12 13 10 13 62 2 13 14 11 10 15 63 3 15 9 12 8 15 59 4 15 10 13 10 15 63 5 12 11 14 9 14 60
>>> ave = df.mean() >>> print(ave) Chinese 13.8 English 11.2 Math 12.6 Natural 9.4 Society 14.4 Total 61.4 dtype: float64
增加 index
可使用 loc 屬性為 DataFrame 增加平均分數。
實例 1 : 在 df 下方新增一行 Average 平均分數。
>>> df.loc['Average'] = ave
>>> print(df)
Chinese English Math Natural Society Total
1 14.0 12.0 13.0 10.0 13.0 62.0
2 13.0 14.0 11.0 10.0 15.0 63.0
3 15.0 9.0 12.0 8.0 15.0 59.0
4 15.0 10.0 13.0 10.0 15.0 63.0
5 12.0 11.0 14.0 9.0 14.0 60.0
Average 13.8 11.2 12.6 9.4 14.4 61.4刪除 index
實例 1 : 刪除一行 Average 平均分數。
>>> df = df.drop(index=['Average']) >>> print(df) Chinese English Math Natural Society Total 1 14.0 12.0 13.0 10.0 13.0 62.0 2 13.0 14.0 11.0 10.0 15.0 63.0 3 15.0 9.0 12.0 8.0 15.0 59.0 4 15.0 10.0 13.0 10.0 15.0 63.0 5 12.0 11.0 14.0 9.0 14.0 60.0
排序
實例 1 : 將 DataFrame 物件 Total 欄位,從大到小排序。
>>> df = df.sort_values(by='Total', ascending=False) >>> print(df) Chinese English Math Natural Society Total 2 13.0 14.0 11.0 10.0 15.0 63.0 4 15.0 10.0 13.0 10.0 15.0 63.0 1 14.0 12.0 13.0 10.0 13.0 62.0 5 12.0 11.0 14.0 9.0 14.0 60.0 3 15.0 9.0 12.0 8.0 15.0 59.0
實例 2 : 增加名次欄位,然後填入名次(Ranking)。
>>> rank = range(1,6) >>> df['Ranking']=rank >>> print(df) Chinese English Math Natural Society Total Ranking 2 13.0 14.0 11.0 10.0 15.0 63.0 1 4 15.0 10.0 13.0 10.0 15.0 63.0 2 1 14.0 12.0 13.0 10.0 13.0 62.0 3 5 12.0 11.0 14.0 9.0 14.0 60.0 4 3 15.0 9.0 12.0 8.0 15.0 59.0 5
實例 2 中 第1、2名總分相同,應該名次相同都是 第1 名。
實例 3 : 改善相同總分應該相同名次。
>>> for i in range(1,5): if df.iat[i,5] == df.iat[i-1,5]: df.iat[i,6]= df.iat[i-1,6] >>> print(df) Chinese English Math Natural Society Total Ranking 2 13.0 14.0 11.0 10.0 15.0 63.0 1 4 15.0 10.0 13.0 10.0 15.0 63.0 1 1 14.0 12.0 13.0 10.0 13.0 62.0 3 5 12.0 11.0 14.0 9.0 14.0 60.0 4 3 15.0 9.0 12.0 8.0 15.0 59.0 5
實例 4 : 依 index 重新排序,可以使用 sort_index()。
>>> df = df.sort_index() >>> print(df) Chinese English Math Natural Society Total Ranking 1 14.0 12.0 13.0 10.0 13.0 62.0 3 2 13.0 14.0 11.0 10.0 15.0 63.0 1 3 15.0 9.0 12.0 8.0 15.0 59.0 5 4 15.0 10.0 13.0 10.0 15.0 63.0 1 5 12.0 11.0 14.0 9.0 14.0 60.0 4
檔案的輸入與輸出
可以讀取的檔案有許多,例如 : TXT、CSV、JSON、Excel….等,也可以將文件以上述資料格式寫入文件。本節將說明讀寫格式的文件。
寫入 CSV 格式檔案
CSV (Comma Separated Values) 格式是電子表格和數據庫中最常見的輸入、輸出文件格式,每一行 row 是一筆資料 record ,每個資料欄位 column 用 "," 逗號隔開,第一行 row 資料是表頭欄位。
Pandas 可以使用 to_csv() 將 DataFrame 物件寫入 CSV 檔案,語法如下:
to_csv(path=None, sep=',' ,header=True, index=True, encoding=None, ....)
- path : 檔案路徑(名稱)。
- sep : 分隔字元,預設是 ','。
- header : 是否保留 columns,預設是 True。
- index : 是否保留 index,預設是 True。
- encoding : 檔案編碼方式。
範例 pythonPandas-12.py : 將 範例 pythonPandas-11.py 所建立的 DataFrame 物件,用有保留 header 和 index 方式儲存至 output-pythonPandas-12a.csv ,然後用沒有保留方式存入 output-pythonPandas-12b.csv。
# pythonPandas-12.py
import pandas as pd
course = ['Chinese', 'English', 'Math', 'Natural', 'Society']
chinese = [14, 12, 13, 10, 13]
eng = [13, 14, 11, 10, 15]
math = [15, 9, 12, 8, 15]
nature = [15, 10, 13, 10, 15]
social = [12, 11, 14, 9, 14]
df = pd.DataFrame([chinese, eng, math, nature, social],
columns = course,
index = range(1,6))
df.to_csv("output-pythonPandas-12a.csv")
df.to_csv("output-pythonPandas-12b.csv", header=False, index=False)
執行結果
讀取CSV格式檔案
Pandas 可以使用 read_csv() 讀取 CSV 檔案,也可以讀取 TXT檔案,他的語法如下:
read_csv(path=None, sep=',' ,header=True, index_col=None, name=None, encoding=None, userrows=None, usecols=None, ....)
- path : 檔案路徑(名稱)。
- sep : 分隔元素,預設是 ','。
- header : 設定哪一個 row 為欄位標籤,預設是 0,當參數有 name 時,此為 None。如果所讀取的檔案有欄位標籤時,就需要設定此 header 值。
- index : 指出第幾個欄位 column 是索引,預設是 None。
- encoding : 檔案編碼方式。
- nrows : 設定讀取前幾 row。
- usecols : 設定讀取哪幾欄位。
範例 pythonPandas-13.py : 分別讀取所建立的 CSV 檔案,然後列印。
# pythonPandas-13.py
import pandas as pd
course = ['Chinese', 'English', 'Math', 'Natural', 'Society']
x = pd.read_csv("out4_12a.csv",index_col=0)
y = pd.read_csv("out4_12b.csv",names=course)
print(x)
print(y)
執行結果
Chinese English Math Natural Society 1 14 12 13 10 13 2 13 14 11 10 15 3 15 9 12 8 15 4 15 10 13 10 15 5 12 11 14 9 14 Chinese English Math Natural Society 0 14 12 13 10 13 1 13 14 11 10 15 2 15 9 12 8 15 3 15 10 13 10 15 4 12 11 14 9 14
Pandas繪圖
Pandas 內有許多繪圖函數,最常使用的是 plot(),我們可以使用它為 Series 和 DataFrame 物件繪圖。基本上這是 Pandas 模組將 matplotlib.pyplot 包裝起來的一個繪圖方法,所以程式設計時需要這個 plot(), 基本語法如下:
plot(x=None, Y=None, kind='xx',title=None, legend=True, rot=None....)
- kind : 是選擇繪圖模式,預設是 line。常見的選項有 bar、barth、hist、box、scatter.....等。
- rot : 是旋轉刻度。
使用 Series 畫折線圖表
範例 pythonPandas-14.py : 建立一個 Series 物件 tw,是紀錄 1950到2010年間,每隔10年台灣人口的數據,單位是萬人。
# pythonPandas-14.py
import pandas as pd
import matplotlib.pyplot as plt
population = [860, 1100, 1450, 1800, 2020, 2200, 2260]
tw = pd.Series(population, index=range(1950, 2011, 10))
tw.plot(title='Population in Taiwan')
plt.xlabel("Year")
plt.ylabel("Population")
plt.show()
執行結果
使用 DataFrame 繪圖表基本知識
範例 pythonPandas-15.py : 設計一個世界大城市的人口圖,製作 DataFrame 物件,然後繪製圖表。
# pythonPandas-15.py
import pandas as pd
import matplotlib.pyplot as plt
cities = {'population':[1000, 850, 800, 1500, 600, 800],
'town':['New York','Chicago','Bangkok','Tokyo',
'Singapore','HongKong']}
tw = pd.DataFrame(cities, columns=['population'],index=cities['town'])
tw.plot(title='Population in the World')
plt.xlabel('City')
plt.ylabel("Population")
plt.show()
執行結果
直條圖的設計
我們也可以使用適當的 kind 參數,更改不同的圖表設計。範例 pythonPandas-16.py : 使用直條圖重新設計程式實例 pythonPandas-15.py。
# pythonPandas-15.py
import pandas as pd
import matplotlib.pyplot as plt
cities = {'population':[1000, 850, 800, 1500, 600, 800],
'town':['New York','Chicago','Bangkok','Tokyo',
'Singapore','HongKong']}
tw = pd.DataFrame(cities, columns=['population'],index=cities['town'])
tw.plot(title='Population in the World')
plt.xlabel('City')
plt.ylabel("Population")
plt.show()
執行結果
調整過後
一個圖表含不同數值資料
我們也可以使用一張圖表建立多個數值資料,例如 : 下列是增加城市面積的數據實例。
範例 pythonPandas-17.py : 擴充 DataFrame ,增加城市面積資料(平方公里)。
# pythonPandas-15.py
import pandas as pd
import matplotlib.pyplot as plt
cities = {'population':[1000, 850, 800, 1500, 600, 800],
'town':['New York','Chicago','Bangkok','Tokyo',
'Singapore','HongKong']}
tw = pd.DataFrame(cities, columns=['population'],index=cities['town'])
tw.plot(title='Population in the World')
plt.xlabel('City')
plt.ylabel("Population")
plt.show()執行結果
在上述程式設計中,將人口數的單位設為"萬",如果我們在程式設計中填入實際人數,若是重新設計上述程式,因為面積與人口數相差太大,將造成面積的資料無法正常顯示。
範例 pythonPandas-18.py : 將人口單位數將為"人",重新設計 pythonPandas-17.py。
# pythonPandas-18.py
import pandas as pd
import matplotlib.pyplot as plt
cities = {'population':[10000000,8500000,8000000,15000000,6000000,8000000],
'area':[400, 500, 850, 300, 200, 320],
'town':['New York','Chicago','Bangkok','Tokyo',
'Singapore','HongKong']}
tw = pd.DataFrame(cities, columns=['population','area'],index=cities['town'])
tw.plot(title='Population in the World')
plt.xlabel('City')
plt.show()
執行結果
若是要解決這類問題,建議是增加數值軸,可以參考下一小節。
多個數值軸的設計
這時需又要使用 subplots() ,可以在一個圖表內顯示多組不同軸的數據。
程式第11行,內容如下:
fig, ax = plt.subplots() # fig 是整個圖表物件,ax 是第一個軸
程式第16行,使用 twinx() 可以建立第2個數值軸,內容如下:
ax2 = ax.twinx() # 使用 twinx() 可以建立第2個數值軸 ax2
範例 pythonPandas-19.py : 使用第2軸的觀念,重新設計 範例 pythonPandas-18.py。
# pythonPandas-19.py
import pandas as pd
import matplotlib.pyplot as plt
cities = {'population':[10000000,8500000,8000000,15000000,6000000,8000000],
'area':[400, 500, 850, 300, 200, 320],
'town':['New York','Chicago','Bangkok','Tokyo',
'Singapore','HongKong']}
tw = pd.DataFrame(cities, columns=['population','area'],index=cities['town'])
fig, ax = plt.subplots() # fig 是整個圖表物件,ax 是第一個軸
fig.suptitle("City Statistics")
ax.set_ylabel("Population")
ax.set_xlabel("City")
ax2 = ax.twinx() # 使用 twinx() 可以建立第2個數值軸 ax2
ax2.set_ylabel("Area")
tw['population'].plot(ax=ax,rot=90) # 繪製人口數線
tw['area'].plot(ax=ax2, style='g-') # 繪製面積線
ax.legend(loc=1) # 圖例位置在右上
ax2.legend(loc=2) # 圖例位置在左上
plt.show()
執行結果
範例 pythonPandas-20.py : 重新設計 範例 pythonPandas-19.py,在左側 y 軸不用科學記號表示人口數,此例 第15行增加下列
ax.ticklabel_format(style='plain') # 不用科學記號表示
# pythonPandas-20.py
import pandas as pd
import matplotlib.pyplot as plt
cities = {'population':[10000000,8500000,8000000,15000000,6000000,8000000],
'area':[400, 500, 850, 300, 200, 320],
'town':['New York','Chicago','Bangkok','Tokyo',
'Singapore','HongKong']}
tw = pd.DataFrame(cities, columns=['population','area'],index=cities['town'])
fig, ax = plt.subplots()
fig.suptitle("City Statistics")
ax.set_ylabel("Population")
ax.set_xlabel("City")
ax.ticklabel_format(style='plain') # 不用科學記號表示
ax2 = ax.twinx()
ax2.set_ylabel("Area")
tw['population'].plot(ax=ax,rot=90) # 繪製人口數線
tw['area'].plot(ax=ax2, style='g-') # 繪製面積線
ax.legend(loc=1) # 圖例位置在右上
ax2.legend(loc=2) # 圖例位置在左上
plt.show()執行結果
使用 Series 物件設計圓餅圖
繪製圓餅圖可以使用 plot.pie() ,常用的語法如下:
pie(x, options, …..)
x 是一個串列,主要是圓餅圖 X 軸的資料,options 代表系列選擇性參數,可以是下列參數內容:
- label : 圓餅圖項目所組成的串列。
- colors : 圓餅圖項目顏色所組成的串列,如果省略則用預設顏色。
- explode : 可設定是否從圓餅圖分離的串列,0 表示不分離。一般可用 0.1,分離數值越大分離越遠,例如在程式實例 pythonPandas-21.py 中可改用 0.2 測試,效果不同,預設是 0。
- autopct : 表示項目的百分比格式,基本語法是 "%格式%%",例如 : "%2.2%%",表示正數2位數,小數2位數。
- labeldistance : 項目標題與圓餅圖中心的距離是半徑的多少倍,例如 1.2 代表是 1.2 倍。
- center : 圓中心座標,預設是 0。
- shadow : True 表示圓餅圖形有陰影,False 表示圓餅圖形沒有陰影,預設是 False。
範例 pythonPandas-21.py : 使用 Series 物件繪製圓餅圖。
# pythonPandas-21.py
import pandas as pd
import matplotlib.pyplot as plt
fruits = ['Apples', 'Bananas', 'Grapes', 'Pears', 'Oranges']
s = pd.Series([2300, 5000, 1200, 2500, 2900], index=fruits,
name='Fruits Shop')
explode = [0.4, 0, 0, 0.2, 0]
s.plot.pie(explode = explode, autopct='%1.2f%%')
plt.show()
執行結果
時間序列(Time Series)
時間序列是指一系列的數據是依時間次序列出來,時間是指一系列的時間戳記 (timestamp) ,這些時間戳記是相等間隔的時間點。音樂MP3文件或是一些聲音文件,其實就是時間序列的應用,因為音頻會依時間序列排成數據點,將這些數據點視覺化,就可以組成音樂波形。這一節先介紹 Python的 datetime 模組,將它應用在 Series 物件,建立時間序列,然後再介紹 Pandas 處理時間序列的工具。
時間模組 datetime
這一節將講解一個時間模組 datatime,在使用前需導入此模組
from datatime import datatime
datetime 模組的資料型態 datetime
datetime 模組內有一個資料型態 datetime,可以用它代表一個特定時間,有一個 now() 方法可以列出現在時間。
範例 pythonPandas-22.py : 列出現在時間。
# pythonPandas-22.py
from datetime import datetime
timeNow = datetime.now()
print(type(timeNow))
print("現在時間 : ", timeNow)
執行結果
<class 'datetime.datetime'> 現在時間 : 2021-10-07 12:14:08.031411
我們也可以使用屬性 year、month、day、hour、minuts、second、microsecond(百萬分之一秒),獲得上述時間的個別內容。
範例 pythonPandas-23.py : 列出時間的個別內容。
# pythonPandas-23.py
from datetime import datetime
timeNow = datetime.now()
print(type(timeNow))
print("現在時間 : ", timeNow)
print("年 : ", timeNow.year)
print("月 : ", timeNow.month)
print("日 : ", timeNow.day)
print("時 : ", timeNow.hour)
print("分 : ", timeNow.minute)
print("秒 : ", timeNow.second)
執行結果
<class 'datetime.datetime'> 現在時間 : 2021-10-07 12:22:48.237163 年 : 2021 月 : 10 日 : 7 時 : 12 分 : 22 秒 : 48
設定特定時間
當你了解了獲得現在時間的方法後,其實可以用下列方法設定一個特定時間。
xtime = datatime.datetime(年, 月, 日, 時, 分, 秒)
上述 xtime 就是一個特定時間。
範例 pythonPandas-24.py : 設定程式迴圈執行到 2019年3月11日22點271分0秒將甦醒停止列印 program is sleeping,然後列印 Wake up。
# pythonPandas-24.py
from datetime import datetime
timeStop = datetime(2021,10,7,12,33,0)
while datetime.now() < timeStop:
print("Program is sleeping.", end="")
print("Wake up")
執行結果
Program is sleeping.Program is sleeping. Program is sleeping.Program is sleeping. Program is sleeping.Program is sleeping. Program is sleeping.Program is sleeping. Program is sleeping.Program is sleeping. Program is sleeping.Program is sleeping. Wake up
一段時間 timedelta
這是 timedelta 的資料型態,代表一段時間,可以用下列方式表示
deltatime = datetime.timedelta(weeks=xx, days=xx, hours=xx, minutes=xx, seconds=xx)
上述 xx 代表設定的單位數
一段時間 物件只有三個屬性, days 代表日數, seconds 代表秒數, microseconds 代表百萬分之一秒。
範例 pythonPandas-25.py : 列印出伊甸時間的日數、秒數、百萬分之一秒數。
# pythonPandas-25.py from datetime import datetime, timedelta deltaTime = timedelta(days=3,hours=5,minutes=8,seconds=10) print(deltaTime.days, deltaTime.seconds, deltaTime.microseconds)
執行結果
3 18490 0
上述5小時8分10秒,被總計為18940秒。另有一個方法, total_second() 可以將一段時間轉為秒數。
範例 pythonPandas-26.py : 重新設計 範例 pythonPandas-25.py ,將一段時間轉為秒數。
# pythonPandas-26.py from datetime import datetime, timedelta deltaTime = timedelta(days=3,hours=5,minutes=8,seconds=10) print(deltaTime.total_seconds())
執行結果
277690.0
使用 Python 的 datetime 模組建立含時間戳記的Series物件
對於時間序列( Time Series ) 而言,基本上就是將索引( index )用日期取代。
範例 pythonPandas-27.py : 使用 datetime 建立含 5 天的 Series 物件和列印,這五天是使用串列 [34, 44, 65, 53, 39] 同時列出時間序列物件的數據型態,以及時間序列的索引 index。
# pythonPandas-27.py import pandas as pd from datetime import datetime, timedelta ndays = 5 start = datetime(2019, 3, 11) dates = [start + timedelta(days=x) for x in range(0, ndays)] data = [34, 44, 65, 53, 39] ts = pd.Series(data, index=dates) print(type(ts)) print(ts) print(ts.index)
執行結果
<class 'pandas.core.series.Series'>
2019-03-11 34
2019-03-12 44
2019-03-13 65
2019-03-14 53
2019-03-15 39
dtype: int64
DatetimeIndex(['2019-03-11', '2019-03-12', '2019-03-13', '2019-03-14',
'2019-03-15'],
dtype='datetime64[ns]', freq=None)
時間序列使允許相同索引執行加法或代數運算。
範例 pythonPandas-28.py : 擴充 範例 pythonPandas-27.py ,建立相同時間戳記的 Series 物件,然後計算兩個 Series 物件的相加與計算平均。
# pythonPandas-28.py
import pandas as pd
from datetime import datetime, timedelta
ndays = 5
start = datetime(2019, 3, 11)
dates = [start + timedelta(days=x) for x in range(0, ndays)]
data1 = [34, 44, 65, 53, 39]
ts1 = pd.Series(data1, index=dates)
data2 = [34, 44, 65, 53, 39]
ts2 = pd.Series(data2, index=dates)
addts = ts1 + ts2
print("ts1+ts2")
print(addts)
meants = (ts1 + ts2)/2
print("(ts1+ts2)/2")
print(meants)
執行結果
ts1+ts2 2019-03-11 68 2019-03-12 88 2019-03-13 130 2019-03-14 106 2019-03-15 78 dtype: int64 (ts1+ts2)/2 2019-03-11 34.0 2019-03-12 44.0 2019-03-13 65.0 2019-03-14 53.0 2019-03-15 39.0 dtype: float64
範例 pythonPandas-29.py : 重新設計 範例 pythonPandas-28.py ,執行兩個 Series 物件相加,但是部分時間戳記是不同。
# pythonPandas-29.py
import pandas as pd
from datetime import datetime, timedelta
ndays = 5
start = datetime(2019, 3, 11)
dates1 = [start + timedelta(days=x) for x in range(0, ndays)]
data1 = [34, 44, 65, 53, 39]
ts1 = pd.Series(data1, index=dates1)
dates2 = [start - timedelta(days=x) for x in range(0, ndays)]
data2 = [34, 44, 65, 53, 39]
ts2 = pd.Series(data2, index=dates2)
addts = ts1 + ts2
print("ts1+ts2")
print(addts)
執行結果
ts1+ts2 2019-03-07 NaN 2019-03-08 NaN 2019-03-09 NaN 2019-03-10 NaN 2019-03-11 68.0 2019-03-12 NaN 2019-03-13 NaN 2019-03-14 NaN 2019-03-15 NaN Freq: D, dtype: float64
Pandas 的時間區間方法
Pandas 的 date_range() 可以產生時間區間,我們可以更方便的將此方法應用在前一小節的程式上。
範例 pythonPandas-30.py : 重新設計 範例 pythonPandas-27.py ,使用 date_range()。
# pythonPandas-30.py
import pandas as pd
dates = pd.date_range('3/11/2019', '3/15/2019')
data = [34, 44, 65, 53, 39]
ts = pd.Series(data, index=dates)
print(type(ts))
print(ts)
print(ts.index)
執行結果
<class 'pandas.core.series.Series'>
2019-03-11 34
2019-03-12 44
2019-03-13 65
2019-03-14 53
2019-03-15 39
Freq: D, dtype: int64
DatetimeIndex(['2019-03-11', '2019-03-12', '2019-03-13', '2019-03-14',
'2019-03-15'],
dtype='datetime64[ns]', freq='D')
基本上與 範例 pythonPandas-27.py 相同,但是多了註明 “Freq : D”, 表示索引是日期。如果這時我們輸入 ts.index 也將獲得一樣的結果。
上述我們使用 date_range() 方法時,是放了起始日期與終止日期,我們也可以用起始日期(start=)再加上期間(periods=),或是終止日期(end=)再加上期間(periods=)設定時間戳記。
實例 1 : 使用起始日期,加上期間設定時間索引。
>>> import pandas as pd
>>> dates = pd.date_range(start='2021-10-07', periods=5)
>>> dates
DatetimeIndex(['2021-10-07', '2021-10-08', '2021-10-09', '2021-10-10',
'2021-10-11'],
dtype='datetime64[ns]', freq='D')實例 2 : 使用終止日期,加上期間設定時間索引。
>>> dates = pd.date_range(end='2021-10-15', periods=5)
>>> dates
DatetimeIndex(['2021-10-11', '2021-10-12', '2021-10-13', '2021-10-14',
'2021-10-15'],
dtype='datetime64[ns]', freq='D')此外在設定 date_range() 時,若是參數 "freq=" 設定為 "B",可議讓時間索引只包含工作天(work day),相當於週六週日不包含在時間索引內。
實例 3 : 設定 '2021-10-01' 到 '2021-10-10' 時間索引,參數 freq='B' 並觀察執行結果。
>>> dates = pd.date_range('2021-10-01', '2021-10-10', freq='B')
>>> dates
DatetimeIndex(['2021-10-01', '2021-10-04', '2021-10-05', '2021-10-06',
'2021-10-07', '2021-10-08'],
dtype='datetime64[ns]', freq='B')由於 2021-10-01是週六,2021-10-02是週日,所以皆不在時間索引內。若是設定 freq='M' 代表時間索引是兩個時間點之間的月底。
實例 4 : 參數 freq='M' 並觀察執行結果。
>>> dates = pd.date_range('2021-8-01', '2021-10-10', freq='M')
>>> dates
DatetimeIndex(['2021-08-31', '2021-09-30'], dtype='datetime64[ns]', freq='M')也可以使用 freq='W-Mon',Mon 是週一的縮寫,2個時間點之間,代表每週一皆是時間索引,可以應用在其他日。
實例 5 : 參數 freq='W-Mon' 並觀察執行結果。
>>> dates = pd.date_range('2021-10-01', '2021-10-31', freq='W-Mon')
>>> dates
DatetimeIndex(['2021-10-04', '2021-10-11', '2021-10-18', '2021-10-25'], dtype='datetime64[ns]', freq='W-MON')其他常用的 freq 設定如下
- A : 年末
- AS : 年初
- Q : 季末
- QS : 季初
- H : 小時
- T : 分鐘
- S : 秒
專題 鳶尾花
進入 iris.data 下載資料集 後將看到下列部分內容:
總共有150筆資料,在這資料集中總共有五個欄位,左到右分別代表意義如下:
- 花萼長度( sepal length )
- 花萼寬度( sepal width )
- 花瓣長度( petal length )
- 花瓣寬度( petal width )
- 鳶尾花類別 (species, 有setosa、versicolor、virginica)
網路爬蟲
由鳶尾花資料及網頁可以發現此網頁內容非常單純,沒有其他 HTML 標籤,所以可以直接讀取然後儲存。
範例 pythonPandas-31.py : 讀取加州大學鳶尾花資料集網頁,然後將此資料集儲存成 iris.csv。
# pythonPandas-31.py
import requests
url = 'http://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data'
try:
htmlfile = requests.get(url) # 將檔案下載至htmlfile
print('下載成功')
except Exception as err:
print('下載失敗')
fileName = 'iris.csv' # 未來儲存鳶尾花的檔案
with open(fileName, 'wb') as fileobj: # 開啟iris.csv
for diskstorage in htmlfile.iter_content(10240):
size = fileobj.write(diskstorage) # 寫入
執行結果
下載成功
下載成功後,可以在目前工作目錄中發現 iris.csv 檔案,開啟後可看到如下結果:
上述的第13行,用 for 迴圈一次寫入10240 位元組資料,直到全部寫入完成。
鳶尾花資料集轉成 DataFrame
範例 pythonPandas-32.py : 讀取 iris.csv,為此資料集加上欄位名稱,然後列出此資料集的長度和內容。
# pythonPandas-32.py
import pandas as pd
colName = ['sepal_len','sepal_wd','petal_len','petal_wd','species']
iris = pd.read_csv('iris.csv', names = colName)
print('資料集長度 : ', len(iris))
print(iris)
執行結果
資料集長度 : 150
sepal_len sepal_wd petal_len petal_wd species
0 5.1 3.5 1.4 0.2 Iris-setosa
1 4.9 3.0 1.4 0.2 Iris-setosa
2 4.7 3.2 1.3 0.2 Iris-setosa
3 4.6 3.1 1.5 0.2 Iris-setosa
4 5.0 3.6 1.4 0.2 Iris-setosa
.. ... ... ... ... ...
145 6.7 3.0 5.2 2.3 Iris-virginica
146 6.3 2.5 5.0 1.9 Iris-virginica
147 6.5 3.0 5.2 2.0 Iris-virginica
148 6.2 3.4 5.4 2.3 Iris-virginica
149 5.9 3.0 5.1 1.8 Iris-virginica
[150 rows x 5 columns]
建立好上述 DataFrame 後,也可以使用 describe() 獲得數據的數量、均值、標準差、最小、最大、各分位數的值。
實例 1 : 使用 describe() 列出 iris 的相關數據
>>> iris.describe()
sepal_len sepal_wd petal_len petal_wd
count 150.000000 150.000000 150.000000 150.000000
mean 5.843333 3.054000 3.758667 1.198667
std 0.828066 0.433594 1.764420 0.763161
min 4.300000 2.000000 1.000000 0.100000
25% 5.100000 2.800000 1.600000 0.300000
50% 5.800000 3.000000 4.350000 1.300000
75% 6.400000 3.300000 5.100000 1.800000
max 7.900000 4.400000 6.900000 2.500000散點圖的製作
範例 pythonPandas-33.py : 繪製 (Sepal Length, Sepal Width) 之散點圖。
# pythonPandas-33.py
import pandas as pd
import matplotlib.pyplot as plt
colName = ['sepal_len','sepal_wd','petal_len','petal_wd','species']
iris = pd.read_csv('iris.csv', names = colName)
iris.plot(x='sepal_len',y='sepal_wd',kind='scatter')
plt.xlabel('Sepal Length')
plt.ylabel('Sepal Width')
plt.title('Iris Sepal length and width anslysis')
plt.show()
執行結果
範例 pythonPandas-34.py : 修改 範例 pythonPandas-33.py 第8行, 使用 plot() 方式完成不同顏色和點標記。
# pythonPandas-34.py
import pandas as pd
import matplotlib.pyplot as plt
colName = ['sepal_len','sepal_wd','petal_len','petal_wd','species']
iris = pd.read_csv('iris.csv', names = colName)
plt.plot(iris['sepal_len'],iris['sepal_wd'],'*',color='g')
plt.xlabel('Sepal Length')
plt.ylabel('Sepal Width')
plt.title('Iris Sepal length and width anslysis')
plt.show()
執行結果
對於這類資料分析而言,我們可能想要了解各品種鳶尾花的的花萼長度與寬度之間的關係,其實我們需要將鳶尾花資料集依據品種先分離然後將不同品種的鳶尾花會在同一個圖表上這樣就可以一目了然下列是將不同品種的鳶尾花擷取出來的方法。
實例 1 : 延續先前實例,擷取品種是 versicolor 的鳶尾花
>>> iris_versicolor = iris[iris['species'] == 'Iris-versicolor']
sepal_len sepal_wd petal_len petal_wd species
50 7.0 3.2 4.7 1.4 Iris-versicolor
51 6.4 3.2 4.5 1.5 Iris-versicolor
52 6.9 3.1 4.9 1.5 Iris-versicolor
53 5.5 2.3 4.0 1.3 Iris-versicolor
54 6.5 2.8 4.6 1.5 Iris-versicolor
55 5.7 2.8 4.5 1.3 Iris-versicolor
..............
範例 pythonPandas-35.py : 將不同的鳶尾花的花萼是用不同的標記繪製散點圖
# pythonPandas-35.py
import pandas as pd
import matplotlib.pyplot as plt
colName = ['sepal_len','sepal_wd','petal_len','petal_wd','species']
iris = pd.read_csv('iris.csv', names = colName)
# 擷取不同品種的鳶尾花
iris_setosa = iris[iris['species'] == 'Iris-setosa']
iris_versicolor = iris[iris['species'] == 'Iris-versicolor']
iris_virginica = iris[iris['species'] == 'Iris-virginica']
# 繪製散點圖
plt.plot(iris_setosa['sepal_len'],iris_setosa['sepal_wd'],
'*',color='g',label='setosa')
plt.plot(iris_versicolor['sepal_len'],iris_versicolor['sepal_wd'],
'x',color='b',label='versicolor')
plt.plot(iris_virginica['sepal_len'],iris_virginica['sepal_wd'],
'.',color='r',label='virginica')
# 標註軸和標題
plt.xlabel('Sepal Length')
plt.ylabel('Sepal Width')
plt.title('Iris Sepal length and width anslysis')
plt.legend()
plt.show()
執行結果
鳶尾花分類統計與直條圖
如果我們想要獲得不同品種鳶尾花的花瓣與花蕊的均值直條圖,首先須計算統計不同品種鳶尾花的資料,這樣可以使用 groupby() 的方法
實例 1 : 延續先前實例,統計不同品種鳶尾花的花萼與花瓣的長與寬。
>>> iris_mean = iris.groupby('species', as_index=False).mean()
species sepal_len sepal_wd petal_len petal_wd
0 Iris-setosa 5.006 3.418 1.464 0.244
1 Iris-versicolor 5.936 2.770 4.260 1.326
2 Iris-virginica 6.588 2.974 5.552 2.026
範例 pythonPandas-36.py : 以均值和直條圖方式繪製不同品種花萼與花瓣長與寬
# pythonPandas-36.py
import pandas as pd
import matplotlib.pyplot as plt
colName = ['sepal_len','sepal_wd','petal_len','petal_wd','species']
iris = pd.read_csv('iris.csv', names = colName)
# 鳶尾花分組統計均值
iris_mean = iris.groupby('species', as_index=False).mean()
# 繪製直條圖
iris_mean.plot(kind='bar')
# 刻度處理
plt.xticks(iris_mean.index,iris_mean['species'], rotation=0)
plt.show()
執行結果
範例 pythonPandas-37.py : 重新設計 範例 pythonPandas-36.py ,將 x 軸 的品種前方字串 "iris-" 刪除,修改第7行程式碼 : iris['species'] = iris['species'].apply(lambda x: x.replace("Iris-",""))
# pythonPandas-37.py
import pandas as pd
import matplotlib.pyplot as plt
colName = ['sepal_len','sepal_wd','petal_len','petal_wd','species']
iris = pd.read_csv('iris.csv', names = colName)
iris['species'] = iris['species'].apply(lambda x: x.replace("Iris-",""))
# 鳶尾花分組統計均值
iris_mean = iris.groupby('species', as_index=False).mean()
# 繪製直條圖
iris_mean.plot(kind='bar')
# 刻度處理
plt.xticks(iris_mean.index,iris_mean['species'], rotation=0)
plt.show()
執行結果
我們也可以使用堆疊方式處理上述長條圖,方法是在 plot() 方法中增加 "stacked=True"。
範例 pythonPandas-38.py : 重新設計 範例 pythonPandas-37.py ,但是使用堆疊方式處裡數據,修改第11行程式碼 : iris_mean.plot(kind='bar',stacked=True)
# pythonPandas-38.py
import pandas as pd
import matplotlib.pyplot as plt
colName = ['sepal_len','sepal_wd','petal_len','petal_wd','species']
iris = pd.read_csv('iris.csv', names = colName)
iris['species'] = iris['species'].apply(lambda x: x.replace("Iris-",""))
# 鳶尾花分組統計均值
iris_mean = iris.groupby('species', as_index=False).mean()
# 繪製堆疊直條圖
iris_mean.plot(kind='bar',stacked=True)
# 刻度處理
plt.xticks(iris_mean.index,iris_mean['species'], rotation=0)
plt.show()
執行結果
直條圖與橫條圖,差別是 "bar" 與 "barh",參考以下範例。
範例 pythonPandas-39.py : 重新設計 範例 pythonPandas-38.py ,將直條圖改為橫條圖,修改第11行程式碼 :iris_mean.plot(kind='barh',stacked=True),第13行程式碼 : plt.yticks(iris_mean.index,iris_mean['species'], rotation=0)
# pythonPandas-39.py
import pandas as pd
import matplotlib.pyplot as plt
colName = ['sepal_len','sepal_wd','petal_len','petal_wd','species']
iris = pd.read_csv('iris.csv', names = colName)
iris['species'] = iris['species'].apply(lambda x: x.replace("Iris-",""))
# 鳶尾花分組統計均值
iris_mean = iris.groupby('species', as_index=False).mean()
# 繪製堆疊橫條圖
iris_mean.plot(kind='barh',stacked=True)
# 刻度處理
plt.yticks(iris_mean.index,iris_mean['species'], rotation=0)
plt.show()
執行結果
專題 匯入網頁表格資料
Pandas模組有一個匯入網頁資料的方法,如下所示:
- read_html(‘url’)
我們可以使用這種方式將網頁的表格資料匯入 Python 程式,再轉成 Pandas 的 DataFrame。在股票和基金市場有個很有名的網站,stockq。
進入此網站請先點選市場動態 => 再點選全球匯率行情,可以看到下列網頁內容
接下來將一步一步分析,將上述全球貨幣匯率表格轉成 Pandas 的 DataFrame資料。
範例 pythonPandas-40.py : 使用 Pandas 的 read_html(‘url’) 讀取全球貨幣匯率表格。
# pythonPandas-40.py import pandas as pd url = 'http://www.stockq.org/market/currency.php' currencys = pd.read_html(url) print(type(currencys)) # 列出資料型態 print(currencys) # 列出匯率的串列內容
執行結果
<class 'list'> [ 0 0 google_ad_client = "ca-pub-9803646600609510"; ..., 0 0 google_ad_client = "ca-pub-9803646600609510"; ... 1 首頁 市場動態 歷史股價 基金淨值 基金分類 經濟數據總覽 2021行事曆 期貨報告 加..., 0 1 0 NaN google_ad_client = "ca-pub-9803646600609510"; ..., 0 1 0 首頁 市場動態 歷史股價 基金淨值 基金分類 經濟數據總覽 2021行事曆 期貨報告 加... 简体中文,
由上述可以看到我們只用第 4-5 行,就可以讀取的全球匯率行情的資料,同時從第 7 行可以知道,所讀取的資料是 串列(list) 資料型態。從上述可以看到列表內,除了表格還有一系列元素資料,為了可以獲得表格真正的元素位置,我們可以使用下列方式更進一步分析。
範例 pythonPandas-41.py : 列出全球匯率網頁的元素內容,一個元素一個元素列印。
# pythonPandas-41.py
import pandas as pd
url = 'http://www.stockq.org/market/currency.php'
currencys = pd.read_html(url) # 讀取全球匯率行情表
item = 0
for currency in currencys:
print("元素 : ", item) # 列出元素編號
print(currency) # 列出元素內容
print()
item += 1
執行結果
元素 : 0
0
0 google_ad_client = "ca-pub-9803646600609510"; ...
元素 : 1
0
0 google_ad_client = "ca-pub-9803646600609510"; ...
1 首頁 市場動態 歷史股價 基金淨值 基金分類 經濟數據總覽 2021行事曆 期貨報告 加...
............................................................
元素 : 7
0 1 ... 3 4
0 全球匯率 (Currency Exchange) 全球匯率 (Currency Exchange) ... 全球匯率 (Currency Exchange) 全球匯率 (Currency Exchange)
1 貨幣 匯率 ... 比例 台北
2 歐元/美元 1.1561 ... 0.06% 19:02
3 英鎊/美元 1.3599 ... 0.15% 19:02
4 美元/瑞士法郎 0.9258 ... -0.13% 19:02
5 美元/瑞典克朗 8.7797 ... -0.21% 19:02
.............
從上述我們可以獲得更明確的結果了,由上述,我們可以知道所要的元素索引是 7,其中元素 7 的 column 標題顯示 "0....4",表示標題"1 2 3"是省略顯示。
範例 pythonPandas-42.py : 顯示元素 7 的 Pandas 之 DataFrame 資料。
# pythonPandas-42.py import pandas as pd url = 'http://www.stockq.org/market/currency.php' currencys = pd.read_html(url) # 讀取全球匯率行情表 currency = currencys[7] # 讀取第7元素 currency = currency.drop(currency.index[[0,1]]) # 拋棄前2 row currency.columns = ['貨幣', '匯率', '漲跌', '比例', '台北'] # 建立column標題 currency.index = range(len(currency.index)) # 建立row標題 print(currency)
執行結果
貨幣 匯率 漲跌 比例 台北 0 歐元/美元 1.1561 0.0006 0.06% 19:02 1 英鎊/美元 1.3599 0.0021 0.15% 19:02 2 美元/瑞士法郎 0.9258 -0.0012 -0.13% 19:02 3 美元/瑞典克朗 8.7797 -0.0184 -0.21% 19:02 4 美元/俄盧布 72.0608 -0.3435 -0.47% 19:02 5 美元/匈牙利幣 309.50 -0.64 -0.21% 19:02 6 美元/土耳其幣 8.8690 0.0020 0.02% 19:02 7 美元/南非幣 14.8737 -0.0859 -0.57% 19:02 8 美元/以色列幣 3.2283 -0.0049 -0.15% 19:02 9 美元/摩洛哥 9.0692 0.0022 0.02% 19:02 10 澳幣/美元 0.7296 0.0024 0.34% 19:02 11 紐幣/美元 0.6928 0.0020 0.29% 19:02 12 美元/日圓 111.38 -0.01 -0.01% 19:02 13 美元/人民幣 6.4452 0.0000 0.00% 05:00 14 美元/港幣 7.7845 -0.0016 -0.02% 19:02 15 美元/台幣 27.968 -0.001 -0.00% 19:02 16 美元/韓圜 1189.71 0.25 0.02% 19:02 17 美元/泰銖 33.770 -0.030 -0.09% 19:02 18 美元/新元 1.3576 -0.0006 -0.05% 19:02 19 美元/菲披索 50.343 -0.467 -0.92% 19:02 20 美元/馬來幣 4.1810 0.0005 0.01% 16:14 21 美元/印尼盾 14215.0 -33.5 -0.24% 15:53 22 美元/印度盧比 74.739 -0.011 -0.01% 19:02 23 美元/加幣 1.2578 -0.0007 -0.06% 19:02 24 美元/巴西幣 5.4932 0.0025 0.05% 05:00 25 美元/墨披索 20.5165 -0.0272 -0.13% 19:02 26 美元/阿根廷 98.9100 0.0050 0.01% 09:57 27 美元/智利 812.93 0.00 0.00% 18:55
參考資料
特色、摘要,Feature、Summary:
關鍵字、標籤,Keyword、Tag:
- Web-Crawler,Data-Mining,Data-Science,Python,Python-Tutorial,
留言
張貼留言
Aron阿龍,謝謝您的留言互動!