即學即用:Pandas入門與時間序列分析
這篇文章是Alexander Hendorf 在PyData Florence 2017上做的報告。報告前半部分主要為初學者介紹Pandas的基本功能,如數據輸入/輸出、可視化、聚合與選擇與訪問,後半部分主要介紹如何使用Pandas進行時間序列分析,源代碼親測可用。
PS:PyData集數據分析工具的用戶和開發者,大家交流經驗、相互學習,為各領域的數據科學愛好者提供一個經驗共享平台,一起討論如何使用語言和工具應對來自數據管理、處理、分析和可視化各方麵的挑戰。
【Pandas起源與目標】
1. 開源Python庫
2. 實際數據分析-高速/高效/簡單
4. Wes McKinney 2008年開始編寫, 再到現在Continuum Analytics的Anaconda
5. 定期更新的穩定項目
6. 地址:https://github.com/pandas-dev/pandas
【特征】
4.數據可視化
6.類似數據庫操作
:https://github.com/Koenigsweg/data-timeseries-analysis-with-pandas
1. DataSeries & DataFrame
2. I/O(輸入/輸出)
3.Data analysis &aggregation(數據分析&聚合)
4.Indexes(索引)
5. Visualization(可視化)
6.Interacting with the Data(數據交互)
【輸入/輸出】
1. import pandas as pd
2. # 讀取數據
3. df = pd.read_csv('raw_weather_data_aug_sep_2014/tempm.csv', header=None)
4. print df.head(5) #輸出前n行
5. print df.tail(5) #輸出最後n行

1. 使用Matplotlib庫,.plot() 函數
【數據結構:Series和DataFrame】
【Series篇】
1. 一維有標簽數組結構,可以存入任一種python的數據類型(integers, strings, floating point numbers, Python objects, etc.)
2. 序列的標簽通常稱為索引(index)
數據選擇與訪問方式:
1. 可以通過標簽(index)選擇,也可以通過位置來選擇(從0開始);
2. 通過切片/布爾索引訪問數據,例如:
1. series[x], series[[x, y]]
2. series[2], series[[2, 3]], series[2:3]
3. series.ix() / .iloc() / .loc()
4. # .ix()這種方式相當於混合了loc()和iloc()兩種方式

【DataFrame】
二維有標簽數據結構,如2維Numpy數組,關於索引,有如下規定:
2.索引可以重置或者替換;
3. 類型:位置,時間戳,時間範圍,標簽…;
4.一個索引號可能會出現多次(不唯一)
例1. 給列命名
1. df.columns = ['timestamp', 'temperature']
2. df.head(3)
例2. 對數據進行運算:
1. def to_fahrenheit(celsius):
2. return (celsius * 9./5.) + 32.
3. df['temperature'].map(to_fahrenheit)[:5]
4. df['temperature F'] = df['temperature'].map(to_fahrenheit)
5. df.head(5)
6. df['temperature F'] = df['temperature'].apply(lambda x: (x * 9./5.) + 32.)
7. df.head()

timestamp |
temperature |
temperature F |
|
0 |
2014-09-26T03:50:00 |
14.0 |
57.2 |
1 |
2014-08-10T05:00:00 |
14.0 |
57.2 |
2 |
2014-08-21T22:50:00 |
12.0 |
53.6 |
3 |
2014-08-17T13:20:00 |
16.0 |
60.8 |
4 |
2014-08-06T01:20:00 |
14.0 |
57.2 |
例3. 兩列之間也可以直接進行運算,如
1. df['ruleoftumb'] = df['temperature F'] / df['temperature']
2. df.head()
timestamp |
temperature |
temperature F |
ruleoftumb |
|
0 |
2014-09-26T03:50:00 |
14.0 |
57.2 |
4.085714 |
1 |
2014-08-10T05:00:00 |
14.0 |
57.2 |
4.085714 |
2 |
2014-08-21T22:50:00 |
12.0 |
53.6 |
4.466667 |
3 |
2014-08-17T13:20:00 |
16.0 |
60.8 |
3.800000 |
4 |
2014-08-06T01:20:00 |
14.0 |
57.2 |
4.085714 |
【修改Series和DataFrame】
Series和DataFrame的方法實際上並沒有修改原始的Series和DataFrame,而是返回一個新的Series或DataFrame,可以使用inplace參數來決定是否要用新結果替換掉原來的數據。
1. # 對列名進行重命名,rename()函數返回一個新DataFrame,
2. # inplace參數表示是否替換原來的DataFrame
3. df.rename(columns={'ruleoftumb': 'bad_rule'}, inplace=True)
4. df.head()
timestamp |
temperature |
temperature F |
bad_rule |
|
0 |
2014-09-26T03:50:00 |
14.0 |
57.2 |
4.085714 |
1 |
2014-08-10T05:00:00 |
14.0 |
57.2 |
4.085714 |
2 |
2014-08-21T22:50:00 |
12.0 |
53.6 |
4.466667 |
3 |
2014-08-17T13:20:00 |
16.0 |
60.8 |
3.800000 |
4 |
2014-08-06T01:20:00 |
14.0 |
57.2 |
4.085714 |
5. # 刪除列,inplace參數同上
6. df.drop('bad_rule', axis=1, inplace=True)
7. df.head()
timestamp |
temperature |
temperature F |
|
0 |
2014-09-26T03:50:00 |
14.0 |
57.2 |
1 |
2014-08-10T05:00:00 |
14.0 |
57.2 |
2 |
2014-08-21T22:50:00 |
12.0 |
53.6 |
3 |
2014-08-17T13:20:00 |
16.0 |
60.8 |
4 |
2014-08-06T01:20:00 |
14.0 |
57.2 |
1. describe()
4. mean(), sum(), median(),…
例1. 創建新列:
1. # .mean()函數計算指定數據的均值
2. df['deviation'] = df['temperature'] - df['temperature'].mean()
3. df.head()
timestamp |
temperature |
temperature F |
deviation |
|
0 |
2014-09-26T03:50:00 |
14.0 |
57.2 |
-1.590951 |
1 |
2014-08-10T05:00:00 |
14.0 |
57.2 |
-1.590951 |
2 |
2014-08-21T22:50:00 |
12.0 |
53.6 |
-3.590951 |
3 |
2014-08-17T13:20:00 |
16.0 |
60.8 |
0.409049 |
4 |
2014-08-06T01:20:00 |
14.0 |
57.2 |
-1.590951 |
例2. 用groupby()分組
1. #按溫度分組,統計每個溫度出現的次數
2. df.groupby('temperature').count()
例3. 輸出指定數據統計信息
1. # describe()方法返回數據的統計信息,不考慮空值
2. df['temperature'].describe(percentiles=[.1,.5,.6,.7])
NaN表示空值,可以使用drop( )移除;也可以用默認值替換或者前向填充/後向填充
例1. 使用Isnull( )函數判斷是否為空
1. df['temperature'].isnull()[2350:2357]
例2. 刪除缺失值:
1. df.dropna(inplace=True)
2. print df['temperature'].isnull().any()
輸出: False ,因為已經刪除缺失值,並且用刪除之後的數據替換掉原數據,所以判斷是否存在空值時,返回False,即不存在空數據。
Part2 時間序列分析(以時間戳為index的序列)
在進行時間序列分析時,先將DataFrame的索引值由默認的數字索引變為時間戳索引:
1. #新增一列deviation,然後將默認的索引值變為時間戳索引值
2. df['deviation']=df['temperature']-df['temperature'].mean()
3. df.index=pd.to_datetime(df['timestamp'])
4. df.head()
畫出DataFrame前100行,此時圖的橫坐標不再是數值索引,而是時間戳。如下:
1. ax=df[:100].plot()
2. ax.axhline(df[:100]['temperature'].median(),color='r',linestyle='-')
3. plt.show()

