# 量化分析師的Python日記【第6天:數據處理的瑞士軍刀pandas下篇
> 來源:https://uqer.io/community/share/5514bb11f9f06c12790415b2
## 第二篇:快速進階
在上一篇中我們介紹了如何創建并訪問`pandas`的`Series`和`DataFrame`型的數據,本篇將介紹如何對`pandas`數據進行操作,掌握這些操作之后,基本可以處理大多數的數據了。首先,導入本篇中使用到的模塊:
```py
import numpy as np
import pandas as pd
from pandas import Series, DataFrame
```
為了看數據方便一些,我們設置一下輸出屏幕的寬度
```py
pd.set_option('display.width', 200)
```
## 一、數據創建的其他方式
數據結構的創建不止是上篇中介紹的標準形式,本篇再介紹幾種。例如,我們可以創建一個以日期為元素的`Series`:
```py
dates = pd.date_range('20150101', periods=5)
print dates
<class 'pandas.tseries.index.DatetimeIndex'>
[2015-01-01, ..., 2015-01-05]
Length: 5, Freq: D, Timezone: None
```
將這個日期`Series`作為索引賦給一個`DataFrame`:
```py
df = pd.DataFrame(np.random.randn(5, 4),index=dates,columns=list('ABCD'))
print df
A B C D
2015-01-01 -0.168870 0.191945 -0.906788 -1.295211
2015-01-02 -0.985849 0.312378 -1.513870 -0.876869
2015-01-03 -0.241945 1.437763 0.209494 0.061032
2015-01-04 0.139199 0.124118 -0.204801 -1.745327
2015-01-05 0.243644 -0.373126 0.333583 2.640955
```
只要是能轉換成`Series`的對象,都可以用于創建`DataFrame`:
```py
df2 = pd.DataFrame({ 'A' : 1., 'B': pd.Timestamp('20150214'), 'C': pd.Series(1.6,index=list(range(4)),dtype='float64'), 'D' : np.array([4] * 4, dtype='int64'), 'E' : 'hello pandas!' })
print df2
A B C D E
0 1 2015-02-14 1.6 4 hello pandas!
1 1 2015-02-14 1.6 4 hello pandas!
2 1 2015-02-14 1.6 4 hello pandas!
3 1 2015-02-14 1.6 4 hello pandas!
```
## 二、數據的查看
在多數情況下,數據并不由分析數據的人員生成,而是通過數據接口、外部文件或者其他方式獲取。這里我們通過量化實驗室的數據接口獲取一份數據作為示例:
```py
stock_list = ['000001.XSHE', '000002.XSHE', '000568.XSHE', '000625.XSHE', '000768.XSHE', '600028.XSHG', '600030.XSHG', '601111.XSHG', '601390.XSHG', '601998.XSHG']
raw_data = DataAPI.MktEqudGet(secID=stock_list, beginDate='20150101', endDate='20150131', pandas='1')
df = raw_data[['secID', 'tradeDate', 'secShortName', 'openPrice', 'highestPrice', 'lowestPrice', 'closePrice', 'turnoverVol']]
```
以上代碼獲取了2015年一月份全部的交易日內十支股票的日行情信息,首先我們來看一下數據的大小:
```py
print df.shape
(200, 8)
```
我們可以看到有200行,表示我們獲取到了200條記錄,每條記錄有8個字段,現在預覽一下數據,`dataframe.head()`和`dataframe.tail()`可以查看數據的頭五行和尾五行,若需要改變行數,可在括號內指定:
```py
print "Head of this DataFrame:"
print df.head()
print "Tail of this DataFrame:"
print df.tail(3)
Head of this DataFrame:
secID tradeDate secShortName openPrice highestPrice lowestPrice closePrice turnoverVol
0 000001.XSHE 2015-01-05 平安銀行 15.99 16.28 15.60 16.02 286043643
1 000001.XSHE 2015-01-06 平安銀行 15.85 16.39 15.55 15.78 216642140
2 000001.XSHE 2015-01-07 平安銀行 15.56 15.83 15.30 15.48 170012067
3 000001.XSHE 2015-01-08 平安銀行 15.50 15.57 14.90 14.96 140771421
4 000001.XSHE 2015-01-09 平安銀行 14.90 15.87 14.71 15.08 250850023
Tail of this DataFrame:
secID tradeDate secShortName openPrice highestPrice lowestPrice closePrice turnoverVol
197 601998.XSHG 2015-01-28 中信銀行 7.04 7.32 6.95 7.15 163146128
198 601998.XSHG 2015-01-29 中信銀行 6.97 7.05 6.90 7.01 93003445
199 601998.XSHG 2015-01-30 中信銀行 7.10 7.14 6.92 6.95 68146718
```
`dataframe.describe()`提供了`DataFrame`中純數值數據的統計信息:
```py
print df.describe()
openPrice highestPrice lowestPrice closePrice turnoverVol
count 200.00000 200.000000 200.00000 200.000000 2.000000e+02
mean 15.17095 15.634000 14.86545 15.242750 2.384811e+08
std 7.72807 7.997345 7.56136 7.772184 2.330510e+08
min 6.14000 6.170000 6.02000 6.030000 1.242183e+07
25% 8.09500 8.250000 7.98750 8.127500 7.357002e+07
50% 13.96000 14.335000 13.75500 13.925000 1.554569e+08
75% 19.95000 20.500000 19.46250 20.012500 3.358617e+08
max 36.40000 37.250000 34.68000 36.150000 1.310855e+09
```
對數據的排序將便利我們觀察數據,`DataFrame`提供了兩種形式的排序。一種是按行列排序,即按照索引(行名)或者列名進行排序,可調用`dataframe.sort_index`,指定`axis=0`表示按索引(行名)排序,`axis=1`表示按列名排序,并可指定升序或者降序:
```py
print "Order by column names, descending:"
print df.sort_index(axis=1, ascending=False).head()
Order by column names, descending:
turnoverVol tradeDate secShortName secID openPrice lowestPrice highestPrice closePrice
0 286043643 2015-01-05 平安銀行 000001.XSHE 15.99 15.60 16.28 16.02
1 216642140 2015-01-06 平安銀行 000001.XSHE 15.85 15.55 16.39 15.78
2 170012067 2015-01-07 平安銀行 000001.XSHE 15.56 15.30 15.83 15.48
3 140771421 2015-01-08 平安銀行 000001.XSHE 15.50 14.90 15.57 14.96
4 250850023 2015-01-09 平安銀行 000001.XSHE 14.90 14.71 15.87 15.08
```
第二種排序是按值排序,可指定列名和排序方式,默認的是升序排序:
```py
print "Order by column value, ascending:"
print df.sort(columns='tradeDate').head()
print "Order by multiple columns value:"
df = df.sort(columns=['tradeDate', 'secID'], ascending=[False, True])
print df.head()
Order by column value, ascending:
secID tradeDate secShortName openPrice highestPrice lowestPrice closePrice turnoverVol
0 000001.XSHE 2015-01-05 平安銀行 15.99 16.28 15.60 16.02 286043643
20 000002.XSHE 2015-01-05 萬科A 14.39 15.29 14.22 14.91 656083570
40 000568.XSHE 2015-01-05 瀘州老窖 20.50 21.99 20.32 21.90 59304755
60 000625.XSHE 2015-01-05 長安汽車 16.40 18.07 16.32 18.07 82087982
80 000768.XSHE 2015-01-05 中航飛機 18.76 19.88 18.41 19.33 84199357
Order by multiple columns value:
secID tradeDate secShortName openPrice highestPrice lowestPrice closePrice turnoverVol
19 000001.XSHE 2015-01-30 平安銀行 13.93 14.12 13.76 13.93 93011669
39 000002.XSHE 2015-01-30 萬科A 13.09 13.49 12.80 13.12 209624706
59 000568.XSHE 2015-01-30 瀘州老窖 19.15 19.51 19.11 19.12 14177179
79 000625.XSHE 2015-01-30 長安汽車 19.16 19.45 18.92 19.18 21233495
99 000768.XSHE 2015-01-30 中航飛機 25.38 25.65 24.28 24.60 59550293
```
## 三、數據的訪問和操作
### 3.1 再談數據的訪問
上篇中已經介紹了使用`loc`、`iloc`、`at`、`iat`、`ix`以及`[]`訪問`DataFrame`數據的幾種方式,這里再介紹一種方法,使用`:`來獲取部行或者全部列:
```py
print df.iloc[1:4][:]
secID tradeDate secShortName openPrice highestPrice lowestPrice closePrice turnoverVol
39 000002.XSHE 2015-01-30 萬科A 13.09 13.49 12.80 13.12 209624706
59 000568.XSHE 2015-01-30 瀘州老窖 19.15 19.51 19.11 19.12 14177179
79 000625.XSHE 2015-01-30 長安汽車 19.16 19.45 18.92 19.18 21233495
```
我們可以擴展上篇介紹的使用布爾類型的向量獲取數據的方法,可以很方便地過濾數據,例如,我們要選出收盤價在均值以上的數據:
```py
print df[df.closePrice > df.closePrice.mean()].head()
secID tradeDate secShortName openPrice highestPrice lowestPrice closePrice turnoverVol
59 000568.XSHE 2015-01-30 瀘州老窖 19.15 19.51 19.11 19.12 14177179
79 000625.XSHE 2015-01-30 長安汽車 19.16 19.45 18.92 19.18 21233495
99 000768.XSHE 2015-01-30 中航飛機 25.38 25.65 24.28 24.60 59550293
139 600030.XSHG 2015-01-30 中信證券 28.50 28.72 27.78 27.86 304218245
58 000568.XSHE 2015-01-29 瀘州老窖 19.04 19.23 19.00 19.15 12421826
```
`isin()`函數可方便地過濾`DataFrame`中的數據:
```py
print df[df['secID'].isin(['601628.XSHG', '000001.XSHE', '600030.XSHG'])].head()
print df.shape
secID tradeDate secShortName openPrice highestPrice lowestPrice closePrice turnoverVol
19 000001.XSHE 2015-01-30 平安銀行 13.93 14.12 13.76 13.93 93011669
139 600030.XSHG 2015-01-30 中信證券 28.50 28.72 27.78 27.86 304218245
18 000001.XSHE 2015-01-29 平安銀行 13.82 14.01 13.75 13.90 101675329
138 600030.XSHG 2015-01-29 中信證券 28.10 28.58 27.81 28.18 386310957
17 000001.XSHE 2015-01-28 平安銀行 13.87 14.30 13.80 14.06 124087755
(200, 8)
```
### 3.2 處理缺失數據
在訪問數據的基礎上,我們可以更改數據,例如,修改某些元素為缺失值:
```py
df['openPrice'][df['secID'] == '000001.XSHE'] = np.nan
df['highestPrice'][df['secID'] == '601111.XSHG'] = np.nan
df['lowestPrice'][df['secID'] == '601111.XSHG'] = np.nan
df['closePrice'][df['secID'] == '000002.XSHE'] = np.nan
df['turnoverVol'][df['secID'] == '601111.XSHG'] = np.nan
print df.head(10)
secID tradeDate secShortName openPrice highestPrice lowestPrice closePrice turnoverVol
19 000001.XSHE 2015-01-30 平安銀行 NaN 14.12 13.76 13.93 93011669
39 000002.XSHE 2015-01-30 萬科A 13.09 13.49 12.80 NaN 209624706
59 000568.XSHE 2015-01-30 瀘州老窖 19.15 19.51 19.11 19.12 14177179
79 000625.XSHE 2015-01-30 長安汽車 19.16 19.45 18.92 19.18 21233495
99 000768.XSHE 2015-01-30 中航飛機 25.38 25.65 24.28 24.60 59550293
119 600028.XSHG 2015-01-30 中國石化 6.14 6.17 6.02 6.03 502445638
139 600030.XSHG 2015-01-30 中信證券 28.50 28.72 27.78 27.86 304218245
159 601111.XSHG 2015-01-30 中國國航 7.92 NaN NaN 7.69 NaN
179 601390.XSHG 2015-01-30 中國中鐵 8.69 8.69 8.12 8.14 352357431
199 601998.XSHG 2015-01-30 中信銀行 7.10 7.14 6.92 6.95 68146718
```
原始數據的中很可能存在一些數據的缺失,就如同現在處理的這個樣例數據一樣,處理缺失數據有多種方式。通常使用`dataframe.dropna()`,`dataframe.dropna()`可以按行丟棄帶有`nan`的數據;若指定`how='all'`(默認是`'any'`),則只在整行全部是`nan`時丟棄數據;若指定`thresh`,則表示當某行數據非缺失列數超過指定數值時才保留;要指定根據某列丟棄可以通過`subset`完成。
```py
print "Data size before filtering:"
print df.shape
print "Drop all rows that have any NaN values:"
print "Data size after filtering:"
print df.dropna().shape
print df.dropna().head(10)
print "Drop only if all columns are NaN:"
print "Data size after filtering:"
print df.dropna(how='all').shape
print df.dropna(how='all').head(10)
print "Drop rows who do not have at least six values that are not NaN"
print "Data size after filtering:"
print df.dropna(thresh=6).shape
print df.dropna(thresh=6).head(10)
print "Drop only if NaN in specific column:"
print "Data size after filtering:"
print df.dropna(subset=['closePrice']).shape
print df.dropna(subset=['closePrice']).head(10)
Data size before filtering:
(200, 8)
Drop all rows that have any NaN values:
Data size after filtering:
(140, 8)
secID tradeDate secShortName openPrice highestPrice lowestPrice closePrice turnoverVol
59 000568.XSHE 2015-01-30 瀘州老窖 19.15 19.51 19.11 19.12 14177179
79 000625.XSHE 2015-01-30 長安汽車 19.16 19.45 18.92 19.18 21233495
99 000768.XSHE 2015-01-30 中航飛機 25.38 25.65 24.28 24.60 59550293
119 600028.XSHG 2015-01-30 中國石化 6.14 6.17 6.02 6.03 502445638
139 600030.XSHG 2015-01-30 中信證券 28.50 28.72 27.78 27.86 304218245
179 601390.XSHG 2015-01-30 中國中鐵 8.69 8.69 8.12 8.14 352357431
199 601998.XSHG 2015-01-30 中信銀行 7.10 7.14 6.92 6.95 68146718
58 000568.XSHE 2015-01-29 瀘州老窖 19.04 19.23 19.00 19.15 12421826
78 000625.XSHE 2015-01-29 長安汽車 19.60 19.64 18.90 19.24 25546060
98 000768.XSHE 2015-01-29 中航飛機 24.65 25.63 24.53 24.98 67095945
Drop only if all columns are NaN:
Data size after filtering:
(200, 8)
secID tradeDate secShortName openPrice highestPrice lowestPrice closePrice turnoverVol
19 000001.XSHE 2015-01-30 平安銀行 NaN 14.12 13.76 13.93 93011669
39 000002.XSHE 2015-01-30 萬科A 13.09 13.49 12.80 NaN 209624706
59 000568.XSHE 2015-01-30 瀘州老窖 19.15 19.51 19.11 19.12 14177179
79 000625.XSHE 2015-01-30 長安汽車 19.16 19.45 18.92 19.18 21233495
99 000768.XSHE 2015-01-30 中航飛機 25.38 25.65 24.28 24.60 59550293
119 600028.XSHG 2015-01-30 中國石化 6.14 6.17 6.02 6.03 502445638
139 600030.XSHG 2015-01-30 中信證券 28.50 28.72 27.78 27.86 304218245
159 601111.XSHG 2015-01-30 中國國航 7.92 NaN NaN 7.69 NaN
179 601390.XSHG 2015-01-30 中國中鐵 8.69 8.69 8.12 8.14 352357431
199 601998.XSHG 2015-01-30 中信銀行 7.10 7.14 6.92 6.95 68146718
Drop rows who do not have at least six values that are not NaN
Data size after filtering:
(180, 8)
secID tradeDate secShortName openPrice highestPrice lowestPrice closePrice turnoverVol
19 000001.XSHE 2015-01-30 平安銀行 NaN 14.12 13.76 13.93 93011669
39 000002.XSHE 2015-01-30 萬科A 13.09 13.49 12.80 NaN 209624706
59 000568.XSHE 2015-01-30 瀘州老窖 19.15 19.51 19.11 19.12 14177179
79 000625.XSHE 2015-01-30 長安汽車 19.16 19.45 18.92 19.18 21233495
99 000768.XSHE 2015-01-30 中航飛機 25.38 25.65 24.28 24.60 59550293
119 600028.XSHG 2015-01-30 中國石化 6.14 6.17 6.02 6.03 502445638
139 600030.XSHG 2015-01-30 中信證券 28.50 28.72 27.78 27.86 304218245
179 601390.XSHG 2015-01-30 中國中鐵 8.69 8.69 8.12 8.14 352357431
199 601998.XSHG 2015-01-30 中信銀行 7.10 7.14 6.92 6.95 68146718
18 000001.XSHE 2015-01-29 平安銀行 NaN 14.01 13.75 13.90 101675329
Drop only if NaN in specific column:
Data size after filtering:
(180, 8)
secID tradeDate secShortName openPrice highestPrice lowestPrice closePrice turnoverVol
19 000001.XSHE 2015-01-30 平安銀行 NaN 14.12 13.76 13.93 93011669
59 000568.XSHE 2015-01-30 瀘州老窖 19.15 19.51 19.11 19.12 14177179
79 000625.XSHE 2015-01-30 長安汽車 19.16 19.45 18.92 19.18 21233495
99 000768.XSHE 2015-01-30 中航飛機 25.38 25.65 24.28 24.60 59550293
119 600028.XSHG 2015-01-30 中國石化 6.14 6.17 6.02 6.03 502445638
139 600030.XSHG 2015-01-30 中信證券 28.50 28.72 27.78 27.86 304218245
159 601111.XSHG 2015-01-30 中國國航 7.92 NaN NaN 7.69 NaN
179 601390.XSHG 2015-01-30 中國中鐵 8.69 8.69 8.12 8.14 352357431
199 601998.XSHG 2015-01-30 中信銀行 7.10 7.14 6.92 6.95 68146718
18 000001.XSHE 2015-01-29 平安銀行 NaN 14.01 13.75 13.90 101675329
```
有數據缺失時也未必是全部丟棄,`dataframe.fillna(value=value)`可以指定填補缺失值的數值
```py
print df.fillna(value=20150101).head()
secID tradeDate secShortName openPrice highestPrice lowestPrice closePrice turnoverVol
19 000001.XSHE 2015-01-30 平安銀行 20150101.00 14.12 13.76 13.93 93011669
39 000002.XSHE 2015-01-30 萬科A 13.09 13.49 12.80 20150101.00 209624706
59 000568.XSHE 2015-01-30 瀘州老窖 19.15 19.51 19.11 19.12 14177179
79 000625.XSHE 2015-01-30 長安汽車 19.16 19.45 18.92 19.18 21233495
99 000768.XSHE 2015-01-30 中航飛機 25.38 25.65 24.28 24.60 59550293
```
### 3.3 數據操作
`Series`和`DataFrame`的類函數提供了一些函數,如`mean()`、`sum()`等,指定0按列進行,指定1按行進行:
```py
df = raw_data[['secID', 'tradeDate', 'secShortName', 'openPrice', 'highestPrice', 'lowestPrice', 'closePrice', 'turnoverVol']]
print df.mean(0)
openPrice 1.517095e+01
highestPrice 1.563400e+01
lowestPrice 1.486545e+01
closePrice 1.524275e+01
turnoverVol 2.384811e+08
dtype: float64
```
`value_counts`函數可以方便地統計頻數:
```py
print df['closePrice'].value_counts().head()
6.58 3
13.12 2
9.13 2
8.58 2
6.93 2
dtype: int64
```
在`panda`中,`Series`可以調用`map`函數來對每個元素應用一個函數,`DataFrame`可以調用`apply`函數對每一列(行)應用一個函數,`applymap`對每個元素應用一個函數。這里面的函數可以是用戶自定義的一個lambda函數,也可以是已有的其他函數。下例展示了將收盤價調整到`[0, 1]`區間:
```py
print df[['closePrice']].apply(lambda x: (x - x.min()) / (x.max() - x.min())).head()
closePrice
0 0.331673
1 0.323705
2 0.313745
3 0.296481
4 0.300465
```
使用`append`可以在`Series`后添加元素,以及在`DataFrame`尾部添加一行:
```py
dat1 = df[['secID', 'tradeDate', 'closePrice']].head()
dat2 = df[['secID', 'tradeDate', 'closePrice']].iloc[2]
print "Before appending:"
print dat1
dat = dat1.append(dat2, ignore_index=True)
print "After appending:"
print dat
Before appending:
secID tradeDate closePrice
0 000001.XSHE 2015-01-05 16.02
1 000001.XSHE 2015-01-06 15.78
2 000001.XSHE 2015-01-07 15.48
3 000001.XSHE 2015-01-08 14.96
4 000001.XSHE 2015-01-09 15.08
After appending:
secID tradeDate closePrice
0 000001.XSHE 2015-01-05 16.02
1 000001.XSHE 2015-01-06 15.78
2 000001.XSHE 2015-01-07 15.48
3 000001.XSHE 2015-01-08 14.96
4 000001.XSHE 2015-01-09 15.08
5 000001.XSHE 2015-01-07 15.48
```
`DataFrame`可以像在SQL中一樣進行合并,在上篇中,我們介紹了使用`concat`函數創建`DataFrame`,這就是一種合并的方式。另外一種方式使用`merge`函數,需要指定依照哪些列進行合并,下例展示了如何根據security ID和交易日合并數據:
```py
dat1 = df[['secID', 'tradeDate', 'closePrice']]
dat2 = df[['secID', 'tradeDate', 'turnoverVol']]
dat = dat1.merge(dat2, on=['secID', 'tradeDate'])
print "The first DataFrame:"
print dat1.head()
print "The second DataFrame:"
print dat2.head()
print "Merged DataFrame:"
print dat.head()
The first DataFrame:
secID tradeDate closePrice
0 000001.XSHE 2015-01-05 16.02
1 000001.XSHE 2015-01-06 15.78
2 000001.XSHE 2015-01-07 15.48
3 000001.XSHE 2015-01-08 14.96
4 000001.XSHE 2015-01-09 15.08
The second DataFrame:
secID tradeDate turnoverVol
0 000001.XSHE 2015-01-05 286043643
1 000001.XSHE 2015-01-06 216642140
2 000001.XSHE 2015-01-07 170012067
3 000001.XSHE 2015-01-08 140771421
4 000001.XSHE 2015-01-09 250850023
Merged DataFrame:
secID tradeDate closePrice turnoverVol
0 000001.XSHE 2015-01-05 16.02 286043643
1 000001.XSHE 2015-01-06 15.78 216642140
2 000001.XSHE 2015-01-07 15.48 170012067
3 000001.XSHE 2015-01-08 14.96 140771421
4 000001.XSHE 2015-01-09 15.08 250850023
```
`DataFrame`另一個強大的函數是`groupby`,可以十分方便地對數據分組處理,我們對2015年一月內十支股票的開盤價,最高價,最低價,收盤價和成交量求平均值:
```py
df_grp = df.groupby('secID')
grp_mean = df_grp.mean()
print grp_mean
openPrice highestPrice lowestPrice closePrice turnoverVol
secID
000001.XSHE 14.6550 14.9840 14.4330 14.6650 154710615
000002.XSHE 13.3815 13.7530 13.0575 13.4100 277459431
000568.XSHE 19.7220 20.1015 19.4990 19.7935 29199107
000625.XSHE 19.4915 20.2275 19.1040 19.7170 42633332
000768.XSHE 22.4345 23.4625 21.8830 22.6905 92781199
600028.XSHG 6.6060 6.7885 6.4715 6.6240 531966632
600030.XSHG 31.1505 32.0825 30.4950 31.2325 611544509
601111.XSHG 8.4320 8.6520 8.2330 8.4505 104143358
601390.XSHG 8.4060 8.6625 8.2005 8.4100 362831455
601998.XSHG 7.4305 7.6260 7.2780 7.4345 177541066
```
如果希望取每只股票的最新數據,應該怎么操作呢?`drop_duplicates`可以實現這個功能,首先對數據按日期排序,再按security ID去重:
```py
df2 = df.sort(columns=['secID', 'tradeDate'], ascending=[True, False])
print df2.drop_duplicates(subset='secID')
secID tradeDate secShortName openPrice highestPrice lowestPrice closePrice turnoverVol
19 000001.XSHE 2015-01-30 平安銀行 13.93 14.12 13.76 13.93 93011669
39 000002.XSHE 2015-01-30 萬科A 13.09 13.49 12.80 13.12 209624706
59 000568.XSHE 2015-01-30 瀘州老窖 19.15 19.51 19.11 19.12 14177179
79 000625.XSHE 2015-01-30 長安汽車 19.16 19.45 18.92 19.18 21233495
99 000768.XSHE 2015-01-30 中航飛機 25.38 25.65 24.28 24.60 59550293
119 600028.XSHG 2015-01-30 中國石化 6.14 6.17 6.02 6.03 502445638
139 600030.XSHG 2015-01-30 中信證券 28.50 28.72 27.78 27.86 304218245
159 601111.XSHG 2015-01-30 中國國航 7.92 8.03 7.65 7.69 61877792
179 601390.XSHG 2015-01-30 中國中鐵 8.69 8.69 8.12 8.14 352357431
199 601998.XSHG 2015-01-30 中信銀行 7.10 7.14 6.92 6.95 68146718
```
若想要保留最老的數據,可以在降序排列后取最后一個記錄,通過指定`take_last=True`(默認值為`False`,取第一條記錄)可以實現:
```py
print df2.drop_duplicates(subset='secID', take_last=True)
secID tradeDate secShortName openPrice highestPrice lowestPrice closePrice turnoverVol
0 000001.XSHE 2015-01-05 平安銀行 15.99 16.28 15.60 16.02 286043643
20 000002.XSHE 2015-01-05 萬科A 14.39 15.29 14.22 14.91 656083570
40 000568.XSHE 2015-01-05 瀘州老窖 20.50 21.99 20.32 21.90 59304755
60 000625.XSHE 2015-01-05 長安汽車 16.40 18.07 16.32 18.07 82087982
80 000768.XSHE 2015-01-05 中航飛機 18.76 19.88 18.41 19.33 84199357
100 600028.XSHG 2015-01-05 中國石化 6.59 7.14 6.45 7.14 1186499645
120 600030.XSHG 2015-01-05 中信證券 33.90 35.25 33.01 34.66 698627215
140 601111.XSHG 2015-01-05 中國國航 7.98 8.62 7.98 8.62 231611758
160 601390.XSHG 2015-01-05 中國中鐵 9.37 9.37 8.90 9.13 469902172
180 601998.XSHG 2015-01-05 中信銀行 8.15 8.33 7.91 8.16 337368242
```
## 四、數據可視化
`pandas`數據直接可以繪圖查看,下例中我們采用中國石化一月的收盤價進行繪圖,其中`set_index('tradeDate')['closePrice']`表示將`DataFrame`的`'tradeDate'`這一列作為索引,將`'closePrice'`這一列作為`Series`的值,返回一個`Series`對象,隨后調用`plot`函數繪圖,更多的參數可以在`matplotlib`的文檔中查看。
```py
dat = df[df['secID'] == '600028.XSHG'].set_index('tradeDate')['closePrice']
dat.plot(title="Close Price of SINOPEC (600028) during Jan, 2015")
<matplotlib.axes.AxesSubplot at 0x49b6510>
```

