# PythonProgramming.net Python 和 Pandas 數據分析教程
> 原文:[Data Analysis with Python and Pandas Tutorial Introduction](https://pythonprogramming.net/data-analysis-python-pandas-tutorial-introduction/)
> 譯者:[飛龍](https://github.com/)
> 協議:[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/)
大家好,歡迎閱讀 Python 和 Pandas 數據分析系列教程。 Pandas 是一個 Python 模塊,Python 是我們要使用的編程語言。Pandas 模塊是一個高性能,高效率,高水平的數據分析庫。
它的核心就像操作一個電子表格的無頭版本,比如 Excel。你使用的大多數數據集將是所謂的數據幀(`DataFrame`)。你可能已經熟悉這個術語,它也用于其他語言,但是如果沒有,數據幀通常就像電子表格一樣,擁有列和行,這就是它了!從這里開始,我們可以利用 Pandas 以閃電般的速度操作我們的數據集。
Pandas 還與許多其他數據分析庫兼容,如用于機器學習的 Scikit-Learn,用于圖形的 Matplotlib,NumPy,因為它使用 NumPy ,以及其他。這些是非常強大和寶貴的。如果你發現自己使用 Excel 或者一般電子表格來執行各種計算任務,那么他們可能需要一分鐘或者一小時來運行,Pandas 將會改變你的生活。我甚至已經看到機器學習的版本,如 K-Means 聚類在 Excel 上完成。這真的很酷,但是我的 Python 會為你做得更快,這也將使你對參數要求更嚴格,擁有更大的數據集,并且能夠完成更多的工作。
還有一個好消息。你可以很容易加載和輸出`xls`或`xlsx`格式的文件,所以,即使你的老板想用舊的方式來查看,他們也可以。Pandas 還可以兼容文本文件,`csv`,`hdf`文件,`xml`,`html`等等,其 IO 非常強大。
如果你剛剛入門 Python,那么你應該可以繼續學習,而不必精通 Python,這甚至可以讓你入門 Python 。最重要的是,如果你有問題,問問他們!如果你為每一個困惑的領域尋找答案,并為此做好每件事,那么最終你會有一個完整的認識。你的大部分問題都可以通過 Google 解決。不要害怕 Google 你的問題,它不會嘲笑你,我保證。我仍然 Google 了我的很多目標,看看是否有人有一些示例代碼,做了我想做的事情,所以不要僅僅因為你這樣做了,而覺得你是個新手。
如果我還沒有把 Pandas 推銷給你,那么電梯演講就是:電子表格式數據的閃電般的數據分析,具有非常強大的輸入/輸出機制,可以處理多種數據類型,甚至可以轉換數據類型。
好的,你被推銷了。現在讓我們獲取 Pandas!首先,我將假設有些人甚至還沒有 Python。到目前為止,最簡單的選擇是使用預編譯的 Python 發行版,比如 ActivePython,它是個快速簡單的方式,將數據科學所需的所有包和依賴關系都集中在一起,而不需要一個接一個安裝它們,特別是在 64 位 Windows 上。我建議獲取最新版本的 64 位 Python。僅在這個系列中,我們使用 Pandas ,它需要 Numpy。我們還將使用 Matplotlib 和 Scikit-Learn,所有這些都是 ActivePython 自帶的,預先編譯和優化的 MKL。你可以從這里下載一個配置完整的 Python 發行版。
如果你想手動安裝 Python,請轉到`Python.org`,然后下載 Python 3+ 或更高版本。不要僅僅獲取`2.X`。記下你下載的位版本。因為你的操作系統是 64 位的,這并是你的 Python 版本,默認總是 32 位。選擇你想要的。 64 位可能有點頭疼,所以如果你是新手,我不會推薦它,但 64 位是數據科學的理想選擇,所以你不會被鎖定在最大 2GB 的 RAM 上。如果你想裝 64 位,查看`pip`安裝教程可能有幫助,其中介紹了如何處理常規安裝以及更棘手的 64 位軟件包。如果你使用 32 位,那么現在不用擔心這個教程。
所以你已經安裝了 Python。接下來,轉到你的終端或`cmd.exe`,然后鍵入:`pip install pandas`。你有沒有得到`pip is not a recognized command`或類似的東西?沒問題,這意味著`pip`不在你的`PATH`中。`pip`是一個程序,但是你的機器不知道它在哪里,除非它在你的`PATH`中。如果你愿意,你可以搜索如何添加一些東西到你的`PATH`中,但是你總是可以顯式提供你想要執行的程序的路徑。例如,在 Windows 上,Python 的`pip`位于`C:/Python34/Scripts/pip`中。 `Python34`的意思是 Python 3.4。如果你擁有 Python 3.6,那么你需要使用`Python36`,以此類推。
因此,如果常規的`pip install pandas`不起作用,那么你可以執行`C:/Python34/Scripts/pip install pandas`。
到了這里,人們爭論的另一個重點是他們選擇的編輯器。編輯器在事物的宏觀層面中并不重要。你應該嘗試多個編輯器,并選擇最適合你的編輯器。無論哪個,只要你感到舒適,而且你的工作效率很高,這是最重要的。一些雇主也會迫使你最終使用編輯器 X,Y 或 Z,所以你可能不應該依賴編輯器功能。因此,我更喜歡簡單的 IDLE,這就是我將用于編程的東西。再次,你可以在 Wing,emacs,Nano,Vim,PyCharm,IPython 中編程,你可以隨便選一個。要打開 IDLE,只需訪問開始菜單,搜索 IDLE,然后選擇它。在這里,`File > New`,砰的一下,你就有了帶高亮的文本編輯器和其他一些小東西。我們將在進行中介紹一些這些次要的事情。
現在,無論你使用哪種編輯器,都可以打開它,讓我們編寫一些簡單的代碼來查看數據幀。
通常,`DataFrame`最接近 Python `Dictionary` 數據結構。如果你不熟悉字典,這里有一個教程。我將在視頻中注明類似的東西,并且在描述中,以及在`PythonProgramming.net`上的文本版教程中有鏈接。
首先,我們來做一些簡單的導入:
```py
import pandas as pd
import datetime
import pandas.io.data as web
```
在這里,我們將`pandas`導入為`pd`。 這只是導入`pandas`模塊時使用的常用標準。 接下來,我們導入`datetime`,我們稍后將使用它來告訴 Pandas 一些日期,我們想要拉取它們之間的數據。 最后,我們將`pandas.io.data`導入為`web`,因為我們將使用它來從互聯網上獲取數據。 接下來:
```py
start = datetime.datetime(2010, 1, 1)
end = datetime.datetime(2015, 8, 22)
```
在這里,我們創建`start`和`end`變量,這些變量是`datetime`對象,獲取 2010 年 1 月 1 日到 2015 年 8 月 22 日的數據。現在,我們可以像這樣創建數據幀:
```py
df = web.DataReader("XOM", "yahoo", start, end)
```
這從雅虎財經 API 獲取 Exxon 的數據,存儲到我們的`df`變量。 將你的數據幀命名為`df`不是必需的,但是它頁是用于 Pandas 的非常主流的標準。 它只是幫助人們立即識別活動數據幀,而無需追溯代碼。
所以這給了我們一個數據幀,我們怎么查看它? 那么,可以打印它,就像這樣:
```py
print(df)
```
所以這是很大一個空間。 數據集的中間被忽略,但仍然是大量輸出。 相反,大多數人只會這樣做:
```py
print(df.head())
```
輸出:
```
Open High Low Close Volume Adj Close
Date
2010-01-04 68.720001 69.260002 68.190002 69.150002 27809100 59.215446
2010-01-05 69.190002 69.449997 68.800003 69.419998 30174700 59.446653
2010-01-06 69.449997 70.599998 69.339996 70.019997 35044700 59.960452
2010-01-07 69.900002 70.059998 69.419998 69.800003 27192100 59.772064
2010-01-08 69.690002 69.750000 69.220001 69.519997 24891800 59.532285
```
這打印了數據幀的前 5 行,并且對于調試很有用,只查看了數據幀的外觀。 當你執行分析等,看看你想要的東西是否實際發生了,就很有用。 不過,我們稍后會深入它。
我們可以在這里停止介紹,但還有一件事:數據可視化。 我之前說過,Pandas 和其他模塊配合的很好,Matplotlib 就是其中之一。 讓我們來看看! 打開你的終端或`cmd.exe`,并執行`pip install matplotlib`。 你安裝完 Pandas,我確信你應該已經獲取了它,但我們要證實一下。 現在,在腳本的頂部,和其他導入一起,添加:
```py
import matplotlib.pyplot as plt
from matplotlib import style
style.use('fivethirtyeight')
```
Pyplot 是 matplotlib 的基本繪圖模塊。 Style 幫助我們快速美化圖形,`style.use`讓我們選擇風格。 有興趣了解 Matplotlib 的更多信息嗎? 查看 Matplotlib 的深入系列教程!
接下來,在我們的`print(df.head())`下方,我們可以執行如下操作:
```py
df['High'].plot()
plt.legend()
plt.show()
```

很酷! 這里有個 pandas 的快速介紹,但一點也不可用。 在這個系列中,我們將會涉及更多 Pandas 的基礎知識,然后轉到導航和處理數據幀。 從這里開始,我們將更多地介紹可視化,多種數據格式的輸入和輸出,基本和進階數據分析和操作,合并和組合數據幀,重復取樣等等。
如果你迷茫,困惑,或需要澄清,請不要猶豫,給對應的視頻提問。
## 二、Pandas 基礎
在這個 Python 和 Pandas 數據分析教程中,我們將弄清一些 Pandas 的基礎知識。 加載到 Pandas 數據幀之前,數據可能有多種形式,但通常需要是以行和列組成的數據集。 所以也許是這樣的字典:
```py
web_stats = {'Day':[1,2,3,4,5,6],
'Visitors':[43,34,65,56,29,76],
'Bounce Rate':[65,67,78,65,45,52]}
```
我們可以將這個字典轉換成數據幀,通過這樣:
```py
import pandas as pd
web_stats = {'Day':[1,2,3,4,5,6],
'Visitors':[43,34,65,56,29,76],
'Bounce Rate':[65,67,78,65,45,52]}
df = pd.DataFrame(web_stats)
```
現在我們可以做什么?之前看到,你可以通過這樣來查看簡單的起始片段:
```py
print(df.head())
```
```
Bounce Rate Day Visitors
0 65 1 43
1 67 2 34
2 78 3 65
3 65 4 56
4 45 5 29
```
你也可以查看后幾行。為此,你需要這樣做:
```py
print(df.tail())
```
```
Bounce Rate Day Visitors
1 67 2 34
2 78 3 65
3 65 4 56
4 45 5 29
5 52 6 76
```
最后,你也可以傳入頭部和尾部數量,像這樣:
```py
print(df.tail(2))
```
```
Bounce Rate Day Visitors
4 45 5 29
5 52 6 76
```
你可以在這里看到左邊有這些數字,`0,1,2,3,4,5`等等,就像行號一樣。 這些數字實際上是你的“索引”。 數據幀的索引是數據相關,或者數據按它排序的東西。 一般來說,這將是連接所有數據的變量。 這里,我們從來沒有為此目的定義任何東西,知道這個變量是什么,對于 Pandas 是個挑戰。 因此,當你沒有定義索引時,Pandas 會像這樣為你生成一個。 現在看數據集,你能看到連接其他列的列嗎?
`Day`列適合這個東西! 一般來說,如果你有任何日期數據,日期將成為“索引”,因為這就是所有數據點的關聯方式。 有很多方法可以識別索引,更改索引等等。 我們將在這里介紹一些。 首先,在任何現有的數據幀上,我們可以像這樣設置一個新的索引:
```
df.set_index('Day', inplace=True)
```
輸出:
```py
Bounce Rate Visitors
Day
1 65 43
2 67 34
3 78 65
4 65 56
5 45 29
```
現在你可以看到這些行號已經消失了,同時也注意到`Day`比其他列標題更低,這是為了表示索引。 有一點需要注意的是`inplace = True`的使用。 這允許我們原地修改數據幀,意味著我們實際上修改了變量本身。 沒有`inplace = True`,我們需要做一些事情:
```py
df = df.set_index('Day')
```
你也可以設置多個索引,但這是以后的更高級的主題。 你可以很容易做到這一點,但它的原因相當合理。
一旦你有了合理的索引,是一個日期時間或數字,那么它將作為一個 X 軸。 如果其他列也是數值數據,那么你可以輕松繪圖。 就像我們之前做的那樣,繼續并執行:
```py
import matplotlib.pyplot as plt
from matplotlib import style
style.use('fivethirtyeight')
```
然后,在底部,你可以繪圖。 還記得我們之前引用了特定的列嘛?也許你注意到了,但是我們可以像這樣,引用數據幀中的特定項目:
```py
print(df['Visitors'])
```
```
Day
1 43
2 34
3 65
4 56
5 29
6 76
Name: Visitors, dtype: int64
```
你也可以像對象一樣引用數據幀的部分,只要沒有空格,就可以這樣做:
```py
print(df.Visitors)
```
```
Day
1 43
2 34
3 65
4 56
5 29
6 76
Name: Visitors, dtype: int64
```
所以我們可以像這樣繪制單列:
```py
df['Visitors'].plot()
plt.show()
```
我們也可以繪制整個數據幀。 只要數據是規范化的或者在相同的刻度上,效果會很好。 這是一個例子:
```py
df.plot()
plt.show()
```
注意圖例如何自動添加。 你可能會喜歡的另一個很好的功能是,圖例也自動為實際繪制的直線讓路。 如果你是 Python 和 Matplotlib 的新手,這可能對你來說并不重要,但這不是一個正常的事情。
最后,在我們離開之前,你也可以一次引用多個列,就像這樣(我們只有兩列,但是多列相同):
```py
print(df[['Visitors','Bounce Rate']])
```
所以這是括起來的列標題列表。 你也可以繪制這個。
這些是一些方法,你可以直接與數據幀進行交互,引用數據框的各個方面,帶有一個示例,繪制了這些特定的方面。
## 三、IO 基礎
歡迎閱讀 Pandas 和 Python 數據分析第三部分。在本教程中,我們將開始討論 Pandas IO 即輸入/輸出,并從一個實際的用例開始。為了得到充分的實踐,一個非常有用的網站是 Quandl。 Quandl 包含大量的免費和付費數據源。這個站點的好處在于數據通常是標準化的,全部在一個地方,提取數據的方法是一樣的。如果你使用的是 Python,并且通過它們的簡單模塊訪問 Quandl 數據,那么數據將自動以數據幀返回。出于本教程的目的,我們將僅僅出于學習的目的而手動下載一個 CSV 文件,因為并不是每個數據源都會有一個完美的模塊用于提取數據集。
假設我們有興趣,在德克薩斯州的奧斯汀購買或出售房屋。那里的郵政編碼是 77006。我們可以訪問當地的房源清單,看看目前的價格是多少,但這并不能真正為我們提供任何真實的歷史信息,所以我們只是試圖獲得一些數據。讓我們來查詢“房屋價值指數 77006”。果然,我們可以在這里看到一個索引。有頂層,中層,下層,三居室,等等。比方說,當然,我們有一個三居室的房子。我們來檢查一下。原來 Quandl 已經提供了圖表,但是我們還是要抓取數據集,制作自己的圖表,或者做一些其他的分析。訪問“下載”,并選擇 CSV。Pandas 的 IO 兼容 csv,excel 數據,hdf,sql,json,msgpack,html,gbq,stata,剪貼板和 pickle 數據,并且列表不斷增長。查看 IO 工具文檔的當前列表。將該 CSV 文件移動到本地目錄(你正在使用的目錄/這個`.py`腳本所在的目錄)。
以這個代碼開始,將 CSV 加載進數據幀就是這樣簡單:
```py
import pandas as pd
df = pd.read_csv('ZILL-Z77006_3B.csv')
print(df.head())
```
輸出:
```
Date Value
0 2015-06-30 502300
1 2015-05-31 501500
2 2015-04-30 500100
3 2015-03-31 495800
4 2015-02-28 492700
```
注意我們又沒有了合適的索引。我們可以首先這樣做來修復:
```py
df.set_index('Date', inplace = True)
```
現在,讓我們假設,我們打算將它轉回 CSV,我們可以:
```py
df.to_csv('newcsv2.csv')
```
我們僅僅有了一列,但是如果你有很多列,并且僅僅打算轉換一列,你可以:
```py
df['Value'].to_csv('newcsv2.csv')
```
要記住我們如何繪制多列,但是并不是所有列。看看你能不能猜出如何保存多列,但不是所有列。
現在,讓我們讀取新的 CSV:
```py
df = pd.read_csv('newcsv2.csv')
print(df.head())
```
輸出:
```
Date Value
0 2015-06-30 502300
1 2015-05-31 501500
2 2015-04-30 500100
3 2015-03-31 495800
4 2015-02-28 492700
```
該死,我們的索引又沒了! 這是因為 CSV 沒有像我們的數據幀那樣的“索引”屬性。 我們可以做的是,在導入時設置索引,而不是導入之后設置索引。 像這樣:
```py
df = pd.read_csv('newcsv2.csv', index_col=0)
print(df.head())
```
輸出:
```py
Value
Date
2015-06-30 502300
2015-05-31 501500
2015-04-30 500100
2015-03-31 495800
2015-02-28 492700
```
現在,我不了解你,但“價值”這個名字是毫無價值的。 我們可以改變這個嗎? 當然,有很多方法來改變列名,一種方法是:
```py
df.columns = ['House_Prices']
print(df.head())
```
輸出:
```
House_Prices
Date
2015-06-30 502300
2015-05-31 501500
2015-04-30 500100
2015-03-31 495800
2015-02-28 492700
```
下面,我們可以嘗試這樣保存為 CSV:
```py
df.to_csv('newcsv3.csv')
```
如果你看看 CSV,你應該看到它擁有標題。如果不想要標題怎么辦呢?沒問題!
```py
df.to_csv('newcsv4.csv', header=False)
```
如果文件沒有標題呢?沒問題!
```py
df = pd.read_csv('newcsv4.csv', names = ['Date','House_Price'], index_col=0)
print(df.head())
```
輸出:
```
House_Price
Date
2015-06-30 502300
2015-05-31 501500
2015-04-30 500100
2015-03-31 495800
2015-02-28 492700
```
這些是IO的基本知識,在輸入和輸出時有一些選項。
一個有趣的事情是使用 Pandas 進行轉換。 所以,也許你是從 CSV 輸入數據,但你真的希望在你的網站上,將這些數據展示為 HTML。 由于 HTML 是數據類型之一,我們可以將其導出為 HTML,如下所示:
```py
df.to_html('example.html')
```
現在我們有了 HTML 文件。打開它,然后你就有了 HTML 中的一個表格:
| | House_Prices |
| --- | --- |
| Date | |
| 2015-06-30 | 502300 |
| 2015-05-31 | 501500 |
| 2015-04-30 | 500100 |
| 2015-03-31 | 495800 |
| 2015-02-28 | 492700 |
| 2015-01-31 | 493000 |
| 2014-12-31 | 494200 |
| 2014-11-30 | 490900 |
| 2014-10-31 | 486000 |
| 2014-09-30 | 479800 |
| 2014-08-31 | 473900 |
| 2014-07-31 | 467100 |
| 2014-06-30 | 461400 |
| 2014-05-31 | 455400 |
| 2014-04-30 | 450500 |
| 2014-03-31 | 450300 |
注意,這個表自動分配了`dataframe`類。 這意味著你可以自定義 CSS 來處理數據幀特定的表!
當我有用數據的 SQL 轉儲時,我特別喜歡使用 Pandas。 我傾向于將數據庫數據直接倒入 Pandas 數據幀中,執行我想要執行的操作,然后將數據顯示在圖表中,或者以某種方式提供數據。
最后,如果我們想重新命名其中一列,該怎么辦? 之前,你已經看到了如何命名所有列,但是也許你只是想改變一個列,而不必輸入所有的列。 足夠簡單:
```py
print(df.head())
df.rename(columns={'House_Price':'Prices'}, inplace=True)
print(df.head())
```
輸出:
```py
Date House_Price
0 2015-06-30 502300
1 2015-05-31 501500
2 2015-04-30 500100
3 2015-03-31 495800
4 2015-02-28 492700
Date Prices
0 2015-06-30 502300
1 2015-05-31 501500
2 2015-04-30 500100
3 2015-03-31 495800
4 2015-02-28 492700
```
所以在這里,我們首先導入了無頭文件,提供了列名`Date`和`House_Price`。 然后,我們決定,我們打算用`Price`代替`House_Price`。 因此,我們使用`df.rename`,指定我們要重命名的列,然后在字典形式中,鍵是原始名稱,值是新名稱。 我們最終使用`inplace = True`,以便修改原始對象。
## 四、構件數據集
在 Python 和 Pandas 數據分析系列教程的這一部分中,我們將擴展一些東西。讓我們想想,我們是億萬富豪,還是千萬富豪,但成為億萬富豪則更有趣,我們正在努力使我們的投資組合盡可能多樣化。我們希望擁有所有類型的資產類別,所以我們有股票,債券,也許是一個貨幣市場帳戶,現在我們正在尋找堅實的不動產。你們都看過廣告了嗎?你買了 60 美元的 CD,參加了 500 美元的研討會,你開始把你的 6 位數字投資到房地產,對吧?
好吧,也許不是,但是我們肯定要做一些研究,并有一些購買房地產的策略。那么,什么統治了房價,我們是否需要進行研究才能找到答案?一般來說,不,你并不需要那么做,我們知道這些因素。房價的因素受經濟,利率和人口統計的影響。這是房地產價格總體上的三大影響。現在當然,如果你買土地,其他的事情很重要,它的水平如何,我們是否需要在土地上做一些工作,才能真正奠定基礎,如何排水等等。那么我們還有更多的因素,比如屋頂,窗戶,暖氣/空調,地板,地基等等。我們可以稍后考慮這些因素,但首先我們要從宏觀層面開始。你會看到我們的數據集在這里膨脹得有多快,它會爆炸式增長。
所以,我們的第一步是收集數據。 Quandl 仍然是良好的起始位置,但是這一次讓我們自動化數據抓取。我們將首先抓取 50 個州的住房數據,但是我們也試圖收集其他數據。我們絕對不想手動抓取這個數據。首先,如果你還沒有帳戶,你需要得到一個帳戶。這將給你一個 API 密鑰和免費數據的無限的 API 請求,這真棒。
一旦你創建了一個賬戶,訪問`your account / me`,不管他們這個時候叫什么,然后找到標有 API 密鑰的部分。這是你所需的密鑰。接下來,我們要獲取 Quandl 模塊。我們實際上并不需要模塊來生成請求,但它是一個非常小的模塊,他能給我們帶來一些小便利,所以不妨試試。打開你的終端或`cmd.exe`并且執行`pip install quandl`(再一次,如果`pip`不能識別,記得指定`pip`的完整路徑)。
接下來,我們做好了開始的準備,打開一個新的編輯器。開始:
```py
import Quandl
# Not necessary, I just do this so I do not show my API key.
api_key = open('quandlapikey.txt','r').read()
df = Quandl.get("FMAC/HPI_TX", authtoken=api_key)
print(df.head())
```
如果你愿意的話,你可以只存儲你的密鑰的純文本版本,我只隱藏了我的密鑰,因為它是我發布的教程。這是我們需要做的,來獲得德克薩斯州的房價指數。我們抓取的實際指標可以在任何頁面上找到,無論你什么時候訪問,只要在網站上點擊你使用的庫,我們這里是 Python,然后需要輸入的查詢就會彈出。
隨著你的數據科學事業的發展,你將學習到各種常數,因為人們是合乎邏輯和合理的。我們這里,我們需要獲取所有州的數據。我們如何做到呢?我們是否需要手動抓取每個指標?不,看看這個代碼,我們看到`FMAC/HPI_TX`。我們可以很容易地把這個解碼為`FMAC = Freddie Mac`。 `HPI = House Price Index`(房價指數)。`TX`是德克薩斯州,它的常用兩字母縮寫。從這里,我們可以安全地假設所有的代碼都是這樣構建的,所以現在我們只需要一個州縮寫的列表。我們搜索它,作出選擇,就像這個 50 個州的列表。怎么辦?
我們可以通過多種方式提取這些數據。這是一個 Pandas 教程,所以如果我們可以 Pandas 熊貓,我們就這樣。讓我們來看看 Pandas 的`read_html`。它不再被稱為“實驗性”的,但我仍然會將其標記為實驗性的。其他 IO 模塊的標準和質量非常高并且可靠。`read_html`并不是很好,但我仍然說這是非常令人印象深刻有用的代碼,而且很酷。它的工作方式就是簡單地輸入一個 URL,Pandas 會從表中將有價值的數據提取到數據幀中。這意味著,與其他常用的方法不同,`read_html`最終會讀入一些列數據幀。這不是唯一不同點,但它是不同的。首先,為了使用`read_html`,我們需要`html5lib`。打開`cmd.exe`或你的終端,并執行:`pip install html5lib`。現在,我們可以做我們的第一次嘗試:
```py
fiddy_states = pd.read_html('https://simple.wikipedia.org/wiki/List_of_U.S._states')
print(fiddy_states)
```
它的輸出比我要在這里發布的更多,但你明白了。 這些數據中至少有一部分是我們想要的,看起來第一個數據幀是一個很好的開始。 那么讓我們執行:
```py
print(fiddy_states[0])
```
```
0 1 2 3
0 Abbreviation State name Capital Became a state
1 AL Alabama Montgomery December 14, 1819
2 AK Alaska Juneau January 3, 1959
3 AZ Arizona Phoenix February 14, 1912
4 AR Arkansas Little Rock June 15, 1836
5 CA California Sacramento September 9, 1850
6 CO Colorado Denver August 1, 1876
7 CT Connecticut Hartford January 9, 1788
8 DE Delaware Dover December 7, 1787
9 FL Florida Tallahassee March 3, 1845
10 GA Georgia Atlanta January 2, 1788
11 HI Hawaii Honolulu August 21, 1959
12 ID Idaho Boise July 3, 1890
13 IL Illinois Springfield December 3, 1818
14 IN Indiana Indianapolis December 11, 1816
15 IA Iowa Des Moines December 28, 1846
16 KS Kansas Topeka January 29, 1861
17 KY Kentucky Frankfort June 1, 1792
18 LA Louisiana Baton Rouge April 30, 1812
19 ME Maine Augusta March 15, 1820
20 MD Maryland Annapolis April 28, 1788
21 MA Massachusetts Boston February 6, 1788
22 MI Michigan Lansing January 26, 1837
23 MN Minnesota Saint Paul May 11, 1858
24 MS Mississippi Jackson December 10, 1817
25 MO Missouri Jefferson City August 10, 1821
26 MT Montana Helena November 8, 1889
27 NE Nebraska Lincoln March 1, 1867
28 NV Nevada Carson City October 31, 1864
29 NH New Hampshire Concord June 21, 1788
30 NJ New Jersey Trenton December 18, 1787
31 NM New Mexico Santa Fe January 6, 1912
32 NY New York Albany July 26, 1788
33 NC North Carolina Raleigh November 21, 1789
34 ND North Dakota Bismarck November 2, 1889
35 OH Ohio Columbus March 1, 1803
36 OK Oklahoma Oklahoma City November 16, 1907
37 OR Oregon Salem February 14, 1859
38 PA Pennsylvania Harrisburg December 12, 1787
39 RI Rhode Island Providence May 19, 1790
40 SC South Carolina Columbia May 23, 1788
41 SD South Dakota Pierre November 2, 1889
42 TN Tennessee Nashville June 1, 1796
43 TX Texas Austin December 29, 1845
44 UT Utah Salt Lake City January 4, 1896
45 VT Vermont Montpelier March 4, 1791
46 VA Virginia Richmond June 25, 1788
47 WA Washington Olympia November 11, 1889
48 WV West Virginia Charleston June 20, 1863
49 WI Wisconsin Madison May 29, 1848
50 WY Wyoming Cheyenne July 10, 1890
```
是的,這看起來不錯,我們想要第零列。所以,我們要遍歷`fiddy_states[0]`的第零列。 請記住,現在`fiddy_states`是一個數幀列表,而`fiddy_states[0]`是第一個數據幀。 為了引用第零列,我們執行`fiddy_states[0][0]`。 一個是列表索引,它返回一個數據幀。 另一個是數據幀中的一列。 接下來,我們注意到第零列中的第一項是`abbreviation`,我們不想要它。 當我們遍歷第零列中的所有項目時,我們可以使用`[1:]`排除掉它。 因此,我們的縮寫列表是`fiddy_states[0][0][1:]`,我們可以像這樣迭代:
```py
for abbv in fiddy_states[0][0][1:]:
print(abbv)
```
```
AL
AK
AZ
AR
CA
CO
CT
DE
FL
GA
HI
ID
IL
IN
IA
KS
KY
LA
ME
MD
MA
MI
MN
MS
MO
MT
NE
NV
NH
NJ
NM
NY
NC
ND
OH
OK
OR
PA
RI
SC
SD
TN
TX
UT
VT
VA
WA
WV
WI
WY
```
完美! 現在,我們回憶這樣做的原因:我們正在試圖用州名縮寫建立指標,來獲得每個州的房價指數。 好的,我們可以建立指標:
```py
for abbv in fiddy_states[0][0][1:]:
#print(abbv)
print("FMAC/HPI_"+str(abbv))
```
```
FMAC/HPI_AL
FMAC/HPI_AK
FMAC/HPI_AZ
FMAC/HPI_AR
FMAC/HPI_CA
FMAC/HPI_CO
FMAC/HPI_CT
FMAC/HPI_DE
FMAC/HPI_FL
FMAC/HPI_GA
FMAC/HPI_HI
FMAC/HPI_ID
FMAC/HPI_IL
FMAC/HPI_IN
FMAC/HPI_IA
FMAC/HPI_KS
FMAC/HPI_KY
FMAC/HPI_LA
FMAC/HPI_ME
FMAC/HPI_MD
FMAC/HPI_MA
FMAC/HPI_MI
FMAC/HPI_MN
FMAC/HPI_MS
FMAC/HPI_MO
FMAC/HPI_MT
FMAC/HPI_NE
FMAC/HPI_NV
FMAC/HPI_NH
FMAC/HPI_NJ
FMAC/HPI_NM
FMAC/HPI_NY
FMAC/HPI_NC
FMAC/HPI_ND
FMAC/HPI_OH
FMAC/HPI_OK
FMAC/HPI_OR
FMAC/HPI_PA
FMAC/HPI_RI
FMAC/HPI_SC
FMAC/HPI_SD
FMAC/HPI_TN
FMAC/HPI_TX
FMAC/HPI_UT
FMAC/HPI_VT
FMAC/HPI_VA
FMAC/HPI_WA
FMAC/HPI_WV
FMAC/HPI_WI
FMAC/HPI_WY
```
我們已經得到了指標,現在我們已經準備好提取數據幀了。 但是,一旦我們拿到他們,我們會做什么? 我們將使用 50 個獨立的數據幀? 聽起來像一個愚蠢的想法,我們需要一些方法來組合他們。 Pandas 背后的優秀人才看到了這一點,并為我們提供了多種組合數據幀的方法。 我們將在下一個教程中討論這個問題。
## 五、連接(concat)和附加數據幀
歡迎閱讀 Python 和 Pandas 數據分析系列教程第五部分。在本教程中,我們將介紹如何以各種方式組合數據幀。
在我們的房地產投資案例中,我們希望使用房屋數據獲取 50 個數據幀,然后把它們全部合并成一個數據幀。我們這樣做有很多原因。首先,將這些組合起來更容易,更有意義,也會減少使用的內存。每個數據幀都有日期和值列。這個日期列在所有數據幀中重復出現,但實際上它們應該全部共用一個,實際上幾乎減半了我們的總列數。
在組合數據幀時,你可能會考慮相當多的目標。例如,你可能想“附加”到他們,你可能會添加到最后,基本上就是添加更多的行。或者,也許你想添加更多的列,就像我們的情況一樣。有四種主要的數據幀組合方式,我們現在開始介紹。四種主要的方式是:連接(Concatenation),連接(Join),合并和附加。我們將從第一種開始。這里有一些初始數據幀:
```py
df1 = pd.DataFrame({'HPI':[80,85,88,85],
'Int_rate':[2, 3, 2, 2],
'US_GDP_Thousands':[50, 55, 65, 55]},
index = [2001, 2002, 2003, 2004])
df2 = pd.DataFrame({'HPI':[80,85,88,85],
'Int_rate':[2, 3, 2, 2],
'US_GDP_Thousands':[50, 55, 65, 55]},
index = [2005, 2006, 2007, 2008])
df3 = pd.DataFrame({'HPI':[80,85,88,85],
'Int_rate':[2, 3, 2, 2],
'Low_tier_HPI':[50, 52, 50, 53]},
index = [2001, 2002, 2003, 2004])
```
注意這些之間有兩個主要的變化。 `df1`和`df3`具有相同的索引,但它們有一些不同的列。 `df2`和`df3`有不同的索引和一些不同的列。 通過連接(concat),我們可以討論將它們結合在一起的各種方法。 我們來試一下簡單的連接(concat):
```py
concat = pd.concat([df1,df2])
print(concat)
```
```
HPI Int_rate US_GDP_Thousands
2001 80 2 50
2002 85 3 55
2003 88 2 65
2004 85 2 55
2005 80 2 50
2006 85 3 55
2007 88 2 65
2008 85 2 55
```
很簡單。 這兩者之間的主要區別僅僅是索引的延續,但是它們共享同一列。 現在他們已經成為單個數據幀。 然而我們這里,我們對添加列而不是行感到好奇。 當我們將一些共有的和一些新列組合起來:
```py
concat = pd.concat([df1,df2,df3])
print(concat)
```
```
HPI Int_rate Low_tier_HPI US_GDP_Thousands
2001 80 2 NaN 50
2002 85 3 NaN 55
2003 88 2 NaN 65
2004 85 2 NaN 55
2005 80 2 NaN 50
2006 85 3 NaN 55
2007 88 2 NaN 65
2008 85 2 NaN 55
2001 80 2 50 NaN
2002 85 3 52 NaN
2003 88 2 50 NaN
2004 85 2 53 NaN
```
不錯,我們有一些`NaN`(不是數字),因為那個索引處不存在數據,但是我們所有的數據確實在這里。
這些就是基本的連接(concat),接下來,我們將討論附加。 附加就像連接的第一個例子,只是更加強大一些,因為數據幀會簡單地追加到行上。 我們通過一個例子來展示它的工作原理,同時也展示它可能出錯的地方:
```py
df4 = df1.append(df2)
print(df4)
```
```
HPI Int_rate US_GDP_Thousands
2001 80 2 50
2002 85 3 55
2003 88 2 65
2004 85 2 55
2005 80 2 50
2006 85 3 55
2007 88 2 65
2008 85 2 55
```
這就是我們期望的附加。 在大多數情況下,你將要做這樣的事情,就像在數據庫中插入新行一樣。 我們并沒有真正有效地附加數據幀,它們更像是根據它們的起始數據來操作,但是如果你需要,你可以附加。 當我們附加索引相同的數據時會發生什么?
```py
df4 = df1.append(df3)
print(df4)
```
```
HPI Int_rate Low_tier_HPI US_GDP_Thousands
2001 80 2 NaN 50
2002 85 3 NaN 55
2003 88 2 NaN 65
2004 85 2 NaN 55
2001 80 2 50 NaN
2002 85 3 52 NaN
2003 88 2 50 NaN
2004 85 2 53 NaN
```
好吧,這很不幸。 有人問為什么連接(concat )和附加都退出了。 這就是原因。 因為共有列包含相同的數據和相同的索引,所以組合這些數據幀要高效得多。 一個另外的例子是附加一個序列。 鑒于`append`的性質,你可能會附加一個序列而不是一個數據幀。 至此我們還沒有談到序列。 序列基本上是單列的數據幀。 序列確實有索引,但是,如果你把它轉換成一個列表,它將僅僅是這些值。 每當我們調用`df ['column']`時,返回值就是一個序列。
```py
s = pd.Series([80,2,50], index=['HPI','Int_rate','US_GDP_Thousands'])
df4 = df1.append(s, ignore_index=True)
print(df4)
```
```
HPI Int_rate US_GDP_Thousands
0 80 2 50
1 85 3 55
2 88 2 65
3 85 2 55
4 80 2 50
```
在附加序列時,我們必須忽略索引,因為這是規則,除非序列擁有名稱。
在這里,我們已經介紹了 Pandas 中的連接(concat)和附加數據幀。 接下來,我們將討論如何連接(join)和合并數據幀。
## 六、連接(join)和合并數據幀
歡迎閱讀 Python 和 Pandas 數據分析系列教程的第六部分。 在這一部分種,我們將討論連接(join)和合并數據幀,作為組合數據框的另一種方法。 在前面的教程中,我們介紹了連接(concat)和附加。
首先,我們將從以前的一些示例數據幀開始,帶有一點更改:
```py
import pandas as pd
df1 = pd.DataFrame({'HPI':[80,85,88,85],
'Int_rate':[2, 3, 2, 2],
'US_GDP_Thousands':[50, 55, 65, 55]},
index = [2001, 2002, 2003, 2004])
df2 = pd.DataFrame({'HPI':[80,85,88,85],
'Int_rate':[2, 3, 2, 2],
'US_GDP_Thousands':[50, 55, 65, 55]},
index = [2005, 2006, 2007, 2008])
df3 = pd.DataFrame({'HPI':[80,85,88,85],
'Unemployment':[7, 8, 9, 6],
'Low_tier_HPI':[50, 52, 50, 53]},
index = [2001, 2002, 2003, 2004])
```
唯一的變化是`df3`,我們把`Int_rate`變成了`unemployment`。 首先,我們來討論合并。
```py
print(pd.merge(df1,df3, on='HPI'))
```
```
HPI Int_rate US_GDP_Thousands Low_tier_HPI Unemployment
0 80 2 50 50 7
1 85 3 55 52 8
2 85 3 55 53 6
3 85 2 55 52 8
4 85 2 55 53 6
5 88 2 65 50 9
```
所以,在這里,我們看到了一個共有列(`HPI`)。 你可以共有多個列,這里有一個例子:
```py
print(pd.merge(df1,df2, on=['HPI','Int_rate']))
```
```
HPI Int_rate US_GDP_Thousands_x US_GDP_Thousands_y
0 80 2 50 50
1 85 3 55 55
2 88 2 65 65
3 85 2 55 55
```
注意這里有`US_GDP_Thousands`的兩個版本。這是因為我們沒有共享這些列,所以都保留下來,使用另外一個字母來區分。記得之前我說過,Pandas 是一個很好的模塊,與類似 MySQL 的數據庫結合。這就是原因。
通常,對于數據庫,你希望使其盡可能輕量化,以便在其上運行的查詢執行得盡可能快。
假設你運營像`pythonprogramming.net`這樣的網站,在那里你有用戶,所以你必須跟蹤用戶名和加密的密碼散列,所以這肯定是兩列。也許那么你有登錄名,用戶名,密碼,電子郵件和注冊日期。所以這已經是基本數據點的五列。如果你有一個論壇,那么也許你有一些東西,像用戶設置,帖子。那么也許你希望有像管理員,主持人,普通用戶的設置。
列表可以繼續。如果你在字面上只有一個巨大的表,這可以工作,但把表分開也可能更好,因為許多操作將更快,更高效。 合并之后,你可能會設置新的索引。像這樣的東西:
```py
df4 = pd.merge(df1,df3, on='HPI')
df4.set_index('HPI', inplace=True)
print(df4)
```
```
Int_rate US_GDP_Thousands Low_tier_HPI Unemployment
HPI
80 2 50 50 7
85 3 55 52 8
85 3 55 53 6
85 2 55 52 8
85 2 55 53 6
88 2 65 50 9
```
現在,如果`HPI`已經是索引了呢? 或者,在我們的情況下,我們可能會按照日期連接,但日期可能是索引。 在這種情況下,我們可能會使用連接(join)。
```py
df1.set_index('HPI', inplace=True)
df3.set_index('HPI', inplace=True)
joined = df1.join(df3)
print(joined)
```
```
Int_rate US_GDP_Thousands Low_tier_HPI Unemployment
HPI
80 2 50 50 7
85 3 55 52 8
85 3 55 53 6
85 2 55 52 8
85 2 55 53 6
88 2 65 50 9
```
現在,我們考慮連接(join)和合并略有不同的索引。 讓我們重新定義`df1`和`df3`數據幀,將它們變成:
```py
df1 = pd.DataFrame({
'Int_rate':[2, 3, 2, 2],
'US_GDP_Thousands':[50, 55, 65, 55],
'Year':[2001, 2002, 2003, 2004]
})
df3 = pd.DataFrame({
'Unemployment':[7, 8, 9, 6],
'Low_tier_HPI':[50, 52, 50, 53],
'Year':[2001, 2003, 2004, 2005]})
```
這里,我們現在有相似的年份列,但日期不同。 `df3`有 2005 年,但沒有 2002 年,`df1`相反。 現在,當我們合并時會發生什么?
```py
merged = pd.merge(df1,df3, on='Year')
print(merged)
```
```
Int_rate US_GDP_Thousands Year Low_tier_HPI Unemployment
0 2 50 2001 50 7
1 2 65 2003 52 8
2 2 55 2004 50 9
````
現在,更實用一些:
```py
merged = pd.merge(df1,df3, on='Year')
merged.set_index('Year', inplace=True)
print(merged)
```
```
Int_rate US_GDP_Thousands Low_tier_HPI Unemployment
Year
2001 2 50 50 7
2003 2 65 52 8
2004 2 55 50 9
```
注意 2005 年和 2002 年完全失蹤了。 合并只會合并現有/共有的數據。 我們能對其做些什么呢? 事實證明,合并時有一個參數`how`。 此參數表明合并選擇,它來自數據庫的合并。 你有以下選擇:左、右、外部、內部。
+ 左 - SQL 左外連接 - 僅使用左側數據幀中的鍵
+ 右 - SQL 右外連接 - 僅使用右側數據幀中的鍵
+ 外部 - 全外聯接 - 使用鍵的并集
+ 內部 - 使用鍵的交集
```py
merged = pd.merge(df1,df3, on='Year', how='left')
merged.set_index('Year', inplace=True)
print(merged)
```
```
Int_rate US_GDP_Thousands Low_tier_HPI Unemployment
Year
2001 2 50 50 7
2002 3 55 NaN NaN
2003 2 65 52 8
2004 2 55 50 9
```
左側合并實際上在左邊的數據幀上。 我們有`df1`,`df3`,左邊的是第一個,`df1`。 所以,我們最終得到了一個與左側數據幀(`df1`)相同的索引。
```py
merged = pd.merge(df1,df3, on='Year', how='right')
merged.set_index('Year', inplace=True)
print(merged)
```
```
Int_rate US_GDP_Thousands Low_tier_HPI Unemployment
Year
2001 2 50 50 7
2003 2 65 52 8
2004 2 55 50 9
2005 NaN NaN 53 6
```
我們選擇了右側,所以這次索引來源于右側(`df3`)。
```py
merged = pd.merge(df1,df3, on='Year', how='outer')
merged.set_index('Year', inplace=True)
print(merged)
```
```
Int_rate US_GDP_Thousands Low_tier_HPI Unemployment
Year
2001 2 50 50 7
2002 3 55 NaN NaN
2003 2 65 52 8
2004 2 55 50 9
2005 NaN NaN 53 6
```
這次,我們選擇了外部,它是鍵的并集。也就是會展示所有索引。
```py
merged = pd.merge(df1,df3, on='Year', how='inner')
merged.set_index('Year', inplace=True)
print(merged)
```
```
Int_rate US_GDP_Thousands Low_tier_HPI Unemployment
Year
2001 2 50 50 7
2003 2 65 52 8
2004 2 55 50 9
```
最后,“內部”是鍵的交集,基本上就是所有集合之間共有的東西。 這些都有其自己的邏輯,但是,正如你所看到的,默認選項是“內部”。
現在我們可以檢查連接(join),這會按照索引連接,所以我們可以做這樣的事情:
```py
df1.set_index('Year', inplace=True)
df3.set_index('Year', inplace=True)
joined = df1.join(df3, how="outer")
print(joined)
```
```
Int_rate US_GDP_Thousands Low_tier_HPI Unemployment
Year
2001 2 50 50 7
2002 3 55 NaN NaN
2003 2 65 52 8
2004 2 55 50 9
2005 NaN NaN 53 6
```
好吧,我想我們已經足以涵蓋了數據幀的組合。 讓我們回到我們的房地產投資,使用我們的新知識,并建立自己的史詩數據集。
## 七、Pickle
歡迎閱讀 Python 和 Pandas 數據分析系列教程第七部分。 在最近的幾個教程中,我們學習了如何組合數據集。 在本教程中,我們將恢復我們是房地產巨頭的假設。 我們希望通過擁有多元化的財富來保護我們的財富,其中一個組成部分就是房地產。 在第 4部分 中,我們建立了以下代碼:
```py
import Quandl
import pandas as pd
# Not necessary, I just do this so I do not show my API key.
api_key = open('quandlapikey.txt','r').read()
fiddy_states = pd.read_html('https://simple.wikipedia.org/wiki/List_of_U.S._states')
for abbv in fiddy_states[0][0][1:]:
#print(abbv)
print("FMAC/HPI_"+str(abbv))
```
這個代碼用來獲得 50 個州,遍歷他們,并產生適當的 Quandl 查詢,來按州返回房價指數。 由于我們將在這里生成 50 個數據幀,我們寧愿把它們全部合并成一個。 為此,我們可以使用前面教程中學到的`.join`。 在這種情況下,我們將使用`.join`,因為 Quandl 模塊將數據返回給我們,實際索引為`Date`。 通常情況下,你可能不會得到這個,它只是索引為常規數字的數據幀。 在這種情況下,你可以使用連接,`on ='Date'`。
現在,為了運行并收集所有的數據,我們可以做以下的改變:
```py
import Quandl
import pandas as pd
# Not necessary, I just do this so I do not show my API key.
api_key = open('quandlapikey.txt','r').read()
fiddy_states = pd.read_html('https://simple.wikipedia.org/wiki/List_of_U.S._states')
main_df = pd.DataFrame()
for abbv in fiddy_states[0][0][1:]:
query = "FMAC/HPI_"+str(abbv)
df = Quandl.get(query, authtoken=api_key)
if main_df.empty:
main_df = df
else:
main_df = main_df.join(df)
```
注意:Quandl 已經改變了數據集的返回值,如果返回值只有一列(或者我認為是這樣),那么該列的標題就是`value`。那么,這很麻煩,但我們可以解決它。在`for`循環中,將數據幀的列重命名為我們的縮寫。如果沒有做這個改變,你可能會看到:`ValueError: columns overlap but no suffix specified: Index([u'Value'], dtype='object')`。
太好了,但是每一次你想運行它時,你會發現這個過程可能需要 30 秒到幾分鐘。這很煩人。現在,你的短期目標是實現它,但接下來呢?我們將繼續在此基礎上進行研究,每次我們進行測試或者其他東西時,我們都必須忍受這個無意義的東西!因此,我們要保存這些數據。現在,這是一個數據分析和 Pandas 教程。有了 Pandas,我們可以簡單地將數據輸出到 CSV,或者我們希望的任何數據類型,包括我們要談論的內容。但是,你可能并不總是可以將數據輸出到簡單文件。在任何情況下,我們都希望將這些數據保存到一個文件中,所以我們只需要執行一次這個操作,然后我們就可以在它頂上建立。
舉個例子來說,就是機器學習。你通常會訓練一個分類器,然后你可以立即開始,然后快速使用該分類器進行分類。問題是,分類器不能保存到`.txt`或`.csv`文件。這是一個對象。幸運的是,以編程的方式,有各種各樣的東西,用于將二進制數據保存到可以稍后訪問的文件。在 Python 中,這被稱為 Pickle。你可能知道它是序列化的,或者甚至別的東西。 Python 有一個名為 Pickle 的模塊,它將把你的對象轉換成一個字節流,或者反過來轉換它。這讓我們做的是保存任何 Python 對象。那機器學習分類器呢?可以。字典?可以。數據幀?可以!現在,Pandas 在 IO 模塊中已經有了 Pickle,但是你真的應該知道如何使用和不使用 Pandas 來實現它,所以讓我們這樣做吧!
首先,我們來談談常規的 Pickle。你可以用你想要的任何 Python 對象來這樣做,它不需要是一個數據幀,但我們會用我們的數據幀來實現。
首先,在腳本的頂部導入`pickle`:
```py
import pickle
```
下面:
```
pickle_out = open('fiddy_states.pickle','wb')
pickle.dump(main_df, pickle_out)
pickle_out.close()
```
首先我們打開一個`.pickle`文件,打算寫一些字節。 然后,我們執行`pickle.dump`來轉儲我們想要保存的數據,之后是轉儲它的地方(我們剛才打開的文件)。 最后,我們關閉任何文件。 完成了,我們保存了`pickle`。
不過,我希望現在組織這些代碼。 我們不希望每次都運行這個代碼,但是我們仍然需要時常引用狀態列表。 我們來清理一下:
```py
import Quandl
import pandas as pd
import pickle
# Not necessary, I just do this so I do not show my API key.
api_key = open('quandlapikey.txt','r').read()
def state_list():
fiddy_states = pd.read_html('https://simple.wikipedia.org/wiki/List_of_U.S._states')
return fiddy_states[0][0][1:]
def grab_initial_state_data():
states = state_list()
main_df = pd.DataFrame()
for abbv in states:
query = "FMAC/HPI_"+str(abbv)
df = Quandl.get(query, authtoken=api_key)
print(query)
if main_df.empty:
main_df = df
else:
main_df = main_df.join(df)
pickle_out = open('fiddy_states.pickle','wb')
pickle.dump(main_df, pickle_out)
pickle_out.close()
grab_initial_state_data()
```
現在,我們可以在任何需要狀態列表的時候,引用`state_list`,然后我們只需要為`HPI`基線調用`grab_initial_state_data`,真的比較快,并且我們已經將這些數據保存到了`pickle`文件中。
現在,再次獲取這些數據,我們只需要做:
```py
pickle_in = open('fiddy_states.pickle','rb')
HPI_data = pickle.load(pickle_in)
print(HPI_data)
```
輸出比我想要粘貼的更多,但是你應該得到一個約 462 行 x50 列的數據幀。 你有了它。 部分對象是它是一個數據幀,這是我們“保存”變量的方式。 很酷! 你可以在 Python 的任何地方用`pickle`模塊來這樣做,但是 Pandas 也有自己的`pickle`,所以我們可以展示:
```py
HPI_data.to_pickle('pickle.pickle')
HPI_data2 = pd.read_pickle('pickle.pickle')
print(HPI_data2)
```
再次,輸出有點多,不能粘貼在這里,但你應該得到同樣的東西。 如果你和我一樣,你可能會想“如果所有的 Python 已經有 Pickle 并且工作得很好,為什么 Pandas 有自己的 Pickle 選項?” 我真的不知道。 顯然,Pandas 有時可以更快地處理海量數據。
現在我們已經得到了數據的`pickle`,我們已經準備好在下一篇教程中繼續深入研究。
## 八、百分比變化和相關表
歡迎閱讀 Python 和 Pandas 數據分析系列教程的第八部分。 在這一部分中,我們將對數據進行一些初步的操作。 我們到目前為止的腳本是:
```py
import Quandl
import pandas as pd
import pickle
# Not necessary, I just do this so I do not show my API key.
api_key = open('quandlapikey.txt','r').read()
def state_list():
fiddy_states = pd.read_html('https://simple.wikipedia.org/wiki/List_of_U.S._states')
return fiddy_states[0][0][1:]
def grab_initial_state_data():
states = state_list()
main_df = pd.DataFrame()
for abbv in states:
query = "FMAC/HPI_"+str(abbv)
df = Quandl.get(query, authtoken=api_key)
print(query)
if main_df.empty:
main_df = df
else:
main_df = main_df.join(df)
pickle_out = open('fiddy_states.pickle','wb')
pickle.dump(main_df, pickle_out)
pickle_out.close()
HPI_data = pd.read_pickle('fiddy_states.pickle')
```
現在我們可以像這樣修改列:
```py
HPI_data['TX2'] = HPI_data['TX'] * 2
print(HPI_data[['TX','TX2']].head())
```
```
TX TX2
Date
1975-01-31 32.617930 65.235860
1975-02-28 33.039339 66.078677
1975-03-31 33.710029 67.420057
1975-04-30 34.606874 69.213747
1975-05-31 34.864578 69.729155
```
我們我們也可以不創建新的列,只是重新定義原來的`TX`。 從我們的腳本中刪除整個`TX2`的代碼,讓我們看看我們現在有什么。 在腳本的頂部:
```py
import matplotlib.pyplot as plt
from matplotlib import style
style.use('fivethirtyeight')
```
之后:
```
HPI_data.plot()
plt.legend().remove()
plt.show()
```
輸出:

嗯,有趣,發生了什么事? 所有這些價格似乎在 2000 年完美匯合!這正是指數從 100.0% 開始的時候。 我們可以得到它,但我根本不喜歡。 那么某種百分比變化呢? 事實證明,Pandas 在這里覆蓋了各種“滾動”統計量。 我們可以用一個基本的,就像這樣:
```py
def grab_initial_state_data():
states = state_list()
main_df = pd.DataFrame()
for abbv in states:
query = "FMAC/HPI_"+str(abbv)
df = Quandl.get(query, authtoken=api_key)
print(query)
df = df.pct_change()
print(df.head())
if main_df.empty:
main_df = df
else:
main_df = main_df.join(df)
pickle_out = open('fiddy_states2.pickle','wb')
pickle.dump(main_df, pickle_out)
pickle_out.close()
grab_initial_state_data()
```
主要是,你要注意:`df = df.pct_change()`,我們將重新運行它,保存到`fiddy_states2.pickle`。 值得注意的是,我們也可以嘗試修改原來的 Pickle,而不是重新構建。 畢竟,這就是 Pickle 的要點。 如果我沒有事后偏見,我可能會同意你的看法。
```py
HPI_data = pd.read_pickle('fiddy_states2.pickle')
HPI_data.plot()
plt.legend().remove()
plt.show()
```
輸出:

不幸的是,我不是那么想的。 我想要一個傳統的百分比變化圖。 這是距離上次報告值的百分比變化。 我們可以增加它,做一些事情,類似于過去 10 個值的滾動百分比,但仍然不是我想要的。 我們來試試其他的東西:
```py
def grab_initial_state_data():
states = state_list()
main_df = pd.DataFrame()
for abbv in states:
query = "FMAC/HPI_"+str(abbv)
df = Quandl.get(query, authtoken=api_key)
print(query)
df[abbv] = (df[abbv]-df[abbv][0]) / df[abbv][0] * 100.0
print(df.head())
if main_df.empty:
main_df = df
else:
main_df = main_df.join(df)
pickle_out = open('fiddy_states3.pickle','wb')
pickle.dump(main_df, pickle_out)
pickle_out.close()
grab_initial_state_data()
HPI_data = pd.read_pickle('fiddy_states3.pickle')
HPI_data.plot()
plt.legend().remove()
plt.show()
```

好的,這就是我要找的! 這是每個州 HPI 自身的百分比變化。 出于各種原因,第一個百分比變化仍然有用。 我們可能會結合使用這個結果,或者取而代之,但是現在,我們最開始堅持使用典型的百分比變化。
現在,我們可能想要引入其他數據集,但是讓我們看看我們是否可以自己到達任何地方。 首先,我們可以檢查某種“基準”。 對于這個數據,這個基準將是美國的房價指數。 我們可以收集:
```py
def HPI_Benchmark():
df = Quandl.get("FMAC/HPI_USA", authtoken=api_key)
df["United States"] = (df["United States"]-df["United States"][0]) / df["United States"][0] * 100.0
return df
```
之后:
```py
fig = plt.figure()
ax1 = plt.subplot2grid((1,1), (0,0))
HPI_data = pd.read_pickle('fiddy_states3.pickle')
benchmark = HPI_Benchmark()
HPI_data.plot(ax=ax1)
benchmark.plot(color='k',ax=ax1, linewidth=10)
plt.legend().remove()
plt.show()
```
輸出:

從這個數據來看,似乎是所有的市場都是相對密切地服從彼此和整體房價指數。這里確實存在一些平均偏差,但基本上每個市場似乎都遵循了非常相似的趨勢。其中最大的偏差是從 200% 的增長到 800% 的增長,顯然我們有很大的偏差,但是在過去的 30 年里,均值從 400% 增長到 500%。
我們如何接近市場呢?之后,我們可以考慮人口統計和利率來預測未來,但不是每個人都對投機游戲感興趣。有些人想要更安全,更安全的投資。在這里看來,像房地產市場從來沒有真正在國家層面失敗。如果我們買房子,顯然我們的計劃可能會失敗,之后我們發現了巨大白蟻危害,并可能在任何時候倒塌。
保持宏觀,我很清楚,我們可以在這里進行一個非常明顯,安全的交易。我們可以使用 Pandas 很容易地收集相關性和協方差信息。相關性和協方差是兩個非常相似的話題,經常被混淆。相關不是因果關系,相關性幾乎總是包含在協方差計算中用于歸一化。相關性衡量了兩個資產相對于彼此移動的程度。協方差是衡量兩個資產如何一起變化的指標。注意相關性是對“程度”的一種度量。協方差不是。如果我自己的理解不正確,這是重要的區別。
我們來創建一個關聯表。這將為我們做的事情,是歷史回顧,衡量每個州與其他州的移動之間的相關性。那么,當兩個通常高度相關的州開始出現不一致的時候,我們可以考慮出售正在上升的州的房地產,并購買正在下降的州的房地產作為一種市場中性策略,其中我們僅僅從差距中獲益,而不是做一些預測未來的嘗試。相互接壤的州更有可能比遠離的州更相似,但是我們會看到數字說了些什么。
```py
HPI_data = pd.read_pickle('fiddy_states3.pickle')
HPI_State_Correlation = HPI_data.corr()
print(HPI_State_Correlation)
```
輸出是 50 行 x50 列,這里是一些輸出。
```
AL AK AZ AR CA CO CT \
AL 1.000000 0.944603 0.927361 0.994896 0.935970 0.979352 0.953724
AK 0.944603 1.000000 0.893904 0.965830 0.900621 0.949834 0.896395
AZ 0.927361 0.893904 1.000000 0.923786 0.973546 0.911422 0.917500
AR 0.994896 0.965830 0.923786 1.000000 0.935364 0.985934 0.948341
CA 0.935970 0.900621 0.973546 0.935364 1.000000 0.924982 0.956495
CO 0.979352 0.949834 0.911422 0.985934 0.924982 1.000000 0.917129
CT 0.953724 0.896395 0.917500 0.948341 0.956495 0.917129 1.000000
DE 0.980566 0.939196 0.942273 0.975830 0.970232 0.949517 0.981177
FL 0.918544 0.887891 0.994007 0.915989 0.987200 0.905126 0.926364
GA 0.973562 0.880261 0.939715 0.960708 0.943928 0.959500 0.948500
HI 0.946054 0.930520 0.902554 0.947022 0.937704 0.903461 0.938974
ID 0.982868 0.944004 0.959193 0.977372 0.944342 0.960975 0.923099
IL 0.984782 0.905512 0.947396 0.973761 0.963858 0.968552 0.955033
IN 0.981189 0.889734 0.881542 0.973259 0.901154 0.971416 0.919696
IA 0.985516 0.943740 0.894524 0.987919 0.914199 0.991455 0.913788
KS 0.990774 0.957236 0.910948 0.995230 0.926872 0.994866 0.936523
KY 0.994311 0.938125 0.900888 0.992903 0.923429 0.987097 0.941114
LA 0.967232 0.990506 0.909534 0.982454 0.911742 0.972703 0.907456
ME 0.972693 0.935850 0.923797 0.972573 0.965251 0.951917 0.989180
MD 0.964917 0.943384 0.960836 0.964943 0.983677 0.940805 0.969170
MA 0.966242 0.919842 0.921782 0.966962 0.962672 0.959294 0.986178
MI 0.891205 0.745697 0.848602 0.873314 0.861772 0.900040 0.843032
MN 0.971967 0.926352 0.952359 0.972338 0.970661 0.983120 0.945521
MS 0.996089 0.962494 0.927354 0.997443 0.932752 0.985298 0.945831
MO 0.992706 0.933201 0.938680 0.989672 0.955317 0.985194 0.961364
MT 0.977030 0.976840 0.916000 0.983822 0.923950 0.971516 0.917663
NE 0.988030 0.941229 0.896688 0.990868 0.912736 0.992179 0.920409
NV 0.858538 0.785404 0.965617 0.846968 0.948143 0.837757 0.866554
NH 0.953366 0.907236 0.932992 0.952882 0.969574 0.941555 0.990066
NJ 0.968837 0.934392 0.943698 0.967477 0.975258 0.944460 0.989845
NM 0.992118 0.967777 0.934744 0.993195 0.934720 0.968001 0.946073
NY 0.973984 0.940310 0.921126 0.973972 0.959543 0.949474 0.989576
NC 0.998383 0.934841 0.915403 0.991863 0.928632 0.977069 0.956074
ND 0.936510 0.973971 0.840705 0.957838 0.867096 0.942225 0.882938
OH 0.966598 0.855223 0.883396 0.954128 0.901842 0.957527 0.911510
OK 0.944903 0.984550 0.881332 0.967316 0.882199 0.960694 0.879854
OR 0.981180 0.948190 0.949089 0.978144 0.944542 0.971110 0.916942
PA 0.985357 0.946184 0.915914 0.983651 0.950621 0.956316 0.975324
RI 0.950261 0.897159 0.943350 0.945984 0.984298 0.926362 0.988351
SC 0.998603 0.945949 0.929591 0.994117 0.942524 0.980911 0.959591
SD 0.983878 0.966573 0.889405 0.990832 0.911188 0.984463 0.924295
TN 0.998285 0.946858 0.919056 0.995949 0.931616 0.983089 0.953009
TX 0.963876 0.983235 0.892276 0.981413 0.902571 0.970795 0.919415
UT 0.983987 0.951873 0.926676 0.982867 0.909573 0.974909 0.900908
VT 0.975210 0.952370 0.909242 0.977904 0.949225 0.951388 0.973716
VA 0.972236 0.956925 0.950839 0.975683 0.977028 0.954801 0.970366
WA 0.988253 0.948562 0.950262 0.982877 0.956434 0.968816 0.941987
WV 0.984364 0.964846 0.907797 0.990264 0.924300 0.979467 0.925198
WI 0.990190 0.930548 0.927619 0.985818 0.943768 0.987609 0.936340
WY 0.944600 0.983109 0.892255 0.960336 0.897551 0.950113 0.880035
```
所以現在我們可以看到,每兩個州之間的 HPI 移動的相關性。 非常有趣,顯而易見,所有這些都非常高。 相關性的范圍從 -1 到 1。1 是個完美的正相關,-1 是個完美的負相關。 協方差沒有界限。 想知道更多的統計量嘛? Pandas 有一個非常漂亮的描述方法:
```py
print(HPI_State_Correlation.describe())
```
```
AL AK AZ AR CA CO \
count 50.000000 50.000000 50.000000 50.000000 50.000000 50.000000
mean 0.969114 0.932978 0.922772 0.969600 0.938254 0.958432
std 0.028069 0.046225 0.031469 0.029532 0.031033 0.030502
min 0.858538 0.745697 0.840705 0.846968 0.861772 0.837757
25% 0.956262 0.921470 0.903865 0.961767 0.916507 0.949485
50% 0.976120 0.943562 0.922784 0.976601 0.940114 0.964488
75% 0.987401 0.957159 0.943081 0.989234 0.961890 0.980550
max 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000
CT DE FL GA ... SD \
count 50.000000 50.000000 50.000000 50.000000 ... 50.000000
mean 0.938752 0.963892 0.920650 0.945985 ... 0.959275
std 0.035402 0.028814 0.035204 0.030631 ... 0.039076
min 0.843032 0.846668 0.833816 0.849962 ... 0.794846
25% 0.917541 0.950417 0.899680 0.934875 ... 0.952632
50% 0.941550 0.970461 0.918904 0.949980 ... 0.972660
75% 0.960920 0.980587 0.944646 0.964282 ... 0.982252
max 1.000000 1.000000 1.000000 1.000000 ... 1.000000
TN TX UT VT VA WA \
count 50.000000 50.000000 50.000000 50.000000 50.000000 50.000000
mean 0.968373 0.944410 0.953990 0.959094 0.963491 0.966678
std 0.029649 0.039712 0.033818 0.035041 0.029047 0.025752
min 0.845672 0.791177 0.841324 0.817081 0.828781 0.862245
25% 0.955844 0.931489 0.936264 0.952458 0.955986 0.954070
50% 0.976294 0.953301 0.956764 0.968237 0.970380 0.974049
75% 0.987843 0.967444 0.979966 0.976644 0.976169 0.983541
max 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000
WV WI WY
count 50.000000 50.000000 50.000000
mean 0.961813 0.965621 0.932232
std 0.035339 0.026125 0.048678
min 0.820529 0.874777 0.741663
25% 0.957074 0.950046 0.915386
50% 0.974099 0.973141 0.943979
75% 0.984067 0.986954 0.961900
max 1.000000 1.000000 1.000000
[8 rows x 50 columns]
```
這告訴我們,對于每個州,最低的相關性是什么,平均相關性是什么,標準差是什么,前 25%,中間值(中位數/ 50%)等等。顯然他們最大都為 1.0,因為他們是完全相關的。然而,最重要的是,我們在這里看到的所有這些州(50 列中的一些被跳過,我們從 GA 到 SD)與其他所有州的相關度平均上高于 90%。懷俄明州與一個州的相關度低至 74%,在看了我們的表后,它就是密歇根州。正因為如此,如果密歇根州上升,我們可能不想在懷俄明州投資,或者因為懷俄明州正在陷入困境而,出售我們在密歇根州的房子。
我們不僅可以從整體指數中看到任何偏差,還可以從個別市場中尋找偏差。正如你所看到的,我們有每個州的標準差數字。當市場低于標準偏差時,我們可以嘗試投資于房地產,或者當市場高于標準偏差時賣出。在我們到達那里之前,讓我們在下一個教程中討論平滑數據以及重采樣的概念。
## 九、重采樣
歡迎閱讀另一個 Python 和 Pandas 數據分析教程。在本教程中,我們將討論通過消除噪音來平滑數據。有兩種主要的方法來實現。所使用的最流行的方法是稱為重采樣,但可能具有許多其他名稱。這是我們有一些數據,以一定的比例抽樣。對我們來說,我們的房屋價格指數是按一個月抽樣的,但是我們可以每周,每一天,每一分鐘或更多時間對 HPI 進行抽樣,但是我們也可以每年,每隔 10 年重新抽樣。
例如,重新抽樣經常出現的另一個環境就是股價。股票價格是二手數據。所發生的事情是,對于免費數據,股票價格通常最低被重新采樣為分鐘數據。但是,你可以購買實時數據。從長遠來看,數據通常會每天采樣,甚至每 3-5 天采樣一次。這通常是為了使傳輸數據的大小保持較小。例如,在一年的過程中,二手數據通常是幾個 GB,并且一次全部傳輸是不合理的,人們將等待幾分鐘或幾小時來加載頁面。
使用我們目前每個月抽樣一次的數據,我們怎樣才能每六個月或兩年抽樣一次呢?試著想想如何親自編寫一個能執行這個任務的函數,這是一個相當具有挑戰性的函數,但是它可以完成。也就是說,這是一個計算效率相當低的工作,但 Pandas 會幫助我們,并且速度非常快。讓我們來看看。我們現在的起始腳本:
```py
import Quandl
import pandas as pd
import pickle
import matplotlib.pyplot as plt
from matplotlib import style
style.use('fivethirtyeight')
# Not necessary, I just do this so I do not show my API key.
api_key = open('quandlapikey.txt','r').read()
def state_list():
fiddy_states = pd.read_html('https://simple.wikipedia.org/wiki/List_of_U.S._states')
return fiddy_states[0][0][1:]
def grab_initial_state_data():
states = state_list()
main_df = pd.DataFrame()
for abbv in states:
query = "FMAC/HPI_"+str(abbv)
df = Quandl.get(query, authtoken=api_key)
print(query)
df[abbv] = (df[abbv]-df[abbv][0]) / df[abbv][0] * 100.0
print(df.head())
if main_df.empty:
main_df = df
else:
main_df = main_df.join(df)
pickle_out = open('fiddy_states3.pickle','wb')
pickle.dump(main_df, pickle_out)
pickle_out.close()
def HPI_Benchmark():
df = Quandl.get("FMAC/HPI_USA", authtoken=api_key)
df["United States"] = (df["United States"]-df["United States"][0]) / df["United States"][0] * 100.0
return df
fig = plt.figure()
ax1 = plt.subplot2grid((1,1), (0,0))
HPI_data = pd.read_pickle('fiddy_states3.pickle')
HPI_State_Correlation = HPI_data.corr()
```
首先,讓我們更簡單一點,首先參考德克薩斯州的信息,然后重新抽樣:
```py
TX1yr = HPI_data['TX'].resample('A')
print(TX1yr.head())
```
```
Date
1975-12-31 4.559105
1976-12-31 11.954152
1977-12-31 23.518179
1978-12-31 41.978042
1979-12-31 64.700665
Freq: A-DEC, Name: TX, dtype: float64
```
我們以`A`重新采樣,這會每年重新采樣(年終)。 你可以在這里找到所有的`resample`選項:`http://pandas.pydata.org/pandas-docs/stable/timeseries.html#offset-aliases`,但這里是我寫這篇教程時的最新版本:
```
Resample rule:
xL for milliseconds
xMin for minutes
xD for Days
Alias Description
B business day frequency
C custom business day frequency (experimental)
D calendar day frequency
W weekly frequency
M month end frequency
BM business month end frequency
CBM custom business month end frequency
MS month start frequency
BMS business month start frequency
CBMS custom business month start frequency
Q quarter end frequency
BQ business quarter endfrequency
QS quarter start frequency
BQS business quarter start frequency
A year end frequency
BA business year end frequency
AS year start frequency
BAS business year start frequency
BH business hour frequency
H hourly frequency
T minutely frequency
S secondly frequency
L milliseonds
U microseconds
N nanoseconds
How:
mean, sum, ohlc
```
現在我們可以比較兩個數據集:
```py
HPI_data['TX'].plot(ax=ax1)
TX1yr.plot(color='k',ax=ax1)
plt.legend().remove()
plt.show()
```

你可以看到,從月度數據變為年度數據并沒有真正向我們隱藏趨勢線本身的任何信息,但是至少在德克薩斯州,有一件有趣的事情需要注意,你覺得月度數據中的那些扭曲看起來有些模式化?我反正是。你可以將鼠標懸停在所有峰值上,然后開始查看出現峰值的一年中的月份。大部分峰值出現在 6 月左右,幾乎每個最低值都在 12 月左右。許多州都有這種模式,而且在美國的 HPI 中也是如此。也許我們會玩玩這些趨勢,并完成整個教程!我們現在是專家!
好的不完全是,我想我們會繼續教程。所以通過重新采樣,我們可以選擇間隔,以及我們希望“如何”重新采樣。默認是按照均值,但也有一個時期的總和。如果我們按年份重采樣,使用`how=sum`,那么收益就是這一年所有 HPI 值的總和。最后是 OHLC,這是高開低收。這將返回這個期間的起始值,最高值,最低值和最后一個值。
我認為我們最好堅持使用月度數據,但重新采樣絕對值得在任何 Pandas 教程中涵蓋。現在,你可能想知道,為什么我們為重采樣創建了一個新的數據幀,而不是將其添加到現有的數據幀中。原因是它會創建大量的`NaN`數據。有時候,即使只是原始的重采樣也會包含`NaN`數據,特別是如果你的數據不按照統一的時間間隔更新的話。處理丟失的數據是一個主要的話題,但是我們將在下一個教程中試圖廣泛地介紹它,包括處理丟失數據的思路,以及如何通過程序處理你的選擇。
## 十、處理缺失數據
歡迎閱讀 Python 和 Pandas 數據分析教程的第 10 部分。在這一部分中,我們將討論缺失或不可用的數據。考慮到缺失數據的存在,我們有幾個選擇。
+ 忽略它 - 只把它留在那里
+ 刪除它 - 刪除所有的情況。完全從數據中刪除。這意味著放棄整行數據。
+ 向前或向后填充 - 這意味著只是采用之前或之后的值填充。
+ 將其替換為靜態的東西 - 例如,用`-9999`替換所有的`NaN`數據。
由于各種原因,這些選項各有其優點。忽略它不需要我們更多的工作。你可能會出于法律原因選擇忽略丟失的數據,或者保留數據的最大完整性。缺失數據也可能是非常重要的數據。例如,也許你的分析的一部分是調查服務器的信號丟失。在這種情況下,缺失數據可能非常重要,需要保持在集合中。
接下來,我們可以刪除它。在這里你有另外兩個選擇。如果行中包含任意數量的`NaN`數據,或者如果該行完全是`NaN`數據,則可以刪除這些行。通常,充滿`NaN`數據的行來自你在數據集上執行的計算,并且數據沒有真的丟失,只是你的公式不可用。在大多數情況下,你至少需要刪除所有完全是`NaN`的行,并且在很多情況下,你只希望刪除任何具有`NaN`數據的行。我們該怎么做呢?我們將從以下腳本開始(請注意,現在通過在`HPI_data`數據幀中添加一個新列,來完成重新采樣)。
```py
import Quandl
import pandas as pd
import pickle
import matplotlib.pyplot as plt
from matplotlib import style
style.use('fivethirtyeight')
# Not necessary, I just do this so I do not show my API key.
api_key = open('quandlapikey.txt','r').read()
def state_list():
fiddy_states = pd.read_html('https://simple.wikipedia.org/wiki/List_of_U.S._states')
return fiddy_states[0][0][1:]
def grab_initial_state_data():
states = state_list()
main_df = pd.DataFrame()
for abbv in states:
query = "FMAC/HPI_"+str(abbv)
df = Quandl.get(query, authtoken=api_key)
print(query)
df[abbv] = (df[abbv]-df[abbv][0]) / df[abbv][0] * 100.0
print(df.head())
if main_df.empty:
main_df = df
else:
main_df = main_df.join(df)
pickle_out = open('fiddy_states3.pickle','wb')
pickle.dump(main_df, pickle_out)
pickle_out.close()
def HPI_Benchmark():
df = Quandl.get("FMAC/HPI_USA", authtoken=api_key)
df["United States"] = (df["United States"]-df["United States"][0]) / df["United States"][0] * 100.0
return df
##fig = plt.figure()
##ax1 = plt.subplot2grid((1,1), (0,0))
HPI_data = pd.read_pickle('fiddy_states3.pickle')
HPI_data['TX1yr'] = HPI_data['TX'].resample('A')
print(HPI_data[['TX','TX1yr']])
##HPI_data['TX'].plot(ax=ax1)
##HPI_data['TX1yr'].plot(color='k',ax=ax1)
##
##plt.legend().remove()
##plt.show()
```
我們現在注釋了繪圖的東西,但是我們稍后會回顧它。
輸出:
```
TX TX1yr
Date
1975-01-31 0.000000 NaN
1975-02-28 1.291954 NaN
1975-03-31 3.348154 NaN
1975-04-30 6.097700 NaN
1975-05-31 6.887769 NaN
1975-06-30 5.566434 NaN
1975-07-31 4.710613 NaN
1975-08-31 4.612650 NaN
1975-09-30 4.831876 NaN
1975-10-31 5.192504 NaN
1975-11-30 5.832832 NaN
1975-12-31 6.336776 4.559105
1976-01-31 6.576975 NaN
1976-02-29 7.364782 NaN
1976-03-31 9.579950 NaN
1976-04-30 12.867197 NaN
1976-05-31 14.018165 NaN
1976-06-30 12.938501 NaN
1976-07-31 12.397848 NaN
1976-08-31 12.388581 NaN
1976-09-30 12.638779 NaN
1976-10-31 13.341849 NaN
1976-11-30 14.336404 NaN
1976-12-31 15.000798 11.954152
1977-01-31 15.555243 NaN
1977-02-28 16.921638 NaN
1977-03-31 20.118106 NaN
1977-04-30 25.186161 NaN
1977-05-31 26.260529 NaN
1977-06-30 23.430347 NaN
... ... ...
2011-01-31 280.574891 NaN
2011-02-28 281.202150 NaN
2011-03-31 282.772390 NaN
2011-04-30 284.374537 NaN
2011-05-31 286.518910 NaN
2011-06-30 288.665880 NaN
2011-07-31 288.232992 NaN
2011-08-31 285.507223 NaN
2011-09-30 283.408865 NaN
2011-10-31 282.348926 NaN
2011-11-30 282.026481 NaN
2011-12-31 282.384836 284.001507
2012-01-31 283.248573 NaN
2012-02-29 285.790368 NaN
2012-03-31 289.946517 NaN
2012-04-30 294.803887 NaN
2012-05-31 299.670256 NaN
2012-06-30 303.575682 NaN
2012-07-31 305.478743 NaN
2012-08-31 305.452329 NaN
2012-09-30 305.446084 NaN
2012-10-31 306.424497 NaN
2012-11-30 307.557154 NaN
2012-12-31 308.404771 299.649905
2013-01-31 309.503169 NaN
2013-02-28 311.581691 NaN
2013-03-31 315.642943 NaN
2013-04-30 321.662612 NaN
2013-05-31 328.279935 NaN
2013-06-30 333.565899 NaN
[462 rows x 2 columns]
```
我們有很多`NaN`數據。 如果我們取消所有繪圖代碼的注釋,會發生什么? 原來,我們沒有得到包含`NaN`數據的圖表! 這是一個偷懶,所以首先我們想,好吧,讓我們丟掉所有有`NaN`數據的行。 這僅僅是出于教程的目的。 在這個例子中,這將是一個非常糟糕的主意。 相反,你會想要做我們原來做的事情,這是為重采樣數據創建一個新的數據幀。 并不意味著你可以總是這樣做,但在這種情況下,你可以這樣做。 無論如何,讓我們刪除包含任何`na`數據的所有行。 這很簡單:
```py
HPI_data.dropna(inplace=True)
print(HPI_data[['TX','TX1yr']])
```
```
TX TX1yr
Date
1975-12-31 6.336776 4.559105
1976-12-31 15.000798 11.954152
1977-12-31 30.434104 23.518179
1978-12-31 51.029953 41.978042
1979-12-31 75.975953 64.700665
1980-12-31 89.979964 85.147662
1981-12-31 108.121926 99.016599
1982-12-31 118.210559 114.589927
1983-12-31 127.233791 122.676432
1984-12-31 133.599958 131.033359
1985-12-31 132.576673 133.847016
1986-12-31 126.581048 131.627647
1987-12-31 109.829893 119.373827
1988-12-31 104.602726 107.930502
1989-12-31 108.485926 107.311348
1990-12-31 109.082279 108.727174
1991-12-31 114.471725 113.142303
1992-12-31 121.427564 119.650162
1993-12-31 129.817931 127.009907
1994-12-31 135.119413 134.279735
1995-12-31 141.774551 139.197583
1996-12-31 146.991204 145.786792
1997-12-31 155.855049 152.109010
1998-12-31 170.625043 164.595301
1999-12-31 188.404171 181.149544
2000-12-31 206.579848 199.952853
2001-12-31 217.747701 215.692648
2002-12-31 230.161877 226.962219
2003-12-31 236.946005 235.459053
2004-12-31 248.031552 245.225988
2005-12-31 267.728910 260.589093
2006-12-31 288.009470 281.876293
2007-12-31 296.154296 298.094138
2008-12-31 288.081223 296.999508
2009-12-31 291.665787 292.160280
2010-12-31 281.678911 291.357967
2011-12-31 282.384836 284.001507
2012-12-31 308.404771 299.649905
```
沒有帶有缺失數據的行了!
現在我們可以繪制它:
```py
fig = plt.figure()
ax1 = plt.subplot2grid((1,1), (0,0))
HPI_data = pd.read_pickle('fiddy_states3.pickle')
HPI_data['TX1yr'] = HPI_data['TX'].resample('A')
HPI_data.dropna(inplace=True)
print(HPI_data[['TX','TX1yr']])
HPI_data['TX'].plot(ax=ax1)
HPI_data['TX1yr'].plot(color='k',ax=ax1)
plt.legend().remove()
plt.show()
```

好的,太好了。 現在只是出于教程的目的,我們如何編寫代碼,只在整行是`NaN`時才刪除行?
```py
HPI_data.dropna(how='all',inplace=True)
```
對于`how`參數,你可以選擇`any`或`all`。 `all`需要該行中的所有數據為`NaN`,才能將其刪除。 你也可以選擇`any`,然后設置一個閾值。 該閾值將要求存在許多非`na`值,才能接受該行。 更多信息,請參閱`dropna`的`Pandas`文檔。
好吧,所以這就是`dropna`,接下來我們可以填充它。 使用填充,我們又有兩個主要的選擇,是向前還是向后。 另一個選擇是僅僅替換數據,但我們稱這是一個單獨的選擇。 碰巧相同函數可以用于實現它,`fillna`。
修改我們原來的代碼塊,主要改變:
```py
HPI_data.fillna(method='ffill',inplace=True)
```
變為:
```py
fig = plt.figure()
ax1 = plt.subplot2grid((1,1), (0,0))
HPI_data = pd.read_pickle('fiddy_states3.pickle')
HPI_data['TX1yr'] = HPI_data['TX'].resample('A')
HPI_data.fillna(method='ffill',inplace=True)
HPI_data.dropna(inplace=True)
print(HPI_data[['TX','TX1yr']])
HPI_data['TX'].plot(ax=ax1)
HPI_data['TX1yr'].plot(color='k',ax=ax1)
plt.legend().remove()
plt.show()
```

`ffill`,或者“前向填充”所做的就是,將數據向前掃描,填充到缺失的數據中。 把它看作是一個掃描動作,其中你可以從過去獲取數據,將其轉移到缺失的數據中。 任何缺失數據的情況都會以最近的非缺失數據填入。 `Bfill`或后向填充是相反的:
```py
HPI_data.fillna(method='bfill',inplace=True)
```

這從未來獲取數據,并向后掃描來填充缺失。
現在,對于最后一種方法,替換數據。 `NaN`數據是相對毫無價值的數據,但它可以污染我們的其余數據。以機器學習為例,其中每行是一個特征集,每列是一個特征。數據對我們來說價值非常高,如果我們有大量的`NaN`數據,那么放棄所有的數據是非常糟糕的。出于這個原因,你可能實際上使用替換。對于大多數機器學習分類器來說,最終的異常值通常被忽略為自己的數據點。正因為如此,很多人會做的是獲取任何`NaN`數據,并用`-99999`的值代替它。這是因為在數據預處理之后,通常需要將所有特征轉換為`-1`到`1`的范圍。對于幾乎任何分類器來說,數據點`-99999`是一個明顯的異常值。但是`NaN`的數據,根本無法處理!因此,我們可以通過執行以下操作來替換數據:
```py
HPI_data.fillna(value=-99999,inplace=True)
```
現在,在我們的情況下,這是一個毫無用處的操作,但它確實在某些形式的數據分析中占有一席之地。
現在我們已經介紹了處理缺失數據的基礎知識,我們準備繼續。 在下一篇教程中,我們將討論另一種平滑數據的方法,這些方法可以讓我們保留月度數據:滾動統計量。 這對于平滑我們的數據,以及在它上面收集一些基本的統計量是有用的。
## 十一、滾動統計量
歡迎閱讀另一個 Python 和 Pandas 數據分析系列教程,這里面我們成為了房地產大亨。在本教程中,我們將討論各種滾動統計量在我們的數據幀中的應用。
其中較受歡迎的滾動統計量是移動均值。這需要一個移動的時間窗口,并計算該時間段的均值作為當前值。在我們的情況下,我們有月度數據。所以 10 移動均值就是當前值加上前 9 個月的數據的均值,之后我們的月度數據將有 10 個移動均值。Pandas 做這個是非常快的。Pandas 帶有一些預先制作的滾動統計量,但也有一個叫做`rolling_apply`。這使我們可以編寫我們自己的函數,接受窗口數據并應用我們想要的任何合理邏輯。這意味著,即使Pandas 沒有處理你想要的東西的正式函數,他們已經覆蓋了你,讓你準確地編寫你需要的東西。讓我們從基本的移動均值開始,或者 Pandas 叫它`rolling_mean`。你可以查看 Pandas 文檔中的所有移動/滾動統計量。
前面的教程涵蓋了我們的起始腳本,如下所示:
```py
import Quandl
import pandas as pd
import pickle
import matplotlib.pyplot as plt
from matplotlib import style
style.use('fivethirtyeight')
# Not necessary, I just do this so I do not show my API key.
api_key = open('quandlapikey.txt','r').read()
def state_list():
fiddy_states = pd.read_html('https://simple.wikipedia.org/wiki/List_of_U.S._states')
return fiddy_states[0][0][1:]
def grab_initial_state_data():
states = state_list()
main_df = pd.DataFrame()
for abbv in states:
query = "FMAC/HPI_"+str(abbv)
df = Quandl.get(query, authtoken=api_key)
print(query)
df[abbv] = (df[abbv]-df[abbv][0]) / df[abbv][0] * 100.0
print(df.head())
if main_df.empty:
main_df = df
else:
main_df = main_df.join(df)
pickle_out = open('fiddy_states3.pickle','wb')
pickle.dump(main_df, pickle_out)
pickle_out.close()
def HPI_Benchmark():
df = Quandl.get("FMAC/HPI_USA", authtoken=api_key)
df["United States"] = (df["United States"]-df["United States"][0]) / df["United States"][0] * 100.0
return df
fig = plt.figure()
ax1 = plt.subplot2grid((1,1), (0,0))
HPI_data = pd.read_pickle('fiddy_states3.pickle')
plt.show()
```
現在,在定義`HPI_data`之后,我們可以添加一些新的數據,如下所示:
```py
HPI_data['TX12MA'] = pd.rolling_mean(HPI_data['TX'], 12)
```
這給了我們一個新列,我們命名為`TX12MA`來表示得克薩斯和 12 移動平均。 我們將這個應用到`pd.rolling_mean()`中,該函數接受 2 個主要參數,我們正在應用的數據以及我們打算執行的周期/窗口。

使用滾動統計量,開頭將生成`NaN`數據。 考慮執行 10 移動均值。 在`#3`行,我們根本沒有 10 個以前的數據點。 因此會形成`NaN`數據。 你可以把它留在那里,或者用前面的教程中的`dropna()`來刪除它。
另一個有趣的是滾動標準差。 我們需要把它放在自己的圖表上,但我們可以這樣做:
```py
ig = plt.figure()
ax1 = plt.subplot2grid((2,1), (0,0))
ax2 = plt.subplot2grid((2,1), (1,0), sharex=ax1)
HPI_data = pd.read_pickle('fiddy_states3.pickle')
HPI_data['TX12MA'] = pd.rolling_mean(HPI_data['TX'], 12)
HPI_data['TX12STD'] = pd.rolling_std(HPI_data['TX'], 12)
HPI_data['TX'].plot(ax=ax1)
HPI_data['TX12MA'].plot(ax=ax1)
HPI_data['TX12STD'].plot(ax=ax2)
plt.show()
```

這里發生了一些事情,讓我們快速談論它們。
```py
ax1 = plt.subplot2grid((2,1), (0,0))
ax2 = plt.subplot2grid((2,1), (1,0), sharex=ax1)
```
在這里,我們定義了第二個軸,并改變我們的大小。 我們說這個子圖的網格是`2×1`(高 2,寬 1),那么我們說`ax1`從`0,0`開始,`ax2`從`1,0`開始,它和`ax1`共享`x`軸。 這使我們可以放大一個圖形,而另一個圖形也放大到同一點。 仍然對 Matplotlib 感到困惑? 使用 Matplotlib 系列教程查看完整的數據可視化。
接下來,我們計算移動標準差:
```py
HPI_data['TX12STD'] = pd.rolling_std(HPI_data['TX'], 12)
```
然后,我們繪制所有東西。
另一個有趣的可視化是比較得克薩斯`HPI`與整體`HPI`。 然后計算他們兩個之間的滾動相關性。 假設是,相關性下降時,很快就會出現逆轉。 如果相關性下降,這意味著得克薩斯`HPI`和整體`HPI`是不一致的。 比方說,美國整體的`HPI`在上面,`TX_HPI`在下面產生分歧。 在這種情況下,我們可能會選擇投資德克薩斯州的房地產。 另一個選擇是使用`TX`和另一個高度相關的區域。 例如,德克薩斯州與阿拉斯加的相關系數為`0.983235`。 讓我們看看我們的計劃看起來怎么樣。 最后一塊應該現在看起來是這樣:
```py
fig = plt.figure()
ax1 = plt.subplot2grid((2,1), (0,0))
ax2 = plt.subplot2grid((2,1), (1,0), sharex=ax1)
HPI_data = pd.read_pickle('fiddy_states3.pickle')
TX_AK_12corr = pd.rolling_corr(HPI_data['TX'], HPI_data['AK'], 12)
HPI_data['TX'].plot(ax=ax1, label="TX HPI")
HPI_data['AK'].plot(ax=ax1, label="AK HPI")
ax1.legend(loc=4)
TX_AK_12corr.plot(ax=ax2)
plt.show()
```

每當相關性下降時,你理論上應該在上漲的地方出售房地產,然后你應該購買正在下降的地區的房地產。這個想法是,這兩個地區是高度相關的,我們可以非常確信,相關性最終會回到`0.98`左右。因此,當相關系數為`-0.5`時,我們可以非常有把握地決定采取這樣的行動,因為結果可能是下面的結果之一:`HPI`永遠是這樣的分歧,永遠不會恢復(不太可能),下降的地區上升并遇到上升的地區,這樣我們贏了,上升的地區下降并遇到另一個下降的地區,在這種情況下,我們發了一筆大財,或者雙方都重新一致,在這種情況下,我們肯定贏了。 `HPI`不可能完全背離這些市場。我們可以清楚地看到,這完全不會發生,我們有 40 年的數據支持。
在接下來的教程中,我們將討論異常值檢測,不管是錯誤與否,還包括了如何處理這些數據背后的一些哲理。
## 十二、將比較操作應用于數據幀
歡迎閱讀 Python 和 Pandas 數據分析系列教程第 12 部分。 在本教程中,我們將簡要討論如何處理錯誤/異常數據。 僅僅因為數據是異常的,并不意味著它是錯誤的。 很多時候,離群數據點可以使一個假設無效,所以去除它的必要性可能會很高,但這不是我們在這里討論的。
錯誤的異常值是多少? 我喜歡使用的一個例子是測量諸如橋梁之類的波動。 由于橋梁承載重量,他們可以移動一點。 在風浪中,可以稍微擺動一下,就會有一些自然的運動。 隨著時間的推移,支撐力量減弱,橋梁可能會移動太多,最終需要加固。 也許我們有一個不斷測量橋梁高度波動的系統。

一些距離傳感器使用激光,另一些則反彈聲波。 無論你想假裝我們正在使用哪個,都沒關系。 我們會假裝聲波。 它們的工作方式是從觸發器發出聲波,然后在前面物體處反彈,返回到接收器。 從這里開始,整個操作發生的時間被考慮在內。 由于音速是一個常數,我們可以從這個過程的時間推斷出聲波傳播的距離。 問題是,這只衡量聲波傳播了多遠。 例如他們去了橋梁和背部,沒有 100% 的確定性。 也許一片樹葉在測量時掉落,并在信號回到接收器之前反彈了信號,誰知道呢。 比方說,舉個例子,你有以下的橋梁讀數:
```py
bridge_height = {'meters':[10.26, 10.31, 10.27, 10.22, 10.23, 6212.42, 10.28, 10.25, 10.31]}
```
我們可以可視化:
```py
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib import style
style.use('fivethirtyeight')
bridge_height = {'meters':[10.26, 10.31, 10.27, 10.22, 10.23, 6212.42, 10.28, 10.25, 10.31]}
df = pd.DataFrame(bridge_height)
df.plot()
plt.show()
```
那么橋是不是被外星人動過了? 由于此后我們有更多的正常讀數,`6212.42`更可能是一個不好的讀數。 我們可以直觀地看出這是一個異常,但是我們怎么能通過我們的程序檢測到這一點?
我們意識到這是一個異常值,因為它與其他價有很大的不同,以及它比其他任何值都突然上升或下降的事實。 聽起來我們可以僅僅應用標準差。 我們用它來自動檢測這個不好的讀數。
```py
df['STD'] = pd.rolling_std(df['meters'], 2)
print(df)
```
```
meters STD
0 10.26 NaN
1 10.31 0.035355
2 10.27 0.028284
3 10.22 0.035355
4 10.23 0.007071
5 6212.42 4385.610607
6 10.28 4385.575252
7 10.25 0.021213
8 10.31 0.042426
```
> 注:兩個數的標準差就是`|a - b|/2`。
接下來,我們可以獲得整個集合的標準差,如:
```py
df_std = df.describe()
print(df_std)
df_std = df.describe()['meters']['std']
print(df_std)
```
```
meters STD
count 9.000000 8.000000
mean 699.394444 1096.419446
std 2067.384584 2030.121949
min 10.220000 0.007071
25% 10.250000 0.026517
50% 10.270000 0.035355
75% 10.310000 1096.425633
max 6212.420000 4385.610607
2067.38458357
```
首先,我們得到所有的描述。 顯示了大部分,所以你看我們如何處理數據。 然后,我們直接查看米的標準差,這是 2067 和一些變化。 這是一個相當高的數字,但仍然遠低于主要波動(4385)的標準差。 現在,我們可以遍歷并刪除所有標準差高于這個值的數據。
這使我們能夠學習一項新技能:在邏輯上修改數據幀! 我們可以這樣做:
```py
df = df[ (df['STD'] < df_std) ]
print(df)
```
```
meters STD
1 10.31 0.035355
2 10.27 0.028284
3 10.22 0.035355
4 10.23 0.007071
7 10.25 0.021213
8 10.31 0.042426
```
之后我們可以繪制所有東西:
```py
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib import style
style.use('fivethirtyeight')
bridge_height = {'meters':[10.26, 10.31, 10.27, 10.22, 10.23, 6212.42, 10.28, 10.25, 10.31]}
df = pd.DataFrame(bridge_height)
df['STD'] = pd.rolling_std(df['meters'], 2)
print(df)
df_std = df.describe()
print(df_std)
df_std = df.describe()['meters']['std']
print(df_std)
df = df[ (df['STD'] < df_std) ]
print(df)
df['meters'].plot()
plt.show()
```
輸出:

我們剛學到的新行是`df = df[ (df['STD'] < df_std) ]`。 這是如何工作的? 首先,我們一開始重新定義`df`。 我們說現在`df`等于`df`,其中`df['STD']`小于我們之前計算的整體`df_std`。 因此,這里唯一剩下的數據將是標準差小于 2067 的數據。
再次,當我們知道這些數據錯誤的,我們應該刪除它。 因為數據不“適合”你而刪除,幾乎總是一個壞主意。
## 十三、30 年抵押貸款利率
歡迎閱讀 Python 和 Pandas 數據分析第 13 部分,以房地產投資為例。到了這里,我們已經了解了 Pandas 能提供給我們的東西,我們會在這里面對一些挑戰!正如我們到目前為止所介紹的那樣,我們可以根據高度相關的州對之間的分歧,做出風險相對較低的投資,可能做得很好。稍后我們將介紹測試這個策略,但是現在讓我們來看看獲取包含房屋價值的其他必要數據:利率。現在,抵押貸款利率有很多不同的類型,既有利息收入,也有貸款的時間表。這些年來,意見有所不同,根據目前的市場情況,是否需要 10 年,15 年或 30 年的抵押貸款。那么你必須考慮你是否想要可調整的利率,或者在半路上再決定為你的房子付費的方式。
在數據的最后,所有這些數據都是有限的,但最終可能會有點過于嘈雜。現在,讓我們簡單介紹一下 30 年的傳統抵押貸款利率。現在,這個數據應該與房價指數(HPI)非常負相關。在這個低嗎之前,我會自動假設并期望相關性不會非常強,就像高于 90% 的`HPI`相關性,它肯定低于`-0.9`,而且應該比`-0.5`大。利率當然很重要,但是整個`HPI`的相關性非常強,因為這些數據非常相似。利率當然是相關的,但并不像其他`HPI`值或美國`HPI`那樣直接。
首先,我們抓取這些數據。我們將開始創建一個新的函數:
```py
def mortgage_30y():
df = Quandl.get("FMAC/MORTG", trim_start="1975-01-01", authtoken=api_key)
df["Value"] = (df["Value"]-df["Value"][0]) / df["Value"][0] * 100.0
print(df.head())
return df
mortgage_30y()
```
```
Value
Date
1975-01-01 0.000000
1975-02-01 -3.393425
1975-03-01 -5.620361
1975-04-01 -6.468717
1975-05-01 -5.514316
```
這里有幾個要點。 首先,注意添加到`Quandl.get()`的新參數,它是`trim_start`。 這使我們能夠在特定的日期啟動數據。 我們之所以選擇 1975 年 1 月 1 日,是因為那是我們的房價指數數據開始的時候。 從這里,我們打印數據頭部,我們有了第一個問題:這是某月的第一天,而不是月底。 當我們將這個數據幀加入到其他數據幀時,這會造成麻煩。 那么現在怎么辦? 我們已經學會了如何重新采樣,如果我們只是使用`M`來進行典型的重新采樣,這意味著月末,會怎么樣呢? 也許這會把數據移動到第 31 天,因為這個月只有一個值。
```py
def mortgage_30y():
df = Quandl.get("FMAC/MORTG", trim_start="1975-01-01", authtoken=api_key)
df["Value"] = (df["Value"]-df["Value"][0]) / df["Value"][0] * 100.0
df=df.resample('M')
print(df.head())
return df
mortgage_30y()
```
```
Value
Date
1975-01-31 NaN
1975-02-28 NaN
1975-03-31 NaN
1975-04-30 NaN
1975-05-31 NaN
```
好吧,這并沒有那么好。 我們可能需要多個數據點才能進行計算,那么我們該怎么做? 我們可以嘗試調整日期列或別的,或者我們可以做一些黑魔法。 如果我們只是按天抽樣呢? 如果我們這樣做的話,那么這個數字將在整個月份里持續重復。 然后,我們可以重采樣到月末,然后一切都應該有效。
```py
def mortgage_30y():
df = Quandl.get("FMAC/MORTG", trim_start="1975-01-01", authtoken=api_key)
df["Value"] = (df["Value"]-df["Value"][0]) / df["Value"][0] * 100.0
df=df.resample('1D')
df=df.resample('M')
print(df.head())
return df
mortgage_30y()
```
```
Value
Date
1975-01-31 0.000000
1975-02-28 -3.393425
1975-03-31 -5.620361
1975-04-30 -6.468717
1975-05-31 -5.514316
```
我們贏了! 接下來,我們可以獲取所有的數據,將這個新的數據集添加到數據幀中,現在我們真的上路了。 為了防止你剛剛加入我們,或者你半路走丟了,這里是目前為止的代碼:
```py
import Quandl
import pandas as pd
import pickle
import matplotlib.pyplot as plt
from matplotlib import style
style.use('fivethirtyeight')
# Not necessary, I just do this so I do not show my API key.
api_key = open('quandlapikey.txt','r').read()
def state_list():
fiddy_states = pd.read_html('https://simple.wikipedia.org/wiki/List_of_U.S._states')
return fiddy_states[0][0][1:]
def grab_initial_state_data():
states = state_list()
main_df = pd.DataFrame()
for abbv in states:
query = "FMAC/HPI_"+str(abbv)
df = Quandl.get(query, authtoken=api_key)
print(query)
df[abbv] = (df[abbv]-df[abbv][0]) / df[abbv][0] * 100.0
print(df.head())
if main_df.empty:
main_df = df
else:
main_df = main_df.join(df)
pickle_out = open('fiddy_states3.pickle','wb')
pickle.dump(main_df, pickle_out)
pickle_out.close()
def HPI_Benchmark():
df = Quandl.get("FMAC/HPI_USA", authtoken=api_key)
df["United States"] = (df["United States"]-df["United States"][0]) / df["United States"][0] * 100.0
return df
def mortgage_30y():
df = Quandl.get("FMAC/MORTG", trim_start="1975-01-01", authtoken=api_key)
df["Value"] = (df["Value"]-df["Value"][0]) / df["Value"][0] * 100.0
df=df.resample('1D')
df=df.resample('M')
return df
```
現在我們可以做一些事情,例如:
```py
HPI_data = pd.read_pickle('fiddy_states3.pickle')
m30 = mortgage_30y()
HPI_Bench = HPI_Benchmark()
m30.columns=['M30']
HPI = HPI_Bench.join(m30)
print(HPI.head())
```
```
United States M30
Date
1975-01-31 0.000000 0.000000
1975-02-28 0.594738 -3.393425
1975-03-31 1.575473 -5.620361
1975-04-30 2.867177 -6.468717
1975-05-31 3.698896 -5.514316
```
下面,我們可以立即計算一個簡單的相關性:
```py
print(HPI.corr())
United States M30
United States 1.000000 -0.740009
M30 -0.740009 1.000000
```
這是我們的預期。 `-0.74`是相當強的負值。 很明顯,各州之間的聯系并不是很好,但這顯然是一個有用的指標。 接下來,我們可以在所有州上檢查這個指標:
```py
state_HPI_M30 = HPI_data.join(m30)
print(state_HPI_M30.corr())
```
```
AL AK AZ AR CA CO CT \
AL 1.000000 0.944603 0.927361 0.994896 0.935970 0.979352 0.953724
AK 0.944603 1.000000 0.893904 0.965830 0.900621 0.949834 0.896395
AZ 0.927361 0.893904 1.000000 0.923786 0.973546 0.911422 0.917500
AR 0.994896 0.965830 0.923786 1.000000 0.935364 0.985934 0.948341
CA 0.935970 0.900621 0.973546 0.935364 1.000000 0.924982 0.956495
CO 0.979352 0.949834 0.911422 0.985934 0.924982 1.000000 0.917129
CT 0.953724 0.896395 0.917500 0.948341 0.956495 0.917129 1.000000
DE 0.980566 0.939196 0.942273 0.975830 0.970232 0.949517 0.981177
FL 0.918544 0.887891 0.994007 0.915989 0.987200 0.905126 0.926364
GA 0.973562 0.880261 0.939715 0.960708 0.943928 0.959500 0.948500
HI 0.946054 0.930520 0.902554 0.947022 0.937704 0.903461 0.938974
ID 0.982868 0.944004 0.959193 0.977372 0.944342 0.960975 0.923099
IL 0.984782 0.905512 0.947396 0.973761 0.963858 0.968552 0.955033
IN 0.981189 0.889734 0.881542 0.973259 0.901154 0.971416 0.919696
IA 0.985516 0.943740 0.894524 0.987919 0.914199 0.991455 0.913788
KS 0.990774 0.957236 0.910948 0.995230 0.926872 0.994866 0.936523
KY 0.994311 0.938125 0.900888 0.992903 0.923429 0.987097 0.941114
LA 0.967232 0.990506 0.909534 0.982454 0.911742 0.972703 0.907456
ME 0.972693 0.935850 0.923797 0.972573 0.965251 0.951917 0.989180
MD 0.964917 0.943384 0.960836 0.964943 0.983677 0.940805 0.969170
MA 0.966242 0.919842 0.921782 0.966962 0.962672 0.959294 0.986178
MI 0.891205 0.745697 0.848602 0.873314 0.861772 0.900040 0.843032
MN 0.971967 0.926352 0.952359 0.972338 0.970661 0.983120 0.945521
MS 0.996089 0.962494 0.927354 0.997443 0.932752 0.985298 0.945831
MO 0.992706 0.933201 0.938680 0.989672 0.955317 0.985194 0.961364
MT 0.977030 0.976840 0.916000 0.983822 0.923950 0.971516 0.917663
NE 0.988030 0.941229 0.896688 0.990868 0.912736 0.992179 0.920409
NV 0.858538 0.785404 0.965617 0.846968 0.948143 0.837757 0.866554
NH 0.953366 0.907236 0.932992 0.952882 0.969574 0.941555 0.990066
NJ 0.968837 0.934392 0.943698 0.967477 0.975258 0.944460 0.989845
NM 0.992118 0.967777 0.934744 0.993195 0.934720 0.968001 0.946073
NY 0.973984 0.940310 0.921126 0.973972 0.959543 0.949474 0.989576
NC 0.998383 0.934841 0.915403 0.991863 0.928632 0.977069 0.956074
ND 0.936510 0.973971 0.840705 0.957838 0.867096 0.942225 0.882938
OH 0.966598 0.855223 0.883396 0.954128 0.901842 0.957527 0.911510
OK 0.944903 0.984550 0.881332 0.967316 0.882199 0.960694 0.879854
OR 0.981180 0.948190 0.949089 0.978144 0.944542 0.971110 0.916942
PA 0.985357 0.946184 0.915914 0.983651 0.950621 0.956316 0.975324
RI 0.950261 0.897159 0.943350 0.945984 0.984298 0.926362 0.988351
SC 0.998603 0.945949 0.929591 0.994117 0.942524 0.980911 0.959591
SD 0.983878 0.966573 0.889405 0.990832 0.911188 0.984463 0.924295
TN 0.998285 0.946858 0.919056 0.995949 0.931616 0.983089 0.953009
TX 0.963876 0.983235 0.892276 0.981413 0.902571 0.970795 0.919415
UT 0.983987 0.951873 0.926676 0.982867 0.909573 0.974909 0.900908
VT 0.975210 0.952370 0.909242 0.977904 0.949225 0.951388 0.973716
VA 0.972236 0.956925 0.950839 0.975683 0.977028 0.954801 0.970366
WA 0.988253 0.948562 0.950262 0.982877 0.956434 0.968816 0.941987
WV 0.984364 0.964846 0.907797 0.990264 0.924300 0.979467 0.925198
WI 0.990190 0.930548 0.927619 0.985818 0.943768 0.987609 0.936340
WY 0.944600 0.983109 0.892255 0.960336 0.897551 0.950113 0.880035
M30 -0.762343 -0.678591 -0.614237 -0.747709 -0.680250 -0.747269 -0.726121
DE FL GA ... TN TX UT \
AL 0.980566 0.918544 0.973562 ... 0.998285 0.963876 0.983987
AK 0.939196 0.887891 0.880261 ... 0.946858 0.983235 0.951873
AZ 0.942273 0.994007 0.939715 ... 0.919056 0.892276 0.926676
AR 0.975830 0.915989 0.960708 ... 0.995949 0.981413 0.982867
CA 0.970232 0.987200 0.943928 ... 0.931616 0.902571 0.909573
CO 0.949517 0.905126 0.959500 ... 0.983089 0.970795 0.974909
CT 0.981177 0.926364 0.948500 ... 0.953009 0.919415 0.900908
DE 1.000000 0.947876 0.954346 ... 0.977213 0.943323 0.952441
FL 0.947876 1.000000 0.933753 ... 0.910359 0.881164 0.908197
GA 0.954346 0.933753 1.000000 ... 0.970564 0.920372 0.943421
HI 0.976226 0.909336 0.887794 ... 0.941823 0.916708 0.925630
ID 0.971421 0.947140 0.953024 ... 0.976012 0.943472 0.989533
IL 0.978133 0.948851 0.986683 ... 0.980145 0.925778 0.961563
IN 0.941916 0.873664 0.972737 ... 0.982888 0.928735 0.956452
IA 0.954993 0.888359 0.948792 ... 0.987924 0.959989 0.980798
KS 0.964387 0.903659 0.961825 ... 0.993486 0.978622 0.980113
KY 0.968469 0.895461 0.966719 ... 0.996549 0.961847 0.975918
LA 0.949931 0.899010 0.911625 ... 0.968690 0.989803 0.975590
ME 0.993413 0.932706 0.949576 ... 0.973697 0.946992 0.935993
MD 0.993728 0.968700 0.938240 ... 0.960881 0.935619 0.945962
MA 0.978758 0.931237 0.964604 ... 0.969053 0.943613 0.923883
MI 0.846668 0.846085 0.952179 ... 0.891484 0.806632 0.855976
MN 0.966800 0.955992 0.976933 ... 0.970940 0.944605 0.955689
MS 0.975673 0.917084 0.963318 ... 0.996444 0.977670 0.987812
MO 0.978316 0.936293 0.986001 ... 0.991835 0.958853 0.969655
MT 0.968166 0.909331 0.917504 ... 0.976586 0.967914 0.985605
NE 0.951875 0.888425 0.962706 ... 0.991270 0.966743 0.976138
NV 0.881209 0.971601 0.911678 ... 0.845672 0.791177 0.841324
NH 0.975576 0.943501 0.959112 ... 0.954165 0.930112 0.908947
NJ 0.995132 0.952767 0.950385 ... 0.967025 0.940268 0.935497
NM 0.980594 0.925001 0.949564 ... 0.989390 0.972216 0.986413
NY 0.993814 0.928749 0.947804 ... 0.974697 0.950417 0.937078
NC 0.977472 0.906887 0.976190 ... 0.998354 0.959839 0.976901
ND 0.926355 0.833816 0.849962 ... 0.944451 0.964373 0.942833
OH 0.927542 0.878248 0.980012 ... 0.966237 0.900707 0.935392
OK 0.917902 0.868255 0.893142 ... 0.947590 0.992422 0.951925
OR 0.969869 0.940983 0.945712 ... 0.977083 0.943652 0.991080
PA 0.994948 0.919264 0.946609 ... 0.984959 0.954439 0.956809
RI 0.984731 0.959567 0.951973 ... 0.947561 0.907964 0.906497
SC 0.983353 0.922779 0.976778 ... 0.997851 0.966682 0.979527
SD 0.963422 0.883479 0.931010 ... 0.987597 0.973825 0.979387
TN 0.977213 0.910359 0.970564 ... 1.000000 0.967678 0.982384
TX 0.943323 0.881164 0.920372 ... 0.967678 1.000000 0.956718
UT 0.952441 0.908197 0.943421 ... 0.982384 0.956718 1.000000
VT 0.992088 0.914969 0.929674 ... 0.976577 0.955538 0.947708
VA 0.994223 0.957210 0.939416 ... 0.970906 0.952162 0.953655
WA 0.985085 0.945027 0.956455 ... 0.983588 0.950234 0.984835
WV 0.968813 0.901690 0.931330 ... 0.985509 0.967845 0.983636
WI 0.970690 0.925943 0.974086 ... 0.988615 0.946572 0.977972
WY 0.938938 0.884962 0.869454 ... 0.945079 0.963628 0.965801
M30 -0.758073 -0.627997 -0.706512 ... -0.770422 -0.669410 -0.737147
VT VA WA WV WI WY M30
AL 0.975210 0.972236 0.988253 0.984364 0.990190 0.944600 -0.762343
AK 0.952370 0.956925 0.948562 0.964846 0.930548 0.983109 -0.678591
AZ 0.909242 0.950839 0.950262 0.907797 0.927619 0.892255 -0.614237
AR 0.977904 0.975683 0.982877 0.990264 0.985818 0.960336 -0.747709
CA 0.949225 0.977028 0.956434 0.924300 0.943768 0.897551 -0.680250
CO 0.951388 0.954801 0.968816 0.979467 0.987609 0.950113 -0.747269
CT 0.973716 0.970366 0.941987 0.925198 0.936340 0.880035 -0.726121
DE 0.992088 0.994223 0.985085 0.968813 0.970690 0.938938 -0.758073
FL 0.914969 0.957210 0.945027 0.901690 0.925943 0.884962 -0.627997
GA 0.929674 0.939416 0.956455 0.931330 0.974086 0.869454 -0.706512
HI 0.979103 0.976083 0.963950 0.952790 0.928536 0.935530 -0.755064
ID 0.955898 0.970393 0.994442 0.975239 0.977441 0.956742 -0.721927
IL 0.958711 0.968271 0.982702 0.962100 0.992079 0.911345 -0.753583
IN 0.937365 0.928187 0.955000 0.958981 0.982614 0.889497 -0.773100
IA 0.960204 0.955724 0.976571 0.990479 0.991509 0.955104 -0.785584
KS 0.967734 0.964949 0.977117 0.988007 0.989477 0.956913 -0.748138
KY 0.970702 0.962244 0.977386 0.985453 0.992035 0.938804 -0.785726
LA 0.958907 0.962746 0.967991 0.982913 0.957145 0.988894 -0.683956
ME 0.993570 0.990376 0.969212 0.963035 0.963999 0.929516 -0.769778
MD 0.983851 0.997558 0.981974 0.962220 0.960073 0.945807 -0.729642
MA 0.975046 0.975432 0.953441 0.947520 0.964247 0.904811 -0.758192
MI 0.817081 0.828781 0.862245 0.843538 0.918028 0.741663 -0.686146
MN 0.952722 0.969721 0.973082 0.961230 0.987026 0.927507 -0.723314
MS 0.974975 0.973635 0.986430 0.989047 0.986738 0.961005 -0.750756
MO 0.968741 0.972720 0.980907 0.974606 0.993691 0.930004 -0.747344
MT 0.974065 0.976197 0.985994 0.993622 0.972195 0.990517 -0.756735
NE 0.954657 0.949766 0.969023 0.981915 0.988942 0.938583 -0.761330
NV 0.828018 0.882206 0.882127 0.820529 0.874777 0.779155 -0.543798
NH 0.966338 0.972531 0.944892 0.930573 0.949941 0.892414 -0.722957
NJ 0.987844 0.992944 0.971273 0.956438 0.960854 0.928928 -0.743508
NM 0.977351 0.978702 0.988594 0.985877 0.976586 0.966689 -0.729704
NY 0.994142 0.989544 0.968541 0.962209 0.961359 0.929946 -0.770619
NC 0.973354 0.965901 0.981436 0.978326 0.987338 0.931717 -0.770820
ND 0.957772 0.944229 0.935840 0.972698 0.921882 0.977003 -0.763102
OH 0.912974 0.910193 0.939052 0.933308 0.974849 0.852217 -0.753133
OK 0.930105 0.933030 0.937180 0.959298 0.932422 0.969641 -0.621887
OR 0.959889 0.973285 0.995502 0.984262 0.984121 0.968156 -0.749370
PA 0.997231 0.989277 0.982052 0.978963 0.972162 0.945319 -0.779589
RI 0.970213 0.980550 0.953760 0.930845 0.950360 0.890562 -0.732558
SC 0.977946 0.975200 0.987828 0.982315 0.989425 0.943358 -0.754808
SD 0.976071 0.967219 0.976170 0.994328 0.979649 0.971496 -0.794906
TN 0.976577 0.970906 0.983588 0.985509 0.988615 0.945079 -0.770422
TX 0.955538 0.952162 0.950234 0.967845 0.946572 0.963628 -0.669410
UT 0.947708 0.953655 0.984835 0.983636 0.977972 0.965801 -0.737147
VT 1.000000 0.991347 0.975016 0.976666 0.961824 0.951637 -0.779342
VA 0.991347 1.000000 0.983402 0.973592 0.966393 0.956771 -0.745763
WA 0.975016 0.983402 1.000000 0.984210 0.984955 0.962198 -0.750646
WV 0.976666 0.973592 0.984210 1.000000 0.981398 0.977070 -0.770068
WI 0.961824 0.966393 0.984955 0.981398 1.000000 0.939200 -0.776679
WY 0.951637 0.956771 0.962198 0.977070 0.939200 1.000000 -0.702034
M30 -0.779342 -0.745763 -0.750646 -0.770068 -0.776679 -0.702034 1.000000
[51 rows x 51 columns]
```
我們感興趣的主要一列是 M30 與其它東西的對比,所以我們這樣做:
```py
print(state_HPI_M30.corr()['M30'])
```
```
AL -0.762343
AK -0.678591
AZ -0.614237
AR -0.747709
CA -0.680250
CO -0.747269
CT -0.726121
DE -0.758073
FL -0.627997
GA -0.706512
HI -0.755064
ID -0.721927
IL -0.753583
IN -0.773100
IA -0.785584
KS -0.748138
KY -0.785726
LA -0.683956
ME -0.769778
MD -0.729642
MA -0.758192
MI -0.686146
MN -0.723314
MS -0.750756
MO -0.747344
MT -0.756735
NE -0.761330
NV -0.543798
NH -0.722957
NJ -0.743508
NM -0.729704
NY -0.770619
NC -0.770820
ND -0.763102
OH -0.753133
OK -0.621887
OR -0.749370
PA -0.779589
RI -0.732558
SC -0.754808
SD -0.794906
TN -0.770422
TX -0.669410
UT -0.737147
VT -0.779342
VA -0.745763
WA -0.750646
WV -0.770068
WI -0.776679
WY -0.702034
M30 1.000000
Name: M30, dtype: float64
```
看起來亞利桑那(AZ)的負相關最弱,為`-0.614237`。 我們可以通過以下方式快速獲取更多數據:
```py
print(state_HPI_M30.corr()['M30'].describe())
```
```
count 51.000000
mean -0.699445
std 0.247709
min -0.794906
25% -0.762723
50% -0.748138
75% -0.722442
max 1.000000
Name: M30, dtype: float64
```
這里的均值在`-0.7`以下,這與我們以前的發現非常一致,這里并沒有太多的延展。這在邏輯上應該是顯而易見的,但數據明確地反映了,抵押貸款利率在房價中起著重要的作用。到目前為止,我所發現的有趣之處是,我們所看到的變化是多么的微小。有一些州存在分歧,但不是很多。大多數州嚴格保持在一條直線上,帶有非常簡單的規則。在深入局部地區之前,我們的第三個主要因素,是整體經濟。從這里開始,我們可以開始關注州的人口統計數據,同時我們深入到縣甚至社區。但是,我想知道,鑒于迄今為止這樣可靠的值,我們已經很容易為`HPI`制定一個公式。如果不是一個基本的公式,我懷疑我們可以在一個隨機森林分類器中使用這些數據,并做得很好。現在,讓我們繼續看看整體經濟。我們希望看到`0.5`以上的相關性。我們在下一個教程中介紹一下。
## 十四、添加其它經濟指標
大家好,歡迎閱讀我們的 Python 和 Pandas 數據分析(和地產投資)系列教程的第14部分。我們在這里已經走了很長一段路,我們想要在這里采取的下一個,最后一大步驟是研究宏觀經濟指標,看看它們對房價或`HPI`的影響。
SP500 (股票市場)和國內生產總值(GDP)是兩個主要的經濟指標。我懷疑 SP500 比國內生產總值相關性更高,但 GDP 總體來說是一個較好的整體經濟指標,所以我可能是錯的。以及,我懷疑在這里可能有價值的宏觀指標是失業率。如果你失業了,你可能不能得到抵押貸款。我們會驗證。我們已經完成了添加更多數據點的流程,所以把你拖入這個過程沒有多少意義。但是會有一個新的東西需要注意。在`HPI_Benchmark()`函數中,我們將`United States`列更改為`US_HPI`。當我們現在引入其他值時,這會更有意義。
對于國內生產總值,我找不到一個包含所有時間的東西。我相信你可以使用這個數據在某個地方,甚至在 Quandl 上找到一個數據集。有時你必須做一些挖掘。我也很難找到一個很好的長期月失業率。我確實找到了一個失業率水平,但我們真的不僅僅想要百分比/比例,否則我們需要把失業水平除以人口。如果我們確定失業率值得擁有,我們可以這樣做,但我們需要首先處理我們得到的東西。
將 Pandas 和 Quandl 代碼更新為 2016 年 8 月 1 日的最新版本:
```py
import quandl
import pandas as pd
import pickle
import matplotlib.pyplot as plt
from matplotlib import style
style.use('fivethirtyeight')
# Not necessary, I just do this so I do not show my API key.
api_key = open('quandlapikey.txt','r').read()
def state_list():
fiddy_states = pd.read_html('https://simple.wikipedia.org/wiki/List_of_U.S._states')
return fiddy_states[0][0][1:]
def grab_initial_state_data():
states = state_list()
main_df = pd.DataFrame()
for abbv in states:
query = "FMAC/HPI_"+str(abbv)
df = quandl.get(query, authtoken=api_key)
df.rename(columns={'Value': abbv}, inplace=True)
df[abbv] = (df[abbv]-df[abbv][0]) / df[abbv][0] * 100.0
print(df.head())
if main_df.empty:
main_df = df
else:
main_df = main_df.join(df)
pickle_out = open('fiddy_states3.pickle','wb')
pickle.dump(main_df, pickle_out)
pickle_out.close()
def HPI_Benchmark():
df = quandl.get("FMAC/HPI_USA", authtoken=api_key)
df["United States"] = (df["Value"]-df["Value"][0]) / df["Value"][0] * 100.0
df.rename(columns={'United States':'US_HPI'}, inplace=True)
return df
def mortgage_30y():
df = quandl.get("FMAC/MORTG", trim_start="1975-01-01", authtoken=api_key)
df["Value"] = (df["Value"]-df["Value"][0]) / df["Value"][0] * 100.0
df=df.resample('1D').mean()
df=df.resample('M').mean()
return df
def sp500_data():
df = quandl.get("YAHOO/INDEX_GSPC", trim_start="1975-01-01", authtoken=api_key)
df["Adjusted Close"] = (df["Adjusted Close"]-df["Adjusted Close"][0]) / df["Adjusted Close"][0] * 100.0
df=df.resample('M').mean()
df.rename(columns={'Adjusted Close':'sp500'}, inplace=True)
df = df['sp500']
return df
def gdp_data():
df = quandl.get("BCB/4385", trim_start="1975-01-01", authtoken=api_key)
df["Value"] = (df["Value"]-df["Value"][0]) / df["Value"][0] * 100.0
df=df.resample('M').mean()
df.rename(columns={'Value':'GDP'}, inplace=True)
df = df['GDP']
return df
def us_unemployment():
df = quandl.get("ECPI/JOB_G", trim_start="1975-01-01", authtoken=api_key)
df["Unemployment Rate"] = (df["Unemployment Rate"]-df["Unemployment Rate"][0]) / df["Unemployment Rate"][0] * 100.0
df=df.resample('1D').mean()
df=df.resample('M').mean()
return df
grab_initial_state_data()
HPI_data = pd.read_pickle('fiddy_states3.pickle')
m30 = mortgage_30y()
sp500 = sp500_data()
gdp = gdp_data()
HPI_Bench = HPI_Benchmark()
unemployment = us_unemployment()
m30.columns=['M30']
HPI = HPI_Bench.join([m30,sp500,gdp,unemployment])
HPI.dropna(inplace=True)
print(HPI.corr())
```
```
US_HPI M30 sp500 GDP Unemployment Rate
US_HPI 1.000000 -0.738364 0.738395 0.543507 0.033925
M30 -0.738364 1.000000 -0.625544 -0.714845 -0.395650
sp500 0.738395 -0.625544 1.000000 0.470505 -0.262561
GDP 0.543507 -0.714845 0.470505 1.000000 0.551058
Unemployment Rate 0.033925 -0.395650 -0.262561 0.551058 1.000000
```
在這里,我們看到 SP500 與`US_HPI`強相關,30 年抵押貸款利率顯然也是如此。其次,GDP 不是最可靠的。這是正值,但我更像看`> 70`的東西。最后,失業率更低。幾乎中立!我對此感到非常驚訝。有了這些信息,我想說 SP500 和 30 年抵押貸款利率可以用來預測房屋市場。這很好,因為這些數字都可以不間斷地獲得。我很驚訝地看到 SP500 與 HPI 之間的 0.738 相關性。大多數人認為股票和住房是多元化的。很多人都記得房地產危機,而且既然股市和房屋都一起下跌,可能就不會有這樣的感覺了,但是傳統的智慧依然表明人們通過持有股票和房地產來多樣化。 40 年的數據似乎并不完全一致。
向前看,我提倡考慮宏觀市場,使用美國房價指數(US_HPI),30 年抵押貸款利率(M30)和標準普爾 500 指數(SP500)。
我們將使用這些值來涵蓋本系列的最后一部分:結合其他主要數據科學庫。我們這里,我們將結合 Scikit Learn,看看我們是否能預測 HPI 的合理軌跡。這樣做只是一個開始,但是之后要求我們使用類似的策略來繼續下去,直到我們實際購買的房產的微觀層面。無論如何,我們還是億萬富翁,生活是美好的。在我們繼續之前,我們將最后一次運行這個代碼,將其保存到一個`pickle`中,這樣我們就不需要繼續運行代碼了。為了保存到`pickle`,只需把它放在腳本的末尾:
```py
HPI.to_pickle('HPI.pickle')
```
## 十五、滾動應用和預測函數
這個 Python 和 Pandas 數據分析教程將涵蓋兩個主題。首先,在機器學習的背景下,我們需要一種方法,為我們的數據創建“標簽”。其次,我們將介紹 Pandas 的映射函數和滾動應用功能。
創建標簽對監督式機器學習過程至關重要,因為它用于“教給”或訓練機器與特征相關的正確答案。
Pandas 數據幀映射函數到非常有用,可用于編寫自定義公式,將其應用于整個數據幀,特定列或創建新列。如果你回想一下,我們生成了一些新列,比如`df['Column2'] = df['Column1']*1.5`,等等。如果你想創建更多的邏輯密集操作,但是,你會希望寫一個函數。我們將展示如何實現它。
由于映射函數是兩種方法之一,用戶可以極大地定制 Pandas 可以做的事情,我們也會涵蓋第二種主要方式,即使用`rolling_apply`。這使我們可以應用函數的移動窗口。我們剛剛寫了一個移動平均函數,但是你可以做任何你想要的。
首先,我們有一些代碼:
```py
import Quandl
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib import style
import numpy as np
from statistics import mean
style.use('fivethirtyeight')
housing_data = pd.read_pickle('HPI.pickle')
housing_data = housing_data.pct_change()
```
首先,我們要加載數據集,然后將所有列轉換為百分比變化。 這將幫助我們規范所有的數據。
下面:
```py
housing_data.replace([np.inf, -np.inf], np.nan, inplace=True)
housing_data['US_HPI_future'] = housing_data['United States'].shift(-1)
```
在這里,我們先用`nan`值代替無窮值。 接下來,我們創建一個新的列,其中包含未來的 HPI。 我們可以用一個新的方法來實現:`.shift()`。 這種方法將會改變有問題的列。 移動`-1`意味著我們正在向下移動,所以下一個點的值會移動回來。 這是我們的方法,用于快速獲得當前值,以及下一時期同一行上的值,用于比較。
接下來,在百分比變化應用和移動中,我們有一些`NaN`數據,所以我們需要做以下工作:
```py
new_column = list(map( function_to_map, parameter1, parameter2, ... ))
```
這就是它的一切,你可以繼續添加更多的參數。
```py
print(housing_data.head())
```
```
AL AK AZ AR CA CO \
Date
1990-03-31 0.003628 0.062548 -0.003033 0.005570 0.007152 0.000963
1990-04-30 0.006277 0.095081 -0.002126 0.005257 0.005569 -0.000318
1990-05-31 0.007421 0.112105 0.001513 0.005635 0.002409 0.004512
1990-06-30 0.004930 0.100642 0.004353 0.006238 0.003569 0.007884
1990-07-31 0.000436 0.067064 0.003322 0.006173 0.004351 0.004374
CT DE FL GA ... WV WI \
Date ...
1990-03-31 -0.009234 0.002786 -0.001259 -0.007290 ... 0.013441 0.015638
1990-04-30 -0.010818 0.000074 0.002675 -0.002477 ... 0.015765 0.015926
1990-05-31 -0.010963 -0.000692 0.004656 0.002808 ... 0.017085 0.012106
1990-06-30 -0.007302 -0.001542 0.003710 0.002857 ... 0.016638 0.010545
1990-07-31 -0.003439 -0.004680 0.003116 0.002276 ... 0.011129 0.009425
WY United States M30 Unemployment Rate GDP \
Date
1990-03-31 0.009831 0.004019 0.090909 0.035714 -0.234375
1990-04-30 0.016868 0.004957 0.119048 -0.068966 4.265306
1990-05-31 0.026130 0.005260 0.117021 0.000000 -1.092539
1990-06-30 0.029359 0.005118 -0.304762 0.074074 3.115183
1990-07-31 0.023640 0.003516 -0.164384 -0.103448 0.441476
sp500 US_HPI_future label
Date
1990-03-31 0.030790 0.004957 1
1990-04-30 -0.001070 0.005260 1
1990-05-31 0.045054 0.005118 0
1990-06-30 0.036200 0.003516 0
1990-07-31 -0.001226 0.000395 0
[5 rows x 57 columns]
```
接下來,讓我們展示一個自定義方式,來應用移動窗口函數。 我們僅僅執行一個簡單的移動平均示例:
```py
def moving_average(values):
ma = mean(values)
return ma
```
這就是我們的功能,請注意,我們只是傳遞了`values`參數。 我們不需要編寫任何類型的“窗口”或“時間框架”處理,Pandas 將為我們處理。
現在,你可以使用`rolling_apply`:
```py
housing_data['ma_apply_example'] = pd.rolling_apply(housing_data['M30'], 10, moving_average)
print(housing_data.tail())
```
```
AL AK AZ AR CA CO \
Date
2011-07-31 -0.003545 -0.004337 0.002217 0.003215 -0.005579 0.004794
2011-08-31 -0.006886 -0.007139 0.004283 0.000275 -0.007782 0.001058
2011-09-30 -0.011103 -0.007609 0.003190 0.000505 -0.006537 -0.004569
2011-10-31 -0.013189 -0.007754 0.000541 0.001059 -0.005390 -0.009231
2011-11-30 -0.008055 -0.006551 0.005119 -0.000856 -0.003570 -0.010812
CT DE FL GA ... \
Date ...
2011-07-31 -0.002806 -0.001084 -0.001531 -0.003036 ...
2011-08-31 -0.010243 -0.002133 0.001438 -0.006488 ...
2011-09-30 -0.012240 -0.004171 0.002307 -0.013116 ...
2011-10-31 -0.013075 -0.006204 -0.001566 -0.021542 ...
2011-11-30 -0.012776 -0.008252 -0.006211 -0.022371 ...
WI WY United States M30 Unemployment Rate \
Date
2011-07-31 -0.002068 0.001897 -0.000756 -0.008130 0.000000
2011-08-31 -0.006729 -0.002080 -0.005243 0.057377 0.000000
2011-09-30 -0.011075 -0.006769 -0.007180 0.031008 -0.100000
2011-10-31 -0.015025 -0.008818 -0.008293 0.007519 -0.111111
2011-11-30 -0.014445 -0.006293 -0.008541 0.014925 -0.250000
GDP sp500 US_HPI_future label ma_apply_example
Date
2011-07-31 0.024865 0.031137 -0.005243 0 -0.003390
2011-08-31 0.022862 -0.111461 -0.007180 0 -0.000015
2011-09-30 -0.039361 -0.010247 -0.008293 0 0.004432
2011-10-31 0.018059 0.030206 -0.008541 0 0.013176
2011-11-30 0.000562 0.016886 -0.009340 0 0.015728
[5 rows x 58 columns]
```
## 十六、Scikit Learn 交互
在這個 Pandas 和 Python 數據分析系列教程中,我們將展示如何快速將 Pandas 數據集轉換為數據幀,并將其轉換為 numpy 數組,然后可以傳給各種其他 Python 數據分析模塊。 我們要在這里使用的例子是 Scikit-Learn,也就是 SKlearn。 為了這樣做,你需要安裝它:
```py
pip install sklearn
```
從這里開始,我們幾乎已經完成了。 對于機器學習來說,至少在監督的形式下,我們只需要幾件事情。 首先,我們需要“特征”。 在我們的例子中,特征是像當前的 HPI,也許是 GDP 等等。 之后你需要“標簽”。 標簽被分配到特征“集”,其中對于任何給定的“標簽”,特征集是任何 GDP,HPI 等等的集合。 這里,我們的標簽是 1 或 0,其中 1 表示 HPI 未來增加,0 表示沒有。
可能不用說,但我會提醒你:你不應該將“未來的 HPI”列包括為一個特征。 如果你這樣做,機器學習算法將認識到這一點,并且準確性非常高,在現實世界中不可能實際有用。
前面教程的代碼是這樣的:
```py
import Quandl
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib import style
import numpy as np
from statistics import mean
style.use('fivethirtyeight')
# Not necessary, I just do this so I do not show my API key.
api_key = open('quandlapikey.txt','r').read()
def create_labels(cur_hpi, fut_hpi):
if fut_hpi > cur_hpi:
return 1
else:
return 0
def moving_average(values):
return mean(values)
housing_data = pd.read_pickle('HPI.pickle')
housing_data = housing_data.pct_change()
housing_data.replace([np.inf, -np.inf], np.nan, inplace=True)
housing_data['US_HPI_future'] = housing_data['United States'].shift(-1)
housing_data.dropna(inplace=True)
#print(housing_data[['US_HPI_future','United States']].head())
housing_data['label'] = list(map(create_labels,housing_data['United States'], housing_data['US_HPI_future']))
#print(housing_data.head())
housing_data['ma_apply_example'] = pd.rolling_apply(housing_data['M30'], 10, moving_average)
print(housing_data.tail())
```
下面,我們打算添加一些新的導入:
```py
from sklearn import svm, preprocessing, cross_validation
```
我們將使用 svm(支持向量機)庫作為我們的機器學習分類器。 預處理用來調整我們的數據集。 通常情況下,如果你的特征介于 -1 和 1 之間,則機器學習會更精確一些。 這并不意味著永遠是真的,檢查是否縮放總是一個好主意,以便萬無一失。 `cross_validation`是一個庫,我們將用來創建我們的訓練和測試集。 這只是一個很好的方法,可以自動隨機抽取數據,用于訓練和測試。
現在,我們可以創建我們的特征和標簽來進行訓練/測試:
```py
X = np.array(housing_data.drop(['label','US_HPI_future'], 1))
X = preprocessing.scale(X)
```
一般來說,對于特征和標簽,你有了`X`,`y`。 大寫字母`X`用來表示一個特征集。 `y`是標簽。 我們在這里所做的是,將特征集定義為`housing_data `數據幀內容的 numpy 數組(這只是將數據幀的內容轉換為多維數組),同時刪除了`label`和`US_HPI_future`列。
```py
y = np.array(housing_data['label'])
```
現在我們的標簽已經定義好了,我們已經準備好,將我們的數據分解成訓練和測試集。 我們可以自己做,但是我們將使用之前的`cross_validation`導入:
> 注:
> `cross_validation`會打亂數據,最好不要在時序數據上使用這個方法,反之應該以一個位置分割數據。
```py
X_train, X_test, y_train, y_test = cross_validation.train_test_split(X, y, test_size=0.2)
```
它所做的就是將你的特征(`X`)和標簽(`y`)隨機分解為訓練和測試集。 正如你所看到的,返回值是訓練集特征,測試集特征,訓練集標簽和測試集標簽。 然后,我們將這些解構到`X_train`,`X_test`,`y_train`,`y_test`中。 `cross_validation.train_test_split`接受你的特征和標簽作為參數,然后你也可以指定測試集的大小(`test_size`),我們已經指定為 0.2,意思是 20%。
現在,我們可以建立我們打算使用的分類器:
```py
clf = svm.SVC(kernel='linear')
```
在這個例子中,我們將使用線性核的支持向量分類器。 在這里更多了解`sklearn.svm.SVC`。
接下來,我們要訓練我們的分類器:
```py
clf.fit(X_train, y_train)
```
最后,我們從這里可以繼續并進行預測,但是讓我們來測試分類器在已知數據上的準確性:
```py
print(clf.score(X_test, y_test))
```
```
0.792452830189
```
我的平均準確度約為 70%。 你可能會得到不同的結果。 有許多地方用于機器學習調參。 我們可以改變一些默認參數,我們可以查看一些其他算法,但是現在這樣做還不錯。