第94天:數據分析之 pandas 初步

by 軒轅御龍

數據分析之 pandas 初步

pandas是一個常用的第三方 Python 庫,提供快速靈活的數據處理功能,也是進行數據分析的有力工具。我們的口號是:“更快,更高,更強”(皮一下)。啊,當然,現在經常有很多庫一上來就要“吊打”pandas,咱們還是不必在意。

pandas尤其擅長處理以下數據:

以下幾種數據尤其適合用pandas進行處理:

  • 多種數據混合的扁平化數據格式,比如 SQL 表和 Excel 電子表格;
  • 時間序列數據,不管有序無序;
  • 任意帶有行列標籤的矩陣數據,不管是同種數據類型還是多種數據類型;
  • 還有其他任意的統計數據集,不必帶標籤。

在本文開頭要提醒的是,pandas指的不是英語中的“panda”,熊貓。實際上pandas是術語“panel data”(面板數據)的簡寫,大家要注意:這不是國寶模塊哈哈,不要看到這個模塊就想起憨憨的大熊貓啦~

1. pandas 安裝

有了之前文章的鋪墊,其實安裝這個步驟大家應該已經很熟悉了,但是在這裏依然要再敘述一遍。已經安裝好的同學跳過就好。

由於pandas並非 Python 的內置模塊,因此我們直接從 Python 官網下載安裝的發行版是不包含 pandas這個模塊的。這個時候你要是想import numpy,顯然是會無功而返的。因此我們需要額外安裝 pandas模塊。

安裝 pandas有好幾種方式,我們這裏推薦的是:1)使用pip進行安裝;2)安裝Anaconda

1.1 使用pip安裝

這種方式推薦給已經從 Python 官網下載了某個 Python 發行版的讀者,或是已經通過其它方式獲得了 Python 環境,但卻沒有 pandas這個模塊的讀者。

安裝命令:

pip install pandas

或:

python -m pip install pandas

均可。

當然,實際上 pandas模塊本身也有很多依賴,也需要其他一些模塊才能夠真正發揮出它強大的功能,因此我們推薦一次安裝多個模塊:

python -m pip install --user numpy scipy matplotlib ipython jupyter pandas sympy nose

1.2 安裝 Anaconda

這種方式適合還沒有安裝 Python 的讀者,或是已經安裝了 Python 但是想一勞永逸擁有大多數科學計算庫的讀者。

訪問 Anaconda 官網找到下載鏈接進行安裝即可。

或者如果你覺得 Anaconda 過於臃腫,也可以安裝其簡化版本 Miniconda

2. 主要數據類型

pandas中有兩個主要的數據類型,一種是 Series,稱爲“序列”,是一種一維數據結構;另一種是 DataFrame,稱爲“數據幀”或是“數據框架”,是一種二維數據結構。在pandas中,我們就是使用這兩種主要的數據結構,“喜迎四海賓朋,笑對八方來客”,分分鐘處理掉天上地下來的各種數據。

其中,Series 內部要求是同種數據,而 DataFrame 則可以使混合數據。更進一步地說, DataFrame 其實就是包含了一至多個 Series

前面我們學習了numpy模塊的基本相關知識,如果大家還有印象的話可以回憶一下。

numpy雖然提供了強大的多維數組供我們進行數據處理,但是這中間有一個要命的問題:維數比較少的時候還好,維數一旦多起來,你還分得清哪個軸代表什麼意義嗎?呃當然不排除有人可以,但是大多數人肯定是不行的,因爲numpy的每個軸之間其實沒有什麼本質上的差異,你可以是軸 1,我也可以是軸 1,誰有比誰高貴怎麼滴?因此在使用numpy進行高維數據處理,尤其是當其中每個維度都有特定的意義時,使用numpy的多維數組就會給使用者造成很大的負擔——而這些本來不應該是由使用者負擔的。

因此pandas的優勢就體現出來了。pandas可以爲每一列數據打上標籤,這樣通過標籤就可以直接區分開每個軸誰是誰,也可以通過標籤獲得更具語義性的信息,知道每列數據都是什麼、有什麼用途。即使是交換了順序也無所謂,比較在pandas中,我們可以不再以默認的序號作爲索引。

當然pandas還有可以組合多種數據類型等優勢,這些就留待大家在實踐中體會啦~

我們預先導入pandas,並且由於演示過程中會用到numpy模塊,在這裏也一併導入:

import numpy as np
import pandas as pd

2.1 Series

Series 實際上是一個帶標籤的一維數組,數組中的內容可以是任何數據類型。在 Series 中,“帶標籤的軸”統稱爲“index(索引)”,類似於我們之前學習的字典數據類型中的“key(關鍵字)”。

2.1.1 創建 Series

創建 Series 最常用的方法就是調用pd.Series

>>> s = pd.Series(data, index=index)