- Python 量化交易教程
- 第一部分 新手入門
- 一 量化投資視頻學習課程
- 二 Python 手把手教學
- 量化分析師的Python日記【第1天:誰來給我講講Python?】
- 量化分析師的Python日記【第2天:再接著介紹一下Python唄】
- 量化分析師的Python日記【第3天:一大波金融Library來襲之numpy篇】
- 量化分析師的Python日記【第4天:一大波金融Library來襲之scipy篇】
- 量化分析師的Python日記【第5天:數據處理的瑞士軍刀pandas】
- 量化分析師的Python日記【第6天:數據處理的瑞士軍刀pandas下篇
- 量化分析師的Python日記【第7天:Q Quant 之初出江湖】
- 量化分析師的Python日記【第8天 Q Quant兵器譜之函數插值】
- 量化分析師的Python日記【第9天 Q Quant兵器譜之二叉樹】
- 量化分析師的Python日記【第10天 Q Quant兵器譜 -之偏微分方程1】
- 量化分析師的Python日記【第11天 Q Quant兵器譜之偏微分方程2】
- 量化分析師的Python日記【第12天:量化入門進階之葵花寶典:因子如何產生和回測】
- 量化分析師的Python日記【第13天 Q Quant兵器譜之偏微分方程3】
- 量化分析師的Python日記【第14天:如何在優礦上做Alpha對沖模型】
- 量化分析師的Python日記【第15天:如何在優礦上搞一個wealthfront出來】
- 第二部分 股票量化相關
- 一 基本面分析
- 1.1 alpha 多因子模型
- 破解Alpha對沖策略——觀《量化分析師Python日記第14天》有感
- 熔斷不要怕, alpha model 為你保駕護航!
- 尋找 alpha 之: alpha 設計
- 1.2 基本面因子選股
- Porfolio(現金比率+負債現金+現金保障倍數)+市盈率
- ROE選股指標
- 成交量因子
- ROIC&cashROIC
- 【國信金工】資產周轉率選股模型
- 【基本面指標】Cash Cow
- 量化因子選股——凈利潤/營業總收入
- 營業收入增長率+市盈率
- 1.3 財報閱讀 ? [米缸量化讀財報] 資產負債表-投資相關資產
- 1.4 股東分析
- 技術分析入門 【2】 —— 大家搶籌碼(06年至12年版)
- 技術分析入門 【2】 —— 大家搶籌碼(06年至12年版)— 更新版
- 誰是中國A股最有錢的自然人
- 1.5 宏觀研究
- 【干貨包郵】手把手教你做宏觀擇時
- 宏觀研究:從估值角度看當前市場
- 追尋“國家隊”的足跡
- 二 套利
- 2.1 配對交易
- HS300ETF套利(上)
- 【統計套利】配對交易
- 相似公司股票搬磚
- Paired trading
- 2.2 期現套利 ? 通過股指期貨的期現差與 ETF 對沖套利
- 三 事件驅動
- 3.1 盈利預增
- 盈利預增事件
- 事件驅動策略示例——盈利預增
- 3.2 分析師推薦 ? 分析師的金手指?
- 3.3 牛熊轉換
- 歷史總是相似 牛市還在延續
- 歷史總是相似 牛市已經見頂?
- 3.4 熔斷機制 ? 股海拾貝之 [熔斷錯殺股]
- 3.5 暴漲暴跌 ? [實盤感悟] 遇上暴跌我該怎么做?
- 3.6 兼并重組、舉牌收購 ? 寶萬戰-大戲開幕
- 四 技術分析
- 4.1 布林帶
- 布林帶交易策略
- 布林帶回調系統-日內
- Conservative Bollinger Bands
- Even More Conservative Bollinger Bands
- Simple Bollinger Bands
- 4.2 均線系統
- 技術分析入門 —— 雙均線策略
- 5日線10日線交易策略
- 用5日均線和10日均線進行判斷 --- 改進版
- macross
- 4.3 MACD
- Simple MACD
- MACD quantization trade
- MACD平滑異同移動平均線方法
- 4.4 阿隆指標 ? 技術指標阿隆( Aroon )全解析
- 4.5 CCI ? CCI 順勢指標探索
- 4.6 RSI
- 重寫 rsi
- RSI指標策略
- 4.7 DMI ? DMI 指標體系的構建及簡單應用
- 4.8 EMV ? EMV 技術指標的構建及應用
- 4.9 KDJ ? KDJ 策略
- 4.10 CMO
- CMO 策略模仿練習 1
- CMO策略模仿練習2
- [技術指標] CMO
- 4.11 FPC ? FPC 指標選股
- 4.12 Chaikin Volatility
- 嘉慶離散指標測試
- 4.13 委比 ? 實時計算委比
- 4.14 封單量
- 按照封單跟流通股本比例排序,剔除6月上市新股,前50
- 漲停股票封單統計
- 實時計算漲停板股票的封單資金與總流通市值的比例
- 4.15 成交量 ? 決戰之地, IF1507 !
- 4.16 K 線分析 ? 尋找夜空中最亮的星
- 五 量化模型
- 5.1 動量模型
- Momentum策略
- 【小散學量化】-2-動量模型的簡單實踐
- 一個追漲的策略(修正版)
- 動量策略(momentum driven)
- 動量策略(momentum driven)——修正版
- 最經典的Momentum和Contrarian在中國市場的測試
- 最經典的Momentum和Contrarian在中國市場的測試-yanheven改進
- [策略]基于勝率的趨勢交易策略
- 策略探討(更新):價量結合+動量反轉
- 反向動量策略(reverse momentum driven)
- 輕松跑贏大盤 - 主題Momentum策略
- Contrarian strategy
- 5.2 Joseph Piotroski 9 F-Score Value Investing Model · 基本面選股系統:Piotroski F-Score ranking system
- 5.3 SVR · 使用SVR預測股票開盤價 v1.0
- 5.4 決策樹、隨機樹
- 決策樹模型(固定模型)
- 基于Random Forest的決策策略
- 5.5 鐘擺理論 · 鐘擺理論的簡單實現——完美躲過股災和精準抄底
- 5.6 海龜模型
- simple turtle
- 俠之大者 一起賺錢
- 5.7 5217 策略 · 白龍馬的新手策略
- 5.8 SMIA · 基于歷史狀態空間相似性匹配的行業配置 SMIA 模型—取交集
- 5.9 神經網絡
- 神經網絡交易的訓練部分
- 通過神經網絡進行交易
- 5.10 PAMR · PAMR : 基于均值反轉的投資組合選擇策略 - 修改版
- 5.11 Fisher Transform · Using Fisher Transform Indicator
- 5.12 分型假說, Hurst 指數 · 分形市場假說,一個聽起來很美的假說
- 5.13 變點理論 · 變點策略初步
- 5.14 Z-score Model
- Zscore Model Tutorial
- 信用債風險模型初探之:Z-Score Model
- user-defined package
- 5.15 機器學習 · Machine Learning 學習筆記(一) by OTreeWEN
- 5.16 DualTrust 策略和布林強盜策略
- 5.17 卡爾曼濾波
- 5.18 LPPL anti-bubble model
- 今天大盤熔斷大跌,后市如何—— based on LPPL anti-bubble model
- 破解股市泡沫之謎——對數周期冪率(LPPL)模型
- 六 大數據模型
- 6.1 市場情緒分析
- 通聯情緒指標策略
- 互聯網+量化投資 大數據指數手把手
- 6.2 新聞熱點
- 如何使用優礦之“新聞熱點”?
- 技術分析【3】—— 眾星拱月,眾口鑠金?
- 七 排名選股系統
- 7.1 小市值投資法
- 學習筆記:可模擬(小市值+便宜 的修改版)
- 市值最小300指數
- 流通市值最小股票(新篩選器版)
- 持有市值最小的10只股票
- 10% smallest cap stock
- 7.2 羊駝策略
- 羊駝策略
- 羊駝反轉策略(修改版)
- 羊駝反轉策略
- 我的羊駝策略,選5只股無腦輪替
- 7.3 低價策略
- 專撿便宜貨(新版quartz)
- 策略原理
- 便宜就是 alpha
- 八 輪動模型
- 8.1 大小盤輪動 · 新手上路 -- 二八ETF擇時輪動策略2.0
- 8.2 季節性策略
- Halloween Cycle
- Halloween cycle 2
- 夏買電,東買煤?
- 歷史的十一月板塊漲幅
- 8.3 行業輪動
- 銀行股輪動
- 申萬二級行業在最近1年、3個月、5個交易日的漲幅統計
- 8.4 主題輪動
- 快速研究主題神器
- recommendation based on subject
- strategy7: recommendation based on theme
- 板塊異動類
- 風險因子(離散類)
- 8.5 龍頭輪動
- Competitive Securities
- Market Competitiveness
- 主題龍頭類
- 九 組合投資
- 9.1 指數跟蹤 · [策略] 指數跟蹤低成本建倉策略
- 9.2 GMVP · Global Minimum Variance Portfolio (GMVP)
- 9.3 凸優化 · 如何在 Python 中利用 CVXOPT 求解二次規劃問題
- 十 波動率
- 10.1 波動率選股 · 風平浪靜 風起豬飛
- 10.2 波動率擇時
- 基于 VIX 指數的擇時策略
- 簡單低波動率指數
- 10.3 Arch/Garch 模型 · 如何使用優礦進行 GARCH 模型分析
- 十一 算法交易
- 11.1 VWAP · Value-Weighted Average Price (VWAP)
- 十二 中高頻交易
- 12.1 order book 分析 · 基于高頻 limit order book 數據的短程價格方向預測—— via multi-class SVM
- 12.2 日內交易 · 大盤日內走勢 (for 擇時)
- 十三 Alternative Strategy
- 13.1 易經、傳統文化 · 老黃歷診股
- 第三部分 基金、利率互換、固定收益類
- 一 分級基金
- “優礦”集思錄——分級基金專題
- 基于期權定價的分級基金交易策略
- 基于期權定價的興全合潤基金交易策略
- 二 基金分析
- Alpha 基金“黑天鵝事件” -- 思考以及原因
- 三 債券
- 債券報價中的小陷阱
- 四 利率互換
- Swap Curve Construction
- 中國 Repo 7D 互換的例子
- 第四部分 衍生品相關
- 一 期權數據
- 如何獲取期權市場數據快照
- 期權高頻數據準備
- 二 期權系列
- [ 50ETF 期權] 1. 歷史成交持倉和 PCR 數據
- 【50ETF期權】 2. 歷史波動率
- 【50ETF期權】 3. 中國波指 iVIX
- 【50ETF期權】 4. Greeks 和隱含波動率微笑
- 【50ETF期權】 5. 日內即時監控 Greeks 和隱含波動率微笑
- 【50ETF期權】 5. 日內即時監控 Greeks 和隱含波動率微笑
- 三 期權分析
- 【50ETF期權】 期權擇時指數 1.0
- 每日期權風險數據整理
- 期權頭寸計算
- 期權探秘1
- 期權探秘2
- 期權市場一周縱覽
- 基于期權PCR指數的擇時策略
- 期權每日成交額PC比例計算
- 四 期貨分析
- 【前方高能!】Gifts from Santa Claus——股指期貨趨勢交易研究