###### tags: `選修`
# python數據分析入門
+ [部份範例來源:成為python數據分析達人的第一課(自學課程)](http://moocs.nccu.edu.tw/course/123/intro)
## 一、資料收集
1. ### 資料收集管道
- 自行收集
* 客戶資料
* 問卷調查
* 自行架設感測器
- 開放資料集
* [政府資料開放平台](https://data.gov.tw)
* [臺北市資料大平臺](https://data.taipei/)
* [臺南市政府資料開放平台](http://data.tainan.gov.tw)
* [Kaggle](https://www.kaggle.com/datasets)
- 商業公司API
* [Facebook Graph API](https://developers.facebook.com/docs/graph-api/using-graph-api)
* [YouTube Data API](https://developers.google.com/youtube/v3/getting-started)
* [Twitter Developers](https://developer.twitter.com/en/docs)
* [Flickr API](https://www.flickr.com/services/developer/api)
- 網頁爬蟲
- 付費
2. ### 資料開放平台
- 網路連線
``` javascript=
import requests
url = 'https://cs.cysh.cy.edu.tw'
html = requests.get(url)
print(html.text)
```
- 開放平台API串接
``` javascript=
import requests
# 抓取寵物登記站名冊:臺北市資料大平臺/資料目錄/主題分類瀏覽/農業/寵物登記站名冊/API
url = 'https://data.taipei/opendata/datalist/apiAccess?scope=resourceAquire&rid=e0241f72-7db0-4d04-91a3-571d1af69f6b'
resp = requests.get(url)
data = resp.json() # 以json()方法解析
print(data)
vhos_list =data['result']['results']
for item in vhos_list: # hospital為字典型態
if item['地址'][:3] == '大安區':
print(f"{item['寵物登記機構名稱']}\n{item['電話']}")
```
:::info
EX_01:至[行政院環境保護署。環境資源資料開放平臺](https://opendata.epa.gov.tw/),抓取嘉義PM2.5的資料。
:::
``` javascript=
import requests
url = 'https://opendata.epa.gov.tw/api/v1/ATM00625?%24skip=0&%24top=1000&%24format=json'
........ # 若來源資料為 https 則加上 verify=False 參數
........ # 以json()方法解析
print(data)
........ # 對data中的每一個字典
if ........ == '嘉義': # 如果字典中Site等於嘉義
print(item)
```
3. ### 網路爬蟲 Web Crawler
- [文組也看得懂的 - 網路爬蟲](https://www.youtube.com/watch?v=BdRjutf8K0c)
- HTML 格式使用 BeautifulSoup 來解析
- [Python爬虫利器二之Beautiful Soup的用法](https://cuiqingcai.com/1319.html)
- [爬蟲使用模組介紹-Beautiful Soup 1](https://ithelp.ithome.com.tw/articles/10206419)、[爬蟲使用模組介紹-Beautiful Soup 2](https://ithelp.ithome.com.tw/articles/10206668)
- [网页爬虫教程系列 | 莫烦Python](https://morvanzhou.github.io/tutorials/data-manipulation/scraping/)
- [Python 爬虫学习系列教程](http://wiki.jikexueyuan.com/project/python-crawler-guide/)
- [Python 爬蟲實戰](https://www.slideshare.net/tw_dsconf/python-83977397)
``` javascript=
import requests
from bs4 import BeautifulSoup
url = 'http://cs.cysh.cy.edu.tw'
html = requests.get(url)
# print(html.text)
sp = BeautifulSoup(html.text, 'lxml')
# print(sp.h1)
a_tags = sp.find_all('a') # 所有a標籤組成的list
for itm in a_tags:
print(itm.text) # 輸出超連結的文字
ul_tags = sp.find('ul',{'class':'alt'}) # ul標籤,class為alt
ul_a_tags = ul_tags.find_all('a')
for itm in ul_a_tags:
print(itm.get('href'))
```
:::info
EX_02:至[《美麗佳人》/Love & Sex/星座運勢](https://www.marieclaire.com.tw/love-sex/astrology),抓取星星教授安格斯的每週星座運勢。
:::
``` javascript=
import requests
from bs4 import BeautifulSoup
url = "https://www.marieclaire.com.tw/love-sex/astrology"
........ # 取得網頁內容
........ # 以 BeautifulSoup 分析
hot = soup.find_all('div', {'class':'hot'}) # 文章在<div class="hot">區塊
# print(hot)
articles = hot[0].find_all('a')
# print(articles)
item = articles[0]
# print(item)
# print(item.attrs) # a的參數
# print(item['href'])
# print(item['href'].split('/')) # 分解超連結
weekly_url = item['href']
article_num = item['href'].split('/')[5]
for item in articles:
if '星星教授安格斯' in item['title'] and item['href'].split('/')[5] > article_num : # 抓超連結最後數字最大者
weekly_url = item['href']
article_num = item['href'].split('/')[5]
weekly_resp = requests.get(weekly_url)
weekly_soup = BeautifulSoup(weekly_resp.text, 'lxml')
article = weekly_soup.find_all('div', {'class':'........'})[0] # 找找看本週星座運勢在那一個區塊
fortune = {}
for item in article.find_all('h2'):
sign = item.string[:2] # 星座
luck = item.next_sibling.string # h2標籤後一個p
fortune[sign] = luck # 組成字典
# print(fortune['牡羊'])
from ipywidgets import interact_manual # 互動選單
interact_manual(lambda 星座: fortune[星座], 星座=['魔羯','射手','天蠍','天秤','處女','獅子','巨蟹','雙子','金牛','牡羊','雙魚','水瓶']);
```
4. ### 正規表達式(Regular expression)
- [用 Regular Expression 做字串比對](https://larry850806.github.io/2016/06/23/regex/)
- [JavaScript RegExp 对象](http://www.w3school.com.cn/js/jsref_obj_regexp.asp)
- [Python正则表达式指南](https://www.cnblogs.com/huxi/archive/2010/07/04/1771073.html)
- [Online regex tester and debugger](https://regex101.com/)
- [正则表达式 - Python 基础 | 莫烦Python](https://morvanzhou.github.io/tutorials/python-basic/basic/13-10-regular-expression/)
``` javascript=
str = 'dog run'
print('dog' in str)
print('cat' in str)
import re
print(re.search('dog', str))
print(re.search('cat', str))
# []匹配多種可能
ptn = r'r[ua]n' # 字串前的 r 表示這是正規表達式,run或ran
print(re.search(ptn, str))
print(re.search(r'r[A-Z]n', str))
print(re.search(r'r[a-z]n', str))
print(re.search(r'd[0-9a-z]g', 'd0g run')) # d、g間為數字或英文
print(re.search(r'd\dg', 'd0g run')) # \d 表示任何数字
```
``` javascript=
import requests
from bs4 import BeautifulSoup
import re
url = 'https://pixabay.com/'
resp = requests.get(url, headers={'User-Agent':'Mozilla/5.0'}) # 讓網站以為是人操作瀏覽器上網
soup = BeautifulSoup(resp.text, 'lxml')
img_links = soup.find_all('img', {'src': re.compile('.+\.jpg')}) # 以正規表達式,選取副檔名為jpg的圖片連結
for link in img_links:
print(link.get('src'))
```
<br />
## 二、NumPy
+ 做數據分析時常把list轉成array,NumPy的ndarray(N-Dimentional Array)是一個快速、節省空間的多維度陣列,可提供向量運算及複雜的功能。
+ NumPy的ndarray中的所有元素的資料型態必須相同,每個陣列都有一個shape(各維度大小的元組)和dtype(元素資料類型)
- 轉換的優先順序為:字串 > 數字 > 布林。
+ 參考網站
- [numpy 用法 (1)](http://violin-tao.blogspot.com/2017/05/numpy-1.html)
- [numpy 用法 (2)](http://violin-tao.blogspot.com/2017/06/numpy-2.html)
- [Data Science — Numpy Basic !](https://medium.com/pyladies-taiwan/data-science-numpy-basic-d3a6ca6c715c)
- [Python玩數據 (2):Numpy [1/2]](https://www.ycc.idv.tw/python-play-with-data_2.html)
- [Python玩數據 (3):Numpy [2/2]](https://www.ycc.idv.tw/python-play-with-data_3.html)
- [NumPy User Guide](https://docs.scipy.org/doc/numpy/user/index.html)
- [NumPy API Reference](https://docs.scipy.org/doc/numpy/reference/)
- [The N-dimensional array (ndarray) API Reference](https://docs.scipy.org/doc/numpy/reference/arrays.ndarray.html)
1. ### 直接建立陣列
``` javascript=
import numpy as np
a = np.array([1,2,3]) # 一維陣列
a
a.ndim # 幾維陣列
a.shape # 陣列形狀
a.size # 陣列元素個數
a.dtype # 陣列的資料型態
a_f = a.astype(np.float64) # 轉換成浮點數型態
a_f.dtype
b = np.array(['1','2.2','3.33'])
b_f = b.astype(float) # 字串陣列若全都是數字,可用astype將其轉換為數值
b_f
b_f.dtype
c = np.array([[1,2,3], [4,5,6]]) # 二維陣列
c
c.ndim
c.shape
c.size
```
2. ### [Numpy的數學(統計)運算](https://docs.scipy.org/doc/numpy/reference/routines.math.html)
- [[python] numpy axis概念整理筆記](http://changtw-blog.logdown.com/posts/895468-python-numpy-axis-concept-organize-notes)
``` javascript=
a = np.array([3,4,5,1,2])
np.sort(a) # 排序
a.sum() # 加總,同 np.sum(a)
a.mean() # 平均
a.max() # 最大值
a.min() # 最小值
a.std() # 標準差
np.mod(5,2) # 求餘數
np.sin(np.pi/2) # 求sin
np.log(100)
a = np.array([[1,2,3], [4,5,6]])
a.sum() # 21,axis=None或defalut,對矩陣內所有元素作運算。同 np.sum(a)
a.sum(axis=0) # [1+4, 2+5, 3+6]。同 np.sum(a, axis=0)
a.sum(axis=1) # [1+2+3, 4+5+6]。同 np.sum(a, axis=1)
```
3. ### 陣列快速生成法
- np.linspace(start, stop, size, endpoint)
* 在stat~stop範圍,產生均勻間隔、指定數量的元素。endpoint=False 不包含stop。
- np.arange(start, stop, step)
* 在start~stop範圍,根據間隔大小(step)生成元素
* 類似python range,回傳型態為ndarray (range回傳型態為list)
- np.random.randint(low, high, size)
* 在low~high(不包含)內,隨機產生指定數量的元素
``` javascript=
import numpy as np
np.zeros(3) # 建立皆為0的1X3陣列
np.zeros((3,5)) # 建立皆為0的3X5陣列
np.zeros((3,5), dtype=np.int)
np.ones(3) # 建立皆為1的1X3陣列
np.full((3,5), 7) # 建立皆為7的3X5陣列
np.eye(3) # 建立3x3的單位矩陣(identity matrix)
np.diag([1,2,3]) # 建立3X3陣列,對角為1,2,3
np.random.randint(0, 10, 9) # 建立1維陣列,9個0~9之間的亂數
np.random.randint(0, 10, (3,3)) # 建立3X3陣列,內容為0~9之間的亂數
np.random.normal(0, 1, (3,3)) # 建立3X3的常態分佈矩陣,平均值為0,標準差為1
np.arange(3) # 建立 [0 1 2]
np.arange(10, 20, 2) # 建立 [10, 12, 14, 16, 18]
np.linspace(0, 10, 6) # 0~10平均取6個點
xy = [[x, y] for x in range(5) for y in range(3)]
np.array(xy)
```
4. ### 陣列重塑形狀
- np.reshape((new_row, new_column))
* 將陣列轉換成新列數、新行數
- np.flatten()、np.ravel()
* 將多維陣列降為一維。
* flatten()返回一份拷貝,對拷貝所做的修改不會影響原始陣列。
* ravel()返回的是檢視(view,類似C/C++的reference),如果改變了,會影響原始陣列。
``` javascript=
import numpy as np
a = np.array([1,2,3,4,5,6,7,8])
a
a.shape
a = a.reshape(2,4) # 同 a.shape = (2,4)
a
a.shape
b = a.flatten() # 將矩陣重組為一維陣列
b
b.shape
a.shape = (2,4)
c = a.reshape(1,8) # 還是2維陣列
c
c.shape
```
5. ### 資料存取
- 同list,可使用index(從0開始算)、slice、iterate 來存取陣列裡的資料。
``` javascript=
import numpy as np
a = np.array([1,2,3,4,5])
a[2] # 取index 2 的元素
a[2:5] # 取index 2~4 的元素
a[:5:2] # 取index 0、2、4 的元素
a[::-1] # 後往前取
a[1:3] = 7 # 將index 1~3 的元素改為 7
b = np.array([[1,2,3], [4,5,6], [7,8,9]])
b[0, 1] # 選取第0列,第1欄的元素
b[0][1] # 同上
b[1, :] # 選取第1列的全部元素
b[1] # 同上
b[1:3] # 選取1~2列多列元素
b[:, 2] # 選取全部列的第2欄(index 2)的元素
x = np.arange(9).reshape((3,3)) # 產生[0,1,2,3,4,5,6,7,8],並轉為3X3陣列
np.diag(x) # 取對角線元素
a = np.arange(10)
b = np.arange(5)
a[5:] = b[::-1] # a為[0,1,2,3,4,4,3,2,1,0]
```
- 以判斷式來進行篩選
``` javascript=
import numpy as np
math = np.array([60,70,55,80,90])
math >= 60 # 每個元素是否 >=60
math[math >= 60] # >=60 的元素
np.count_nonzero(math >= 60) # 計算 >=60 的有多少位
np.sum(math >= 60) # 計算 >=60 的有多少位,True == 1, False == 0
np.where(math >= 60)[0] # 成績 >=60 的index
np.any(math >= 60) # 是否有一人成績 >=60
np.all(math >= 60) # 是否全班都及格
```
6. ### 矩陣element-wise運算(每個相對應元素做運算)
``` javascript=
import numpy as np
us = [100,500,400]
us * 3
us_arr = np.array(us)
rate = 30.8
us_arr * rate
grades = np.array([80, 60, 70])
weights = np.array([0.3, 0.3, 0.4])
g = grades * weights
a = np.array([[1,2], [3,4]])
b = np.array([[5,6], [7,8]])
a+b # element-wise plus
c = np.array([1, 2, 3])
c**2
```
7. ### 矩陣操作(matrix operation)
``` javascript=
import numpy as np
a = np.array([1,2,3,4,5,6,7,8,9])
np.cumsum(a) # a 中元素的累計和(cumulative sum)
np.diff(a) # 兩兩元素差
np.clip(a,3,8) # 將元素限製在3~8間,大於8改為8,小於3改為3
a = np.array([[1,2], [3,4]])
b = np.array([[5,6], [7,8]])
np.dot(a, b) # 矩陣相乘,同 a.dob(b)
a.T # 轉置矩陣,同 np.transpose(a)
a_rev = np.linalg.inv(a) # 反矩陣
np.dot(a, a_rev)
np.vstack((a, b)) # 垂直方向合併
np.hstack((a, b)) # 水平方向合併
a = np.array([1,2,3])
b = np.array([4,5,6])
z = np.c_[a, b] # numpy中的zip。np.c_是列向相加,列向量在axis = 1接起來
# array([[1, 4],
# [2, 5],
# [3, 6]])
np.r_[a, b] # np.r_是行向相加,列向量在axis = 0接起來
a = z[:,0] # unzip
b = z[:,1]
a = np.arange(9)
np.split(a, 3) # 分割成3段
a = np.arange(8)
np.array_split(a, 3) # split必須可以均分,否則會錯誤。array_split不會
```
8. ### 資料擴充與重複
``` javascript=
import numpy as np
np.append([0,0], [1,1,1]) # append(原陣列, 要附加的元素) [0, 0, 1, 1, 1]
np.insert([0,0], 1, [1,1,1]) # insert(原陣列, 要插入的位置, 要插入的元素) [0, 1, 1, 1, 0]
a = np.array([0,1])
np.tile(a, 3) # tile()對整個數組進行複製。把[0,1]看成一組,重複3遍 [0, 1, 0, 1, 0, 1]
np.tile(a, (2,3)) # 將[0, 1]變成2x3陣列
np.repeat(a, 2) # 每個元素重複2次
a = np.array([[1,2], [3,4]])
np.repeat(a, 2)
np.repeat(a, 2, axis=0) # axis指定要往哪個方向的維度擴展
np.repeat(a, 2, axis=1)
```
9. ### 陣列拷貝與刪除
- slice出來的新陣列,與原本的陣列共用同一塊記憶體,copy()出來的新陣列不會。
``` javascript=
import numpy as np
a = np.arange(5)
b = a[::2]
np.may_share_memory(a, b)
a[0] = -1 # 新陣列b與原陣列a用同一個記憶體空間,當a改變時,b會跟著改變
a
b
a = np.arange(5)
c = a[::2].copy() # copy出來的新陣列c,不與原陣列a用同一個記憶體空間
np.may_share_memory(a, c)
a[0] = -1
a
c
a = np.arange(10)
index = [1, 3, 5]
np.delete(a, index) # 刪除索引值的元素
a = np.array([[1,2,3], [4,5,6], [7,8,9]])
np.delete(a, 1, axis=0) # delete(原陣列, 要刪除的索引值, 維度方向)
np.delete(a, 1, axis=1)
```
<br />
## 三、資料視覺化
+ 參考網站
- [[資料分析&機器學習] 第2.5講:資料視覺化(Matplotlib, Seaborn, Plotly)](https://medium.com/jameslearningnote/%E8%B3%87%E6%96%99%E5%88%86%E6%9E%90-%E6%A9%9F%E5%99%A8%E5%AD%B8%E7%BF%92-%E7%AC%AC2-5%E8%AC%9B-%E8%B3%87%E6%96%99%E8%A6%96%E8%A6%BA%E5%8C%96-matplotlib-seaborn-plotly-75cd353d6d3f)
1. ### Matplotlib
- 線圖(Line plot)
``` javascript=
import matplotlib.pyplot as plt
x = [1, 2, 3, 4, 5]
y = [2, 9, 4, 8, 3]
plt.plot(x, y)
plt.xlabel('x label') # 加上座標軸的label
plt.ylabel('y label')
```
``` javascript=
import numpy as np
import matplotlib.pyplot as plt
plt.plot(np.random.randn(100)) # randn(100) 產生100個常態分布的亂數(平均值0,標準差1)
```
``` javascript=
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0, 10, 100) # 0~10間,產生100個點
plt.plot(x, np.sin(x))
plt.plot(x, np.cos(x),'bo') # blue,circle marker
```
- 散佈圖(Scatter plot)
``` javascript=
import matplotlib.pyplot as plt
x = [2, 1, 3, 4, 5]
y = [9, 2, 4, 8, 3]
plt.scatter(x, y)
```
- 長條圖(Bar plot)
``` javascript=
import matplotlib.pyplot as plt
x = [1, 2, 3, 4, 5]
y = [2, 9, 4, 8, 3]
plt.bar(x, y)
```
- 直方圖(Histogram)
``` javascript=
import numpy as np
import matplotlib.pyplot as plt
normal_samples = np.random.normal(size = 1000) # 生成 1000 組標準常態分配隨機數(平均值0,標準差1 的常態分配)
plt.hist(normal_samples,bins = 100) # bins 為直方圖直條個數
```
<br />
## 四、Pandas數據分析
+ Python的Excel,pandas 可以擷取 JSON, CSV, Excel, HTML 等格式的資料,主要資料型態有Series(一維)、DataFrame(二維、類似表格)。
+ 基於Numpy構建,包含許多操作資料與統計的函式,讓以NumPy為中心的應用變的更加簡單。
+ 參考網站
- [Python pandas Q&A video series](https://github.com/justmarkham/pandas-videos)
- [Python資料分析(四)Pandas](https://medium.com/@allaboutdataanalysis/python%E8%B3%87%E6%96%99%E5%88%86%E6%9E%90-%E5%9B%9B-pandas-e2fdeb6808c1?postPublishedType=repub&fbclid=IwAR2RmaITrI5mBFAYQ4pZFZ3TLUbwUTIXs2XV3X4_TmBbs-v-O52prqXHRRk)
- [[Python] Pandas 基礎教學](https://oranwind.org/python-pandas-ji-chu-jiao-xue/)
- [Python Pandas 基本操作教學_成績表](https://medium.com/@weilihmen/python-pandas-%E5%9F%BA%E6%9C%AC%E6%93%8D%E4%BD%9C%E6%95%99%E5%AD%B8-%E6%88%90%E7%B8%BE%E8%A1%A8-f6d0ec4f89)
- [[資料分析&機器學習] 第2.3講:Pandas 基本function介紹(Series, DataFrame, Selection, Grouping)](https://medium.com/jameslearningnote/%E8%B3%87%E6%96%99%E5%88%86%E6%9E%90-%E6%A9%9F%E5%99%A8%E5%AD%B8%E7%BF%92-%E7%AC%AC2-3%E8%AC%9B-pandas-%E5%9F%BA%E6%9C%ACfunction%E4%BB%8B%E7%B4%B9-series-dataframe-selection-grouping-447a3fa90b60)
- [莫煩Python](https://morvanzhou.github.io/)
- [pandas 用法 (1)](http://violin-tao.blogspot.com/2017/06/pandas-1-indexing.html)、[pandas 用法 (2)](http://violin-tao.blogspot.com/2017/06/pandas-2-concat-merge.html)
- [pandas 官方手冊](https://pandas.pydata.org/pandas-docs/stable/index.html)
1. ### pandas 讀取資料
- 讀取 CSV 檔案
- 讀取 Html 檔案
``` javascript
df = pd.read_html('http://rate.bot.com.tw/xrt?Lang=zh-TW')
df[0]
```
2. ### DataFrame
- 建立 DataFrame:可以透過 Dictionary、Array 來建立,也可以讀取外部資料(CSV、資料庫等)來建立。
- DataFrame 基本資訊
| 基本資訊方法 | 說明 |
|:--------------|:-------------|
| df.info() | 表格的資訊 |
| df.shape | 表格列數與欄數 |
| df.columns | 回傳欄位名稱 |
| df.index | 回傳 index |
| df.head(n) | 回傳前n筆資料,省略預設為5筆 |
| df.tail(n) | 回傳後n筆資料,省略預設為5筆 |
| df.describe() | 回傳各類統計資料 |
- [資料選取](https://codertw.com/%E7%A8%8B%E5%BC%8F%E8%AA%9E%E8%A8%80/462517/)
| 選取方法 | 說明 |
| -------------| --------- |
| df['欄位名'] | 選取欄的元素|
| df.欄位名 | 選取欄的元素|
| df.loc() | 根據行、列標籤來選取 |
| df.iloc() | 根據索引值來選取|
| df.ix() | 以行、列的標題或位置來選取,loc和iloc的綜合體|
- 資料篩選:在中括號裡面放入篩選條件
- 資料排序
| 排序方法 | 說明 |
| ------------ | --------- |
| df.sort_index() | 依索引值排序,axis指定是列索引值或行索引值排序 |
| df.sort_values()| 依欄位值排序,by指定排序欄位,ascending指定升冪或降冪排序|
:mega: [pandas中axis參數](https://stackoverflow.com/questions/25773245/ambiguity-in-pandas-dataframe-numpy-array-axis-definition)
<br />
:::info
EX_03:上傳[pandas_grades](https://drive.google.com/open?id=1kXda1ylxi5V8htWYQGc7BDA4m0OhfGwp)至Colab,練習dataframe的基本操作(選取、篩選、排序...)。
:::
``` javascript=
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
df = pd.read_csv('pandas_grades.csv')
# 基本資訊
df.info()
df.shape
df.columns
df.index
df.head()
df.tail()
# 資料選取
# 欄
df['國文']
df[['國文','英文']].head() # 多個欄位用list裡面放欄位名稱
# 列
df[5:10] # 取得index 5~9 的資料
df.loc[5:10, ['國文','英文']] # 取得index 5~10 的資料,同df.loc[5:10][['國文','英文']]
df.loc[5:10, '國文':'數學']
df.iloc[5:11, 1:4] # 同上,用iloc以索引值來選取
df.國文 # 同 df['國文']
cg = df.國文.values
cg.mean()
cg.std()
df.國文.mean()
df.describe() # 取得 df 的統計資訊(每個欄位的平均值、最大值、最小值、標準差…)
# 資料篩選
test = df.iloc[:3]
test[ [True, False, True] ] # 列篩選的作法為保留布林list(和資料筆數同)中True索引那一列
filter = df['姓名'].str.contains('陳')
df[filter]
df[ df['數學'] >= 14 ]
df[ df.數學 == 15 ]
df[ (df.數學 == 15) & (df.英文 == 15) ] # panda中 &(and)、|(or)
# 繪圖
df.國文.plot()
df.國文.hist(bins=15)
df.corr() # 相關係數
df.國文.corr(df.數學)
df['總級分'] = df[['國文', '英文', '數學', '社會', '自然']].sum(axis=1) # df["新欄位名稱"]=df[要加總的欄位的list].sum(axis=1)
df.head()
df['主科'] = df.數學*1.5 + df.英文 # 新增欄位
df.head()
# 排序
df.sort_values(by='總級分', ascending=False).head(20)
df.sort_values(by=['主科', '總級分'], ascending=False).head(20)
```
- [數據合併、連接](https://zhuanlan.zhihu.com/p/38184619)
| 合併方法 | 說明 |
| --------| --------- |
| concat | 沿縱向或橫向,將多個df合併 |
- 資料刪除
| 刪除方法 | 說明 |
| --------------| --------- |
| del df['欄名'] | 刪除單行(直接修改df) |
| df.drop(['欄名1', '欄名2'], axis=1) | 刪除多行,axis=1為刪除行,axis=0為刪除列。(不會直接修改df,加入inplace=True才會修改df) |
- 遺漏值處理
* 缺失資料如果用「平均值、中位數、眾數、隨機值等替代」,效果一般,因為等於人為增加了雜質。
* 如果資料量大,可直接將資料刪除。
| 遺漏值處理方法 | 說明 |
| -------- | --------- |
| df.isnull() | 判斷是否為空值 |
| df.notnull()| 判斷是否不為空值|
| df.dropna() | 刪除有NaN(Not a number, 缺失值)的列 |
| df.fillna(value=0) | 將NaN填入0 |
- 資料分群
| 分群方法 | 說明 |
| ------------ | --------- |
| sector = df.groupby(by='欄位名') | 以欄位名分群,後面可加入要運算的函式,如sum、count、mean |
| sector.size() | 每個群的大小 |
| sectors.get_group('A') | 取出欄位名為'A'的資料 |
<br />
:::info
EX_04:DataFrame建立、合併操作、NaN處理。
:::
``` javascript=
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
mydata = np.random.randn(4,3) # 產生 4x3 標準常態分佈亂數(平均值0,標準差1)
df1 = pd.DataFrame(mydata, columns=list('ABC')) # 將array放入DataFrame
df2 = pd.DataFrame(np.random.randn(3,3), columns=list('ABC'))
df3 = pd.concat([df1, df2], axis=0)
df3.index = range(7)
df4 = pd.concat([df1, df2], axis=1)
df4.columns=list('ABCDEF')
df4.info() # D、E、F欄後為3 non-null,表示有一個NaN
df4.isnull()
df4.notnull()
df4.dropna()
df4.fillna(value=0)
values_to_fill = {'D': 1, 'E': 2 ,'F': 3} # 指定將 'D'欄填入1,'E'欄填入2,'E'欄填入3
df4.fillna(value = values_to_fill)
df4.mean() # 計算每個欄位的平均值,再將它填入NaN
df4.fillna(df4.mean())
```
:::info
EX_05:美國哪裡最容易看到UFO。(分群)
:::
``` javascript=
import pandas as pd
df = pd.read_csv('http://bit.ly/uforeports')
df.head()
sector = df.groupby(by='Shape Reported') # 以 'Shape Reported' 分組
sector.size() # 每個組別的大小
sector.get_group('DISK').head() # 取得 'Shape Reported' 為 'disk' 的資料
df_state = df.groupby(by='State').count()
df_state.sort_values(by='Time', ascending=False) # 原始資料並不會被排序後的資料覆蓋
df_state.sort_values(by='Time', ascending=False, inplace=True) # 覆蓋原始資料
df_state[:10].Time.plot(kind='bar')
```
<br />
## 五、特徵標準化(Normalization)與選擇
+ 透過特徵標準化,可以讓每個特徵的數值都落在某一特定的區間。可以優化梯度下降法,還可以提高精準度。
- 有些分類器需要計算樣本間的距離(KNN),如果一個特徵值的範圍非常大,那麼距離就會取決於這個特徵,導致分析的結果失真。
+ 「特徵選取」(feature selection)的目標是要從原有的特徵中挑選出最佳的部分特徵,可改善高維度數據的準確率。
1. ### 常見的標準化
- Min-Max 標準化
* 將特徵數值按比例縮放到特定區間(0~1 或 -1~1)
- Z-score 標準化
* 將特徵數值縮放成平均為 0、標準差為 1
- 參考網站
* [機器學習:特徵標準化!](https://ithelp.ithome.com.tw/articles/10197357)
* [【資料科學】 - 資料的正規化與標準化](https://aifreeblog.herokuapp.com/posts/54/data_science_203/)
* [莫煩-正規化Normalization](https://morvanzhou.github.io/tutorials/machine-learning/sklearn/3-1-normalization/)
* [4.3. 数据预处理](http://sklearn.lzjqsdd.com/modules/preprocessing.html)
<br />
:::info
EX_06:標準化對SVM分類的影響?
:::
``` javascript=
from sklearn import preprocessing
from sklearn.model_selection import train_test_split
from sklearn.datasets.samples_generator import make_classification
from sklearn.svm import SVC
import numpy as np
import matplotlib.pyplot as plt
x,y = make_classification(n_samples=300,n_features=2,n_redundant=0,n_informative=2,
random_state=3,scale=100,n_clusters_per_class=1) # 生成分類模型數據
plt.scatter(x[:,0],x[:,1],c=y)
x_train,x_test,y_train,y_test = train_test_split(x,y,test_size=0.2)
clf = SVC()
clf.fit(x_train,y_train)
clf.score(x_test,y_test)
```
``` javascript=
x_scaled = preprocessing.scale(x) # 標準化X
plt.scatter(x_scaled[:,0],x_scaled[:,1],c=y)
x_train,x_test,y_train,y_test = train_test_split(x_scaled,y,test_size=0.2)
clf = SVC()
clf.fit(x_train,y_train)
clf.score(x_test,y_test)
```
2. ### 特徵選擇 Feature Selection
- 移除低變異數的特徵(Removing features with low variance)
* 變異數可以描述特徵的離散程度。一般情況下,可以刪除變異數過小的特徵(偏向某一兩個分類),因為其對結果的解釋力通常不大。
* 若建立 VarianceThreshold 時不設定 threshold 參數,預設會篩選掉變異數為零的欄位。
- 單變數特徵選擇(Univariate Feature Selection)
* 單變數特徵選擇是根據每個特徵的單變數統計值(如chi2)作為門檻,然後依據該門檻選擇特徵(如SelectKBest)。
* Scikit-learn封装了一些特徵選擇方法如
(1) SelectKBest:將每個特徵的統計值算出後,選出 k 個最佳的特徵。
(2) SelectPercentile:將每個特徵的統計值算出後,選擇排前百分之幾最有意義的特徵。
* Select K Best為分類提供了三種評價特微的方式
(1) chi2(卡方統計值 χ2)能評估兩個變數是否互相獨立。該值愈大,兩變數愈有機會是相關的,愈小則愈不相關。
(2) f_classif(樣本方差F值)
(3) mutual_info_classif(離散類別交互信息)
(4) 另有用於回歸的f_regression
- 利用模型選擇特徵
* 先訓練一個模型,然後以該模型計算出的特徵重要性作為依據,挑選解釋力大的特徵。
- 參考網站
* [特徵選擇(feature selection)演算法筆記](https://www.itread01.com/content/1546133794.html)
* [sklearn中的特征提取](http://d0evi1.com/sklearn/feature_selection/)
* [1.13. 特征选择(Feature selection)](http://sklearn.lzjqsdd.com/modules/feature_selection.html)
<br />
:::info
EX_07: (1)設定變異數的門檻,抽取最佳的特徵。
(2)使用卡方檢驗,抽取2個最佳的特徵。
(3)使用模型選擇特徵。
:::
``` javascript=
from sklearn.datasets import load_iris
from sklearn.feature_selection import VarianceThreshold
from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import chi2
from sklearn.feature_selection import SelectFromModel
from sklearn.ensemble import ExtraTreesClassifier # 載入極限隨機樹模組做特徵選擇
iris = load_iris()
x, y = iris.data, iris.target
x.shape
sel = VarianceThreshold(threshold=0.5) # 設定變異數的閾值,若特徵的變異數低於該值,該特徵就會被移除
x_sel_1 = sel.fit_transform(x) # 利用先前建立的 VarianceThreshold 來篩選
x_sel_1.shape # 篩選後剩下的特徵
```
``` javascript=
x_sel_2 = SelectKBest(chi2, k=2).fit_transform(x, y)
x_sel_2.shape
```
``` javascript=
clf = ExtraTreesClassifier(n_estimators=10)# 決定決策數的數量
clf = clf.fit(x, y) # 訓練模型
clf.feature_importances_ # 模型訓練完會得到一個評估各特徵重要性的矩陣,值愈大愈重要
clf.feature_importances_.mean() # 特徵重要性平均值
model = SelectFromModel(clf, prefit=True) # 建立 SelectFromModel 選擇器,並載入剛剛訓練完的極限隨機樹,因為該模型已訓練過,prefit 參數要設為 True。沒有設定threshold參數會以平均值作為門檻。
x_sel_3 = model.transform(x) # 篩選特徵。
x_sel_3.shape
```