其中,data要求是下列數據類型之一:

  • Python 字典;
  • Python 列表;
  • N 維數組;
  • 標量(即一個數字)。

而參數index則應當是一個用來指定軸標籤的列表。

按照原始數據類型的不同,創建 Series 的方式也分爲 4 種:1)用 Python 字典創建;2)用 Python 列表創建;3)用 N 維數組創建;4)用標量創建。

  1. Python 字典
>>> d = {'b': 1, 'a': 0, 'c': 2}
>>> s = pd.Series(d)
>>> s
b    1
a    0
c    2
dtype: int64
  1. Python 列表
>>> l = [1,2,3]
>>> s = pd.Series(l)
>>> s
0    1
1    2
2    3
dtype: int64

可以看到,在只使用列表而不提供索引值時,pandas會自動爲 Series 中的數據分配默認索引作爲標籤。

  1. N 維數組
>>> ar = np.random.randn(5)
>>> ar
array([-0.12383463,  0.2312694 ,  1.82605315, -1.4743252 , -0.71267657])
>>> s = pd.Series(ar, index=['a', 'b', 'c', 'd', 'e'])
>>> s
a   -0.123835
b    0.231269
c    1.826053
d   -1.474325
e   -0.712677
dtype: float64
  1. 標量
>>> # 標量生成單元素序列
>>> s = pd.Series(5.)
>>> s
0    5.0
dtype: float64
>>> 
>>> # 標量生成多元素序列
>>> s = pd.Series(5., index=['a', 'b', 'c', 'd', 'e'])
>>> s
a    5.0
b    5.0
c    5.0
d    5.0
e    5.0
dtype: float64

2.1.2 索引 Series

既然說到 Series 類似於一維數組,也就是說 Series 也可以通過序號進行索引:

>>> s = pd.Series([5,-4,7,-8,9], index=['a','b','c','d','e'])
>>> s
a    5
b   -4
c    7
d   -8
e    9
dtype: int64
>>> s[2]
7
>>> s[1]
-4

其次,Series 還可以通過標籤進行索引:

>>> s['a']
5
>>> s['d']
-8

並且 Series 也有切片功能:

>>> s[1:3]
b   -4
c    7
dtype: int64
>>> s[:3]
a    5
b   -4
c    7
dtype: int64

甚至標籤也可以用於切片:

>>> s['a':'d']
a    5
b   -4
c    7
d   -8
dtype: int64

都是觀察可以發現,使用標籤進行索引與使用序號進行索引還是存在一點兒不同:使用序號進行索引時,切片結果不會包括結束序號對應的內容;但使用標籤進行索引就會包括末尾標籤指定的內容。

還可以從 Series 中直接選取特定的項。同樣地,也是既可以使用序號,也可以使用標籤,但要記得將指定的序號或標籤放在一個列表中:

>>> # 使用序號
>>> s[[1,2]]
b   -4
c    7
dtype: int64
>>> 
>>> # 使用標籤
>>> s[['a','d']]
a    5
d   -8
dtype: int64

此外還有根據條件進行篩選的用法,這種用法是一種pandasif-then方言:

>>> s[s > 0]
a    5
c    7
e    9
dtype: int64

這樣就提取出了s中大於 0 的部分。

還要注意,Series 的直接賦值不會創建副本,如果想要新的 Series 對象與舊的沒有關係,需要顯式地創建副本並賦值:

>>> s2 = s
>>> s2 is s
True
>>> s2 = s.copy()
>>> s2 is s
False

2.1.3 Series 的運算

類似numpy數組地,Series 的算術運算——包括應用於很多numpy中的函數——也是逐元素進行的:

>>> s + s
a    10.0
b    -8.0
c    14.0
d   -16.0
e    18.0
dtype: float64
>>> s * 2
a    10.0
b    -8.0
c    14.0
d   -16.0
e    18.0
dtype: float64
>>> np.exp(s)
a     148.413159
b       0.018316
c    1096.633158
d       0.000335
e    8103.083928
dtype: float64

而 Series 與numpy數組的不同之處在於,Series 有自動對齊的特性,也就是說,在運算中如果兩個參與運算的 Series 數據長度不一樣,pandas會自動用默認的缺省值補全缺失的部分,以使運算順利進行:

>>> s[1:] + s[:-1]
a     NaN
b    -8.0
c    14.0
d   -16.0
e     NaN
dtype: float64

簡單來講,在運算時如果遇到了“在某個運算對象中找不到對應項標籤”的情況,那麼pandas就會自作主張用缺省值NaN來代替。這就使得在進行交互式數據分析的時候有了極大的靈活性。

2.2 DataFrame

2.2.1 創建 DataFrame

