2018-06-15 開胃學習Data系列 - Pandas 基礎1

  • 2012 年 Wes McKinney 一本經典的 Python for Data Analysis 由 O'Reilly 出版的。Pandas 參考書 現在有一點過時了 ,他最近宣布新版的新書即將出版 我還是覺得這是一本 瞭解 Pandas 如何作用的必備書 我也欣賞一本更簡要的書

  • Learning the Pandas Library 由 Matt Harrison 著作 這不是一本有關資料分析及統計的綜合書籍 但如果您只是要學習基本的 Pandas 想要很快的上手

  • Marco Rodriguez 跟 Tim Golden 維護了一個 很棒的部落格稱為 Planet Python 您可以到 planetpython.org 這個網站, 訂閱 RSS 或者從 推特(Twitter) 的 @PlanetPython 得到最新的文章 里面有很多 Python 資料科學的貢獻者 我也強烈建議您訂閱 RSS

  • Kyle Polich 運作一個稱為 Data Skeptic 的 podcast 它并不是專門講 Python 但它的制作精良 有很棒的跟這個領域專家座談 以及 簡短的教育課程 大部分的字眼是 有關于機器學習方法 但如果您計畫 進一步探索這個學程 這個課程也在其中, 我真的很建議您訂閱這個 podcast













The Series Data Structure


  • 傳遞一個 list 的值來新創一個 Series, 當這麼做時, Pandas 會自動從零開始分配索引 并將該series的名稱設置為“None”。

  • 傳入一些資料 索引和名稱 資料可以是任何東西,類似陣列(array),像list一樣。

  • pandas自動的識別了類型 在list中包含的數據,在這裡我們傳入string列表, pandas將這類型設定為object。

In [1]:
import pandas as pd
import numpy  as np
In [2]:
animals = ['Tiger', 'Bear', 'Moose','Bear']
pd.Series(animals)

Out[2]:      
0    Tiger
1     Bear
2    Moose
3     Bear
dtype: object
In [3]:
numbers = [1, 2, 3]
pd.Series(numbers)


Out[3]:
0    1
1    2
2    3
dtype: int64
  • 不一定要使用strings。 如果傳入整數列表, 可以看見Pandas設定類型為int64。 在Pandas內部儲存series的值,使用NumPy程式庫的類型陣列(typed array)。 在處理數據時這提供顯著的加速相比于傳統 Python的list

  • NumPy 和 Pandas 如何處理遺失的資料: 在Python中,有none type以表示資料缺失。

In [4]:
animals = ['Tiger', 'Bear', None]
pd.Series(animals)


Out[4]:
0    Tiger
1     Bear
2     None
dtype: object
In [5]:
numbers = [1, 2, None]
pd.Series(numbers)


Out[5]:
0    1.0
1    2.0
2    NaN
dtype: float64



  • 事實上不能對Nan本身的做相等測試。 因為答案總是錯誤的。
  • 需要使用特殊功能來測試 '不是一個數字'的存在,例如numpy程式庫中的isnan。
In [6]:
np.nan == None

Out[6]:
False
In [7]:
np.nan == np.nan

Out[7]:
False
In [8]:
np.isnan(np.nan)

Out[8]:
True
In [9]:
sports = {'Archery': 'Bhutan',
         'Golf': 'Scotland',
         'Sumo': 'Japan',
         'Taekwondo': 'South Korea'}
s = pd.Series(sports)
s


Out[9]:
Archery           Bhutan
Golf            Scotland
Sumo               Japan
Taekwondo    South Korea
dtype: object

In [10]:
s.index

Out[10]:
Index(['Archery', 'Golf', 'Sumo', 'Taekwondo'], dtype='object')

In [11]:
s = pd.Series(['Tiger', 'Bear', 'Moose'], index=['India', 'America', 'Canada'])
s


Out[11]:
India      Tiger
America     Bear
Canada     Moose
dtype: object
In [12]:
sports = {'Archery': 'Bhutan',
         'Golf': 'Scotland',
         'Sumo': 'Japan',
         'Taekwondo': 'South Korea'}
s = pd.Series(sports, index=['Golf', 'Sumo', 'Hockey'])
s


Out[12]:
Golf      Scotland
Sumo         Japan
Hockey         NaN
dtype: objec
  • series創建完成后, 可以使用index屬性獲取index對象。
  • 也可以將index的創建與數據分離,通過 將index作為列表,明確地傳遞給series。

那麼如果index中的值列表 與dictionary中用于創建該系列的keys不對齊

  • pandas會覆蓋自動創建index值,僅只用 你提供的所有的index值。
  • 會忽略你的dictionary中所有的keys,當keys不在你的index中,pandas將添加non類型或NaN













