---
# System prepended metadata

title: Pandas
tags: [Python]

---

---
tags: Python
---
# Pandas
[Pandas cheat sheet pandas功能簡介](https://github.com/pandas-dev/pandas/blob/master/doc/cheatsheet/Pandas_Cheat_Sheet.pdf)

### 建立資料表
```
#建立空欄位
pd.DataFrame(columns=['col_name'])

#透過dict&list建立
pd.DataFrame({'col1'=list1,'col2'=list2})

#透過concat串接一維ndaarray、list
pd.concat([ndarray1,ndarray2],names=['col1','col2'])

#透過二維list建立
pd.DataFrame(item for item in list)

#透過array dictionary建立
pd.DataFrame([{'a':123,'b':456}])
```
### 讀取資料
```
#讀取csv、txt(使用中文路徑需加 engine='python')
df = pd.read_csv(path)

#讀取excel方法一
df = pd.read_excel(path,sheet_name='sheet1', engine='openpyxl')

#讀取excel方法二
xlsx = pd.ExcelFile('.xlsx')
sheets = xlsx.sheet_names
df = xlsx.parse(sheets[0])

#讀取網頁上的table(讀完會生成list型態)
df = pd.read_html(url_path)[0]
```
### 輸出資料
```
# 尾端加上 index=0 去掉預設的擾人索引值
df.to_csv(path,index=0)
writer = pd.ExcelFile('.xlsx')
df.to_excel(writer,sheet_name='mySheet',index=0)
writer.close()
df.to_json(path,orient='record')
```
### 基礎統計運算
```
df.describe()            #秀出統計資料
df.mean()                #平均值        
df.std()                 #標準差
df.skew()                #偏態
df.kurtosis()            #峰態
df.corr()                #欄位相關系數矩陣
df.sum()                 #縱向加總
df.T.sum().T             #橫向加總
df.col.value_counts()    #欄位的資料類別統計
```
### 資料型態
```
df.shape                            #dataframe維度
df.info()                           #dataframe資料型態列表
df.col.astype(str)                  #轉成字串
df.col.astype(int)                  #轉成整數
df.col.astype(float)                #轉成浮點數
df.col.astype('datetime64[ns]')     #轉成timpstamp物件
df.col.date.dt.day                  #從時間物件中取出日期
```
### 篩選
```
#頭尾篩選
df.head(10)
df.tail(10)

#取出特定欄位並轉成pandas series物件
df.col           #懶得打中括號和引號的時候
df['col']        #如果欄位是中文字或是尷尬的英文字就得用這個

#行列篩選
df.loc[:,['col1','col2']]        #依欄位名稱
df.iloc[:,[1,3,5]]               #依欄位序號
df.ix[[1,3,5],['col1','col2']]   #混搭兩者(deprecated)
df[row][col]                     #不套函式

#轉成ndarray
df.values           #二維陣列
df.col.values       #一維陣列

#轉成list
df.tolist()        #二維列表
df.col.tolist()    #一維列表

#條件篩選(傳入True和False的ndarray)
df[df.col.isin(ndarray)]         #是否包含陣列內的物件
df[df.col.isnull()]
df[df.col.notnull()]
df[df.col.str.contains(string)]  #欄位的文字是否有特定的字串
df[df.col.duplicated()]          #抓出重複的值

#多重條件篩選
constraint_1 = df.col.notnull()
constraint_2 = df.col.str.contains('abc')
df[constraint_1 & constraint_2]
```
### 新增刪除更改欄位
```
df['col'] = np.nan                       #新增空欄位
df.drop(columns=['col'])                 #刪除欄位
df.rename(columns={'old_col':'new_col'}) #更改欄位名稱
df.columns = ['col1','col2']             #換上一整組新的欄位名稱
```
### 索引
```
df.index
df.reset_index(drop=True)            #重設索引並且把原本的索引刪除
```
### 排序
```
#依索引排序(ascending=False 從大到小)
df.sort_index(ascending=False)

#依欄位值排序
df.sort_values(by='col', ascending=False)    #依據單一欄位
df.sort_values(by=['year','month','day'])    #依據多欄位、順序
```
### 空值處理
```
#空值、非空值分布狀況
df.isnull().any()
df.col.isnull().sum()
df.col.notnull().sum()

#篩選有空值、非空值的row
df[df.col.isnull()]
df[df.col.notnull()]

#去除、填上空值
df.dropna(how='any')       #去除其一欄位為空者
df.dropna(how='all')       #去除整行欄位為空者
df.dropna(thresh = 3)      #至少有三欄不為空
df.fillna(0)               #以0替代空值
df.fillna(method='ffill')  #以不為空值的前者補上
df.fillna(method='bfill')  #以不為空值的後者補上

#空值插補(沒有所謂最好的)
df.col.interpolate(method='linear')
#其他方法 linear, nearest, zero, slinear, quadratic, cubic, barycentric
```
![](https://i.imgur.com/4iRXGCJ.png)
### 重複值處理
```
#取得非重複值
df.col.unique()                           #欄位內所有種類

#去除重複值
df.drop_duplicates()                      #去除整行欄位重複者
df.drop_duplicates('col',keep='first')    #遇到重複值只保留第一個
df.drop_duplicates('col',keep='last')     #遇到重複值只保留最後一個

#篩選重複值
df.col.duplicated()
```
### 時間序列
[想要深造時間序列模型請點我](https://www.kaggle.com/thebrownviking20/everything-you-can-do-with-a-time-series)
```
#轉成時戳物件
pd.to_datetime('2017-11-11 09:08:07')
pd.to_datetime('col',format='%Y-%m-%d %H:%M:%S')

#時戳物件TimeStamp()常用函數
.date、.time
.year、.month、.day        #日期
.hour、.minute、.second    #時間
.daysinmonth              #一個月有幾天
.weekday                  #星期幾(0~6)(一~日)

#轉成時差物件(兩個時戳物件互相加減變換轉換成時差物件)
pd.timedelta('00:30:00')
.total_seconds()          #常用函數->總秒數

#產生時間範圍
pd.date_range(start='1/1/2018', periods=5, freq='M') #產生五個時間點、以月分作為間隔

#時序取樣
df.resample(on='datetime',freq='30min').mean()
df.col.asfreq('30min')
df.col.rolling('7D').mean()    #7天的移動平均(往前取樣，因此取樣的最後一天才有值)
df.col.expanding('7D').mean()  #7天平均(往後取樣，因此前6天值不為空值)
```

### 字串處理
```
df.col.str.contains(str1|str2)       #抓出涵蓋字串1和2的文字
df.col.str[1:-1]                     #將字串頭尾去掉
df.col.str.extract(r'')              #使用正規表達式抽出字串
df.col.str.replace('不要的字串','')    #去除掉不要的字串
df.col.astype('category').cat.codes #轉成category物件並重新編號
df.col.map({0:''winner',1:'chicken',2:'dinner'}) #使用字典替代特定資料

### 判斷是否含有中文字
def is_chinese(uchar):
    return True if u'\u4e00'<=uchar<=u'\u9fff' else False
```
### 更改欄位資料
```
#套用預設函數
df.col.map(np.sqrt)

#使用lambda進行三元運算
df.col.map(lambda x:x**2 if x>0 else x)

#自訂函數
def my_function(x):
    return x**2
df.col.map(my_function)
```
### 資料表串接
```
#橫向串接(指定串接欄位與串接方式)
pd.merge(df1,df2,on=['col_1','col_2'], how='left', suffix=['_x','_y'])
#how種類 left, right, inner, outer
#suffix用於兩個表中欄位名稱一樣但沒有加入on裡面，因此加入詞綴來重新命名

#上下縱向串接(欄位名稱需一致)
df1.append(df2)
```
### 資料表展開、溶解
```
#展開(將三個欄位展開，各別給上新索引、欄位、值)
df.pivot(index='col1',columns='col2',values='col3')
df.groupby('col').sum().unstack()
#溶解(反展開，將整張表轉換成三個欄位)
pd.melt(df,id_vars='唯一值類別的欄位')
```
### 群組分析
```
df.groupby(['col1','col2'])['col3'].mean()
df.groupby(['col1','col2'])['col3'].median()
df.groupby(['col1','col2'])['col3'].quantile(0.5)
df.groupby(['col1','col2'])['col3'].count()
df.groupby(['col1','col2'])['col3'].size()
df.groupby(['col1','col2'])['col3'].sum()
df.groupby(['col1','col2'])['col3'].describe()
df.groupby(['col1','col2'])['col3'].count().unstack()#群組統計並且pivot
#grouby之後索引會變成 multi index，再加上.reset_index()可以回復原本單索引的DataFrame
df.groupby(['col1']).apply(lambda dataframe: ...)
for index, dataframe in df.groupby(['col1']):
    pass
```

### 隱藏警告
```
# 常常在做資料處理的時候會顯示出超長的warining，這裡有個方法可以隱藏
import warnings
warnings.filterwarnings('ignore')
```
### 讀取政府的開放資料(ods, pdf)
> [open document](https://github.com/T0ha/ezodf)
```
import ezodf
def read_ods(filename, sheet_no=0, header=0):
    tab = ezodf.opendoc(filename=filename).sheets[sheet_no]
    return pd.DataFrame({col[header].value:[x.value for x in col[header+1:]]
                         for col in tab.columns()})
df = read_ods(path, header=1)
header代表前面要先空個幾行再進行讀取
```

> [pdf](https://github.com/chezou/tabula-py)
```
from tabula import read_pdf
df = read_pdf(PDF網址,encoding = 'big5', spreadsheet = True, pages = '1-10')
encoding 大多數的中文字編碼為big5
spreadsheet 是否為表單格式
pages 要抓取的頁數
```
### numpy
pandas是基於numpy的高階程式庫，了解numpy本身怎麼寫也是蠻重要的
```python
import numpy as np
### 資料格式
np.array(list)   #從list轉為np陣列(ndarray)
ndarray.shape    #各個維度的大小
ndarray.dtype    #資料型態
ndarray.ndim     #資料維度
ndarray.size     #資料尺寸
ndarray.itemsize #資料格式記憶體大小

### 陣列處理
ndarray.flat             #攤開變成一維
ndarray.resize((x,y))
ndarray.T
ndarray.reshape(x,-1)    #-1代表自動計算
np.squeeze(ndarray)      #將陣列壓成一維

### 陣列篩選
ndarray[1:-1]     #第二個到倒數第二
ndarray[::2]      #每隔兩行篩選出來

### 陣列簡單運算
ndarray + ndarray_row             #列相加
ndarray + ndarray[:,np.newaxis]   #行相加

### 線性代數 Linear Algebra 
np.eye(3)                     #eye代表線性代數中的I
np.identity(3)                #同於np.eye()
np.diag(ndarray)              #取出陣列對角線的值
ndarray.transpose()           #轉置矩陣，同於ndarray.T
np.dot(np.sin(), np.cos())    #內積 dot product
np.outer(np.sin(), np.cos())  #外積 cross product

np.linalg.inv(ndarray)        #反轉矩陣
np.linalg.solve(x,y)          #矩陣相乘

#產生一維陣列
np.arange(0,15,1)     #最後一個值代表數值間隔
np.linspace(0,15,5)   #最後一個值代表產生的數量
np.r_[1:4,0,4]        #橫向產生[1,2,3,4,0,4]
np.c_[1:4,0,4]        #縱向產生

#產生高維陣列
np.zeros((x,y,z))
np.ones((x,y,z))
np.empty((x,y,z))

def func(x,y):
    return 10*x+y
np.fromfunction(func,(x,y),dtype=int)

#隨機產生
np.random.randint(50,size=20)
np.random.random((x,y,z))
np.random.normal(平均值,sigma,數量)
np.histogram(ndarray,bins=50,norm=True)

### 陣列串接
np.concatenate([list1,list2])     #一維合併
np.vstack((n1,n2))                #垂直合併
np.hstack((n1,n2))                #水平合併
np.columns_stack((n1,n2))         #橫向合併

### 陣列分割
np.hsplit(ndarray,3) 水平切成3個ndarray
np.vplit(ndarray,3) 垂直切成3個ndarray

### 儲存、載入
np.save('filename.npy',ndarray)
ndarray = np.load('filename.npy')
```

## 用R語言做報告
> 如果課堂作業必須用R語言的話...

RMD輸出PDF的方法(擺脫office word的束縛)：
安裝[VSCODE萬用程式碼編輯器](https://code.visualstudio.com/)
安裝[R語言](https://cran.r-project.org/bin/windows/base/)
安裝[Pandoc](https://pandoc.org/installing.html)
在VScode的Extensions(ctrl+shift+x開啟)，搜尋R並安裝擴充套件
創建一個`.rmd`檔，填入安裝rmarkdown與knitr的指令：
```r
install.packages("rmarkdown")
install.packages("knitr")
```
將程式碼片段框起來，使用快捷鍵`ctrl+enter`執行
RMD基本語法：
* 控制輸出圖案的大小
`{r,fig.width=3,fig.height=3}`
* 以latex語法輸入數學式
`{=latex}`

打完Markdown語法後，按下右上的`Knit RMD`(ctrl+shift+k)輸出HTML，
用瀏覽器開啟HTML，滑鼠右鍵>列印>另存成PDF