DataFrame 是一種二維帶標籤的數據結構,並且允許各列直接數據類型不同。我們既可以把它當做是電子表格或是 SQL 表,也可以將其當作是一個由若干個 Series 對象組成的字典;也是pandas中最常用的數據結構。

創建 DataFrame 的方法是調用pd.DataFrame

pd.Series(data, index=index, columns=columns)

其中的data參數要求是下列數據類型之一:

  • 由一維數組、列表、字典或是 Series 構成的字典;
  • 二維 Numpy 數組;
  • 結構化數組;
  • 一個 Series;
  • 別的 DataFrame。

參數index對應於 DataFrame 中的行標籤,參數columns對應於DataFrame 中的列標籤。通過指定這兩個參數,可以有篩選使用哪些數據來生成 DataFrame。

在這裏我們僅僅介紹 3 中可能用到的方法。

  1. 使用由 Series 組成的字典由字典組成的的字典來創建 DataFrame

如果不指定columns參數的話,默認將columns設置爲字典關鍵字的有序列表。

>>> d = {'one': pd.Series([1., 2., 3.], index=['a', 'b', 'c']),
...      'two': pd.Series([1., 2., 3., 4.], index=['a', 'b', 'c', 'd'])}
>>> df = pd.DataFrame(d, index=['d', 'b', 'a'])
>>> df
   one  two
d  NaN  4.0
b  2.0  2.0
a  1.0  1.0
>>> df = pd.DataFrame(d, index=['d', 'b', 'a'], columns=['two', 'three'])
>>> df
   two three
d  4.0   NaN
b  2.0   NaN
a  1.0   NaN
>>> 
>>> # 默認形式
>>> df = pd.DataFrame(d)
>>> df
   one  two
a  1.0  1.0
b  2.0  2.0
c  3.0  3.0
d  NaN  4.0
  1. 使用 N 維數組或列表的字典
>>> d = {'one': [1., 2., 3., 4.],
...      'two': [4., 3., 2., 1.]}
>>> pd.DataFrame(d)
   one  two
0  1.0  4.0
1  2.0  3.0
2  3.0  2.0
3  4.0  1.0
>>> pd.DataFrame(d, index=['a', 'b', 'c', 'd'])
   one  two
a  1.0  4.0
b  2.0  3.0
c  3.0  2.0
d  4.0  1.0
  1. 使用字典組成的列表
>>> data2 = [{'a': 1, 'b': 2}, {'a': 5, 'b': 10, 'c': 20}]
>>> pd.DataFrame(data2)
   a   b     c
0  1   2   NaN
1  5  10  20.0
>>> pd.DataFrame(data2, index=['first', 'second'])
        a   b     c
first   1   2   NaN
second  5  10  20.0
>>> pd.DataFrame(data2, columns=['a', 'b'])
   a   b
0  1   2
1  5  10

2.2.2 索引 DataFrame

通過indexcolumns兩個屬性可以分別查看 DataFrame 的行標籤和列標籤:

>>> d = {'one': pd.Series([1., 2., 3.], index=['a', 'b', 'c']),
...       'two': pd.Series([1., 2., 3., 4.], index=['a', 'b', 'c', 'd'])}
>>> df = pd.DataFrame(d)
>>> df
   one  two
a  1.0  1.0
b  2.0  2.0
c  3.0  3.0
d  NaN  4.0
>>> df.index
Index(['a', 'b', 'c', 'd'], dtype='object')
>>> df.columns
Index(['one', 'two'], dtype='object')

可以使用列標籤來索引:

>>> df['one']
a    1.0
b    2.0
c    3.0
d    NaN
Name: one, dtype: float64

也可以直接將列標籤作爲屬性:

>>> df.one
a    1.0
b    2.0
c    3.0
d    NaN
Name: one, dtype: float64

還可以按列選取:


>>> df[['one', 'two']]
   one  two
a  1.0  1.0
b  2.0  2.0
c  3.0  3.0
d  NaN  4.0

要對 DataFrame 按行索引,則需要使用loc這個屬性:

>>> df.loc['a']
one    1.0
two    1.0
Name: a, dtype: float64

同樣地,也可以通過行標籤來按行切片、選取:

>>> df.loc['a':'c']
   one  two
a  1.0  1.0
b  2.0  2.0
c  3.0  3.0
>>> df.loc[['a','d']]
   one  two
a  1.0  1.0
d  NaN  4.0

此外,還可以使用headtail來分別獲取數據的前、後幾行,具體數目由參數指定:

>>> df.head(2)
   one  two
a  1.0  1.0
b  2.0  2.0
>>> df.tail(2)
   one  two
c  3.0  3.0
d  NaN  4.0

2.2.3 統計信息

使用describe可以計算得到一個 DataFrame 數據的相關統計信息,並且計算統計信息時會自動忽略缺省值NaN

>>> df
   one  two