Querying a Series


  • Pandas的Series(列表)可以查詢,使用索引(index)的位置或索引的標簽(label)。

  • 要利用數位位置查詢,從零開始,使用 iloc 屬性。

  • 要通過索引標簽(label)進行查詢,可以使用 loc 屬性。

  • 以下是維基百科的全國體育賽事數據。假設我們想要列出所有的運動當我們的索引(index),和 國家列表作為值(value)。

sports = {'Archery': 'Bhutan',
          'Golf': 'Scotland',
          'Sumo': 'Japan',
          'Taekwondo': 'South Korea'}
s = pd.Series(sports)
s

>>>
Archery           Bhutan
Golf            Scotland
Sumo               Japan
Taekwondo    South Korea
dtype: object


s.iloc[3]
>>> 'South Korea'

s.loc['Golf']
>>> 'Scotland'

s[3]
>>> 'South Korea'

s['Golf']
>>> 'Scotland'

  • 請記住,iloc和loc不是方法(method),是屬性(attribute)。所以不用括號()來查詢它們,而是使用方括號[], 我們稱之為索引運算符。在Python中, 這是獲取(get)和設置(set)一個項目的方法,根據其使用的背景來決定。
  • 這看起來可能有點困惑的,如果你習慣于語言在哪里封裝在里面的 屬性、變數和性能是常見的,比如在JAVA中。 Pandas試圖使我們的程式更具有可讀性,并提供一種 智慧語法,使用index操作符直接在series本身。

  • 最后兩行指令:例如,如果你傳入一個整數參數, 運算子會表現得好像你想要通過iloc屬性來查詢。如果你傳入一個物件(object), 它將認為你想要查詢使用根據標簽(label)的loc屬性。

  • 那么如果你的index是整數列表會發生什么呢?這有點復雜,pandas無法自動確定 你是打算通過索引位置或索引標簽進行查詢。所以在series本身使用index操作時,你需要小心。而更安全的選擇是更加明確,直接使用 iloc或loc屬性。
sports = {99: 'Bhutan',
          100: 'Scotland',
          101: 'Japan',
          102: 'South Korea'}
s = pd.Series(sports)


s[0] 
#This won't call s.iloc[0] as one might expect, it generates an error instead
  • 一個典型的程式設計方法,要遍歷 該series中的所有項目,并調用一個你感興趣的運算: 例如,我們可以創建一個浮點值的數據組(dataframe)。讓我們把這些看作是不同產品的價格。我們可以寫一個小的例行程序碼,遍歷的所有 series中的項目,并將它們加一起以獲得總數。

  • Pandas和基礎的NumPy程式庫支持一個稱為 向量化 vectorization.

  • Vectorization與NumPy庫中的大部分功能一起使用, 包括sum函數。

  • 調用np.sum 并傳入一個可遍歷迭代的項目。在這里,我們的pandas series。

s = pd.Series([100.00, 120.00, 101.00, 3.00])
s

>>>
0    100.0
1    120.0
2    101.0
3      3.0
dtype: float64

total = 0
for item in s:
    total+=item
print(total)
>>> 324.0

total = np.sum(s)
print(total)
>>> 324.0

現在這兩種方法產生相同的值,但是哪一種是確實更快嗎?
首先,設置一個大系列的隨機(random)數字。

  • 神奇功能以百分比符號%開頭。如果我們打入這個標志%,然后按Tab鍵, 我們可以看到可用的魔術函數的列表。你也可以編寫自己的魔術函數 但這不過是本課程的范圍之外。我們實際上會

  • 使用所謂的細胞(cellular)魔術函數 -- 以兩個百分比的符號開始, 并修改或包裝當前Jupyter單元中的程式。

** 要使用的函數稱為timeit。你可能已經從名稱猜到了,此函數會運行我們的程式幾次來確定,平均運行時間。


#this creates a big series of random numbers
s = pd.Series(np.random.randint(0,1000,10000))
s.head()


%%timeit -n 100
summary = 0
for item in s:
    summary+=item
>>> 100 loops, best of 3: 1.87 ms per loop

%%timeit -n 100
summary = np.sum(s)
>>>100 loops, best of 3: 107 μs per loop
  • 在pandas和NumPy的相關的功能稱為廣播(broadcasting)。通過broadcasting,你可以對series中的每個值應用操作, 更改series。
  • 例如,如果我們想要對每個隨機變數增加2, 我們可以使用+=運算符號直接在列表對像上快速地執行。在這里,我只需要使用head運算印出前五項 首先,我想要先來介紹這門課的四位講師
  • 做這的樣程序方式是,遍歷所有的 列表中的項目和直接增加它的數值。很快的提一下, Pandas確實支持遍歷迭代列表項目,很類似于dictionary, 讓你容易地把數值分拆開。但如果你發現自己反覆遍歷一列表, 你應該質疑你做的方式是否是盡可能最好的。