此時,對DataFrame加入weekday列和weekend列,
1. # DatetimeIndex.weekday 將返回該日期是一星期中的第幾天,星期一是0,星期天是6
2. df['weekday'] = df.index.weekday
3. # isin()返回布爾值,表示df['weekday']是否在{5,6}中,
4. # 即判斷是否是周末
5. df['weekend'] = df['weekday'].isin({5, 6})
6. # 根據日期來分組,進行統計
7. df.groupby(df.index.date).count()
那麼就可以進一步分析溫度隨著時間的變化趨勢,比如觀察每周氣溫的變化情況:
1. # 以周為時間單位進行聚合,分析氣溫的變化情況
2. # 前麵已經將時間序列作為索引值,那麼這裏df.index.week返回的是一年的第幾周
3. df.groupby(df.index.week).plot()

也可以分析指定時間內的溫度變化趨勢
1. # 2014年9月氣溫變化圖(左圖) 2. df['2014-09']['temperature'].plot() 3. # 12點到16點之間的氣溫變化圖(右圖) 4. df[(df.index.hour > 12) & (df.index.hour <=16)]['temperature'].plot()

時間序列重采樣(resample)
重采樣是對原樣本重新處理的一個方法,是一個對常規時間序列數據重新采樣和頻率轉換的便捷的方法,分為降采樣和升采樣,將高頻率數據聚合到低頻率數據稱為降采樣(downsampling),將低頻率轉換到高頻率稱為升采樣(upsampling)。

首先用DataFrame進行重采樣:
1. # 按3天為時間間隔采樣
2. df.resample('3D').plot()

又如對Series進行降采樣:
1. import random
2. index = pd.date_range('1/1/2016', periods=1200, freq='S')
3. series = pd.Series([random.randint(0,100) for p in range(1200)], index=index)
4. # label參數表示采用區間左邊的時間戳還是右邊的時間戳,
5. # closed參數表示區間是左邊閉合還是右邊閉合,和數學中[ ),( ]區間表示形式一樣
6. # 一個時間戳隻能屬於一個時間段,所有時間段合並起來必須能組成原始的整個時間幀
7. # 降采樣,從之前的1秒變為5分鍾
8. resampled = series.resample('5T', label='right', closed='right')
9. print resampled
10. print series.resample('5T', label='left', closed='right')
11. print series.resample('5T', label='left', closed='left')
升采樣,采樣頻率從5分鍾變到100秒,
1. # 升采樣默認會引入缺失值
2. print resampled.resample('100S')[:6]
3. # ffill()向前填充,即用上一個有效值填充缺失數據
4. # bfill()向後填充,即用下一個有效值填充缺失數據
5. print resampled.resample('100S').ffill()[:6]
6. print resampled.resample('100S').bfill()[:6]

使用statsmodels庫進一步分析時序數據

1. dtap=pd.DataFrame(mdf.groupby(mdf.index)['activity'].sum())
2. # 對缺失數據插值
3. dtap.activity.interpolate(inplace=True)
4. res=sm.tsa.seasonal_decompose(dtap.activity)
5. resplot=res.plot()
6. resplot.set_size_inches(15,15)
輸出:
以上為譯文
文章原標題《Introduction to Pandas and Time Series Analysis》,作者:Alexander C. S. Hendorf,譯者:李烽 審校:
文章為簡譯,更為詳細的內容,請查看原文。
PS:中文譯製PDF版食用更佳,可讀性更強,見附件。
最後更新:2017-05-15 13:01:26