a  1.0  1.0
b  2.0  2.0
c  3.0  3.0
d  NaN  4.0
>>> df.describe()
       one       two
count  3.0  4.000000
mean   2.0  2.500000
std    1.0  1.290994
min    1.0  1.000000
25%    1.5  1.750000
50%    2.0  2.500000
75%    2.5  3.250000
max    3.0  4.000000

其中count是各列的數據個數,mean是各列數據的平均值,std則對應標準差,後續的各行爲從最小值到最大值的均勻數據。

還可以使用median方法主動求出平均值:

>>> df.median() # 也適用於 Series
one    2.0
two    2.5
dtype: float64

2.3 其他

Series 和 DataFrame 都可以使用同樣的方法轉換爲numpy數組的形式:

>>> s.to_numpy()
array([ 5., -4.,  7., -8.,  9.])

此外,兩種主要數據結構還有一個叫做apply的方法,用來對實例調用指定的函數。可以指定已有的函數,也可以臨時定義一個匿名函數,後者更加常見一些:

>>> df.apply(len)
one    4
two    4
dtype: int64
>>> df.apply(lambda x: x * x)
   one   two
a  1.0   1.0
b  4.0   4.0
c  9.0   9.0
d  NaN  16.0

3. 讀取數據

實際上,大多數時候我們並不會手動創建一個 Series 或是 DataFrame,更一般的方法是通過使用pandas的讀寫接口,直接從文件中讀取需要處理的數據。

爲了演示pandas讀取數據的功能,我們提供了一個真實的數據集,其中包含加利福尼亞州住房數據。同學們可以從“代碼示例”獲取該文件;也可直接使用示例代碼中指定的 URL 進行下載。

california_housing_dataframe = pd.read_csv("/data/california_housing_train.csv", sep=",")

使用columns來看看有哪些種類的數據:

>>> california_housing_dataframe.columns
Index(['longitude', 'latitude', 'housing_median_age', 'total_rooms',
       'total_bedrooms', 'population', 'households', 'median_income',
       'median_house_value'],
      dtype='object')

pandas提供了大量函數用於文件讀寫,適用於 CSV、Excel、HDF、SQL、JSON、HTML 等文件類型,還包括一個讀取系統剪貼板的接口pd.read_clipboard()

4. pandas 畫圖

上一節我們讀取了一個真實的數據集,現在讓我們針對其中意義最豐富的屬性median_house_value(即平均房價)這一列,來畫個直方圖瞧一瞧:

>>> import matplotlib.pyplot as plt
>>> california_housing_dataframe.hist('median_house_value')
array([[<matplotlib.axes._subplots.AxesSubplot object at 0x00000222934BC8D0>]],
      dtype=object)
>>> plt.show()

加州平均房價直方圖

然後我們使用latitude作爲 x 軸,以latitude作爲 y 軸,考察一下加州房價在南北走向上的分佈:

>>> california_housing_dataframe.plot.scatter(y='median_house_value',x='latitude')
<matplotlib.axes._subplots.AxesSubplot object at 0x000002229301C7B8>
>>> plt.show()

加州房價南北分佈

從圖上我們可以看到,加州的房價在南北走向上有兩個高價帶。

再考察一下東西走向上的分佈:

>>> california_housing_dataframe.plot.scatter(y='median_house_value',x='longitude')
<matplotlib.axes._subplots.AxesSubplot object at 0x00000222939A87B8>
>>> plt.show()

加州房價東西分佈

可以看到,加州房價在東西走向上也出現了兩個高價帶。顯然加州高價房應該是集中在兩個區域,我們可以通過對應的經緯度,找到這兩個區域。

最後我們將經緯度分別作爲 x、y 軸,將平均房價作爲 z 軸畫出一個三維圖像,直觀地觀察一下:

>>> from mpl_toolkits.mplot3d import Axes3D
>>> x = california_housing_dataframe['longitude']
>>> y = california_housing_dataframe['latitude']
>>> z = california_housing_dataframe['median_house_value']
>>> fig = plt.figure()
>>> ax = Axes3D(fig)
>>> ax.scatter(x,y,z)
<mpl_toolkits.mplot3d.art3d.Path3DCollection object at 0x00000222943317B8>
>>> plt.show()

加州房價平面分佈

通過拖動 3D 圖像轉換視角,容易看出確實有兩個區域集中分佈着高價房。

5. 總結

本文初步介紹了pandas模塊中最核心的兩個數據類型:Series 和 DataFrame,以及它們的一些性質。

通過演示讀取數據和使用pandas畫圖,我們熟悉了pandas的基本操作,也感受了一下數據可視化的效果。

示例代碼:Python-100-days

參考資料

pandas 文檔

Google colab - pandas 簡介

python:利用pandas進行繪圖(總結)基礎篇

關注公衆號:python技術,回覆"python"一起學習交流

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章