%%timeit -n 10
s = pd.Series(np.random.randint(0,1000,10000))
for label, value in s.iteritems():
    s.loc[label]= value+2
>>>
10 loops, best of 3: 1.65 s per loop

%%timeit -n 10
s = pd.Series(np.random.randint(0,1000,10000))
s+=2
>>>?
10 loops, best of 3: 514 μs per loop
  • 最后一點要注意的,在使用索引運算來存取列表資料。 .loc屬性(attribute) 不僅可以修改數據, 還可以添加新數據。如果作為索引傳入的值不存在,則它會添加一個新條目。請記住,指數可以有混合類型。雖然重要的是,要注意在下面的類型是什么, Pandas會根據需要,自動更改基本的NumPy類型。
s = pd.Series([1, 2, 3])
s.loc['Animal'] = 'Bears'
s
>>>
0             1
1             2
2             3
Animal    Bears
dtype: object
original_sports = pd.Series({'Archery': 'Bhutan',
                             'Golf': 'Scotland',
                             'Sumo': 'Japan',
                             'Taekwondo': 'South Korea'})
cricket_loving_countries = pd.Series(['Australia',
                                      'Barbados',
                                      'Pakistan',
                                      'England'], 
                                   index=['Cricket',
                                          'Cricket',
                                          'Cricket',
                                          'Cricket'])
all_countries = original_sports.append(cricket_loving_countries)

original_sports
Archery           Bhutan
Golf            Scotland
Sumo               Japan
Taekwondo    South Korea
dtype: object

cricket_loving_countries
Cricket    Australia
Cricket     Barbados
Cricket     Pakistan
Cricket      England
dtype: object

all_countries
Archery           Bhutan
Golf            Scotland
Sumo               Japan
Taekwondo    South Korea
Cricket        Australia
Cricket         Barbados
Cricket         Pakistan
Cricket          England
dtype: object

all_countries.loc['Cricket']
Cricket    Australia
Cricket     Barbados
Cricket     Pakistan
Cricket      England
dtype: object
  • 我們回到我們原來的運動列表。可以創建一個帶有多個條目的新列表,用 板球索引,然后使用append將它們放在一起。使用append時,有幾個重要的注意事項。首先,Pandas將采取你的列表, 并嘗試推斷使用最好的數據類型。在這個例子中,一切都是字符(string),所以這里沒有問題。
  • 其次,append方法實際上并沒有改變底層的列表。而是返回一個由兩個附加在一起組成的新列表。我們可以回溯并列印原始列表值, 看到它們沒有改變。
  • 這是實際上的一個重大問題 新的Pandas使用者,之前習慣了物件(objects)在原處更改。所以要當心了,不只是append,還有其他的Pandas函數功能。

  • 最后,我們看到,當我們查詢附加在一起的列表,用板球 作為國家運動的,我們不是得到一個單一的值,而是一個列表。這實際上是很常見的。













The DataFrame Data Structure


  • DataFrame數據結構是Pandas的核心。

  • DataFrame在概念上是一個二維列表(series)對象, 其中有一個索引(index)和多列內容,每列(column)都有一個標簽(label)。事實上,列(column)和行(row)之間的區別 實際上只是一個概念上的區別。可以將DataFrame本身視為簡單的雙軸有標簽的陣列。

  • 可以以許多不同的方式創建一個DataFrame。例如,你可以使用一組列表(series), 其中每個列表代表一行數據。或者你可以使用一組字典(dictionary), 其中每個字典都代表一行數據。
purchase_1 = pd.Series({'Name': 'Chris',
                        'Item Purchased': 'Dog Food',
                        'Cost': 22.50})
purchase_2 = pd.Series({'Name': 'Kevyn',
                        'Item Purchased': 'Kitty Litter',
                        'Cost': 2.50})
purchase_3 = pd.Series({'Name': 'Vinod',
                        'Item Purchased': 'Bird Seed',
                        'Cost': 5.00})
df = pd.DataFrame([purchase_1, purchase_2, purchase_3], index=['Store 1', 'Store 1', 'Store 2'])
df.head()

>>>
Cost        Item Purchased  Name
Store 1     22.5    Dog Food    Chris
Store 1    2.5  Kitty Litter    Kevyn
Store 2     5.0 Bird Seed   Vinod
  • 與列表(series)類似,可以使用iloc和loc屬性提取數據。因為DataFrame是二維的,所以將單一值傳遞給loc 索引操作將返回一個列表,如果只有一行返回。
df.loc['Store 2']
>>>
Cost                      5
Item Purchased    Bird Seed
Name                  Vinod
Name: Store 2, dtype: object
  • 列表的名稱作為行索引值返回, 而列名(column_name)也包括在輸出中。
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。