灰太狼的數據世界(三)

  • 2019 年 10 月 6 日
  • 筆記

一期我們了解了Pandas裡面Series數據結構,了解了如何創建修改,清理Series,也了解了一些統計函數,例如方差,標準差,峰度這些數學概念。那麼今天我們就來了解Pandas裡面的另一個數據結構—–DataFrame。

DataFrame拆開的英文意思是數據框架。事實上它就是一個數據框架,一個類似於資料庫中表一樣的結構。

比如說我們現在有這樣一張表,那麼把這張表做成dataframe,先把每一列都提取出來,然後將這些在列的數據都放到一個大的集合里,在這裡我們使用字典。(這裡我們取姓名,年齡和收入這些欄位)


import pandas as pd  data = {'Fname': ['amy', 'john', 'tony'],          'age': [50, 55, 54],          'income': [1000000, 500000, 400000000]}  df1 = pd.DataFrame(data)  print(df1)

這個時候我們看到這些數據做成的dataframe真的就像一個表一樣,事實上它真的就是一張表。

我們把每一列數據都取出來,做成一個list(其實就是我們上期說的Series)。

如果我們想為這些數據添修改索引列(就是數據中的0,1,2),可以使用index參數指定索引。

df2 = pd.DataFrame(data, index=['A', 'B', 'C'], columns=['Fname', 'age', 'income'])  print(df2)

所以如果構造一個DataFrame,那就需要想好有哪幾個列,把列對應的數據做成一個列表放進去。就可以了。說白了就是每個列都是一個Series,DataFrame = n * Series

下面我們來看看一些基礎的稱呼:

在pandas裡面有一些基礎的屬性需要搞明白,這就和資料庫差不多。我們對照數據來理解一下。dataframe裡面有個屬性叫index,那這個就是索引對應的也是資料庫的索引,你也可以把它理解成主鍵。第二個屬性是columns,這個就是一列。對應資料庫的表也是一列。有多少個columns就有多少列了~第三個屬性是rows,rows大家可以對比成數據的記錄,有多少條記錄就有多少rows。

當然,我們創建dateframe 的時候用的數據可能不是字典,可能就像是多個Series,想直接把它拼成dataframe,這樣可以嗎?

答案是可以的。我們可以直接使用多個Series去做出一個dataframe。

import pandas as pd  import numpy as np  s1 = np.array([1, 2, 3, 4])  s2 = np.array([5, 6, 7, 8])  df = pd.DataFrame([s1, s2])  print(df)

這就是我們上節課講的,Series有默認索引,從零開始,那這個dataframe也就會和Series一樣,如果不給他指定值(列名或索引),他就會從零開始計數。

我們工作中除了手動創建DataFrame,絕大多數數據都是讀取文件獲得的,例如讀取csv文件,excel文件等等,那下面我們來看看pandas如何讀取文件呢?

pd.read_csv(filename):從CSV文件導入數據  pd.read_table(filename):從限定分隔符的文本文件導入數據  pd.read_excel(filename):從Excel文件導入數據  pd.read_sql(query, connection_object):從SQL表/庫導入數據  pd.read_json(json_string):從JSON格式的字元串導入數據  pd.read_html(url):解析URL、字元串或者HTML文件,抽取其中的tables表格  pd.read_clipboard():從你的粘貼板獲取內容,並傳給read_table()  pd.DataFrame(dict):從字典對象導入數據,Key是列名,Value是數據

pandas支援從多個數據源導入數據,包含文件,字典,json,sql,html等等。

那我們先來看看文件的導入:

我們創建一個csv文件,填寫以上數據。

下面我們讀取這個文件:

import pandas as pd  df = pd.read_csv("ex.csv")  print(df)

讀出來的數據就是一個dataframe,可以直接對他進行操作。

如果想獲取前幾行值可以直接使用head方法,或者切片,都是可以拿到前兩行的值的。讀取數據的方法提供如下幾種:

df.head(n):查看DataFrame對象的前n行  df.tail(n):查看DataFrame對象的最後n行  df.shape():查看行數和列數  df.info():查看索引、數據類型和記憶體資訊  df.describe():查看數值列的匯總統計  s.value_counts(dropna=False):查看Series對象的唯一值和計數  df.apply(pd.Series.value_counts):查看DataFrame對象中每一列的唯一值和計數
print(df.head(2))  print(df[0:2])

讀取excel:

import pandas as pd  score = pd.DataFrame(pd.read_excel('data.xlsx'))  score.to_excel('data1.xlsx')  print(score)

讀取文件的示例就到這裡,基本上每種文件都是一樣的。

關於DataFrame裡面還有一些修改表結構的操作,可以來適當了解一下:

import pandas as pd  import numpy as np  val = np.arange(10, 60).reshape(10, 5)  col = ["ax", "bx", "cx", "dx", "ex"]  idx = list("abcdefghij")  df1 = pd.DataFrame(val, columns = col, index = idx)  print(df1)  print("*" * 21, "<- dataframe")  df2 = df1.rename(columns={"ax": "修改1", "bx": "修改2"})  print(df2)  print("*" * 21, "<- dataframe")

通過rename方法來修改列名,本質上並沒有修改原來的dataframe,而是生成新的dataframe替換了列名。

在DataFrame中增加一列,我們可以直接給值來增加一列,就和python的字典裡面添加元素是一樣的:

import pandas as pd  import numpy as np  val = np.arange(10, 60).reshape(10, 5)  col = ["ax", "bx", "cx", "dx", "ex"]  idx = list("abcdefghij")  df1 = pd.DataFrame(val, columns=col, index=idx)  print(df1)  nval = val = np.arange(100, 110).reshape(10, 1)  df1["fx"] = nval  print(df1)

連接多個dataframe,這個就和資料庫一樣,可以聯想一下資料庫之間的表連接,在dataframe裡面我們使用contact方法。我們做的連接是全連接,如果數據不全的就會拿NaN來補:

import pandas as pd  import numpy as np  val1 = np.arange(10, 40).reshape(10, 3)  val2 = np.arange(50, 80).reshape(10, 3)  col1 = ["ax", "bx", "cx"]  col2 = ["cx", "dx", "ex"]  idx = list("abcdefghij")  df1 = pd.DataFrame(val1, columns=col1, index=idx)  df2 = pd.DataFrame(val2, columns=col2, index=idx)  print(df1)  print(df2)  df3 = pd.concat([df1, df2[5:], df1[:5], df2], axis=1)  print(df3)

如果不想做全連接,想做一些其他的連接,那我們在連接的時候可以使用merge方法,這樣就可以進行不同的連接了。

import pandas as pd  df1 = pd.DataFrame({'name':['amy', 'john', 'a', 'b', 'c'], 'data1': range(5)})  df2 = pd.DataFrame({'name':['amy', 'john', 'A', 'B', 'C'], 'data2': range(5)})    # 指定 name 這列進行連接。  df3 = pd.merge(df1, df2, on='name')  # 內連接  df3 = pd.merge(df1, df2, how='inner')  # 左連接  df3 = pd.merge(df1, df2, how='left')  # 右連接  df3 = pd.merge(df1, df2, how='right')

在這後,我們需要做的就是處理數據了。把給定的一些數據處理好,這就看我們這些人是如何處理數據了。俗話說的好,條條大路通羅馬。每個數據分析師都有自己處理數據的手段,最好能達到目的就可以了。

我們一開始拿到的原始數據多多少少是有些問題的,可能會丟失數據啊,有臟數據啊等等,這個時候需要我們來對數據進行一些清理。數據清洗是在數據準備的過程中必不可少的環節,pandas為我們提供了一系列清洗數據的方法。這裡我們就來介紹一些。

首先我們可能需要從給定的數據中提取出一些我們想要的數據,而Pandas 提供了一些選擇的方法,這些選擇的方法可以把數據切片,也可以把數據切塊。下面我們簡單介紹一下:

選擇一列:

data['column_name']

選擇一列的前幾行數據:

data['columns_name'][:n]

選擇多列:

data[['column1','column2']]

Where 條件過濾:

data[data['column_name'] > condition]

那我們可以考慮一下產生這些異常數據的原因有哪些呢?

一般的,產生這個問題可能的原因可能有以下幾點:

1、從來沒有填正確過

2、數據不可用

3、計算錯誤

對於這些問題,我們處理這些異常數據無非就是下面幾種辦法:

1、為缺失數據賦值默認值

2、去掉/刪除缺失數據行

3、去掉/刪除缺失率高的列

添加默認值(fillna)

現在我們的數據中,年齡出現了異常值None,這個時候我們需要把None替換成標準的年齡值,我們假設研究對象的年齡平均在23左右,就把默認值設成23,那我們就可以成功的把None替換成23了。

import pandas as pd  data = {'Fname': ['amy', 'john', 'tony'],          'age': [50, None, 54],          'income': [1000000, 500000, 400000000]}  df1 = pd.DataFrame(data)  df1.age = df1.age.fillna(23)  print(df1)

刪除不完整的行(dropna)

假設我們想刪除任何有缺失值的行。這種操作具有侵略性,但是我們可以根據我們的需要進行擴展。

我們可以使用isnull來查看dataframe中是否有缺失值。

df1.isnull().values.any()

刪除任何包含 NA 值的行是很容的:

df1.dropna() 

當然,我們也可以刪除一整行的值都為 NA:

df1.dropna(how='all') 

我們也可以增加一些限制,在一行中有多少非空值的數據是可以保留下來的(在下面的例子中,行數據中至少要有 5 個非空值)

df1.drop(thresh=5) 

刪除不完整的列(dropna)

我們可以上面的操作應用到列上。我們僅僅需要在程式碼上使用 axis=1 參數。這個意思就是操作列而不是行。(默認是axis=0。)

刪除一整列為 NA 的列:

data.drop(axis=1, how='all')

刪除任何包含空值的列:

data.drop(axis=1. how='any')

規範化數據類型

我們可以在讀取文件的時候就限定,哪一列的數據是什麼類型。

data = pd.read_csv('../data/moive.csv', dtype={'duration': int})    data = pd.read_csv('./data/moive.csv', dtype={'year':str})

還有一些注意點就是,當數據變成人為的破環,例如大寫變小寫,單詞拼錯等。使用一些方法來修復,具體是用正則還是其他方法,就看你了。

刪除重複值(drop_duplicates)

表中難免會有一些重複的記錄,這時候我們需要把這些重複的數據都刪除掉。

import pandas as pd  data = {'Fname': ['amy', 'amy', 'john', 'tony'],          'age': [50, 50, None, 54],          'income': [1000000, 1000000, None, 400000000]}  df1 = pd.DataFrame(data)  print(df1.duplicated())  print(df1.drop_duplicates())

使用duplicated方法可以查找出是否有重複的行,使用drop_duplicated方法就可以直接將重複的行刪除了。

關於dataframe中的統計函數,這裡就不多說什麼了,具體已經在Serires那個章節中列詳細出來了。具體可以參考以下方法。

df.count()#非空元素計算  df.min()#最小值  df.max()#最大值  df.idxmin()#最小值的位置,類似於R中的which.min函數  df.idxmax()#最大值的位置,類似於R中的which.max函數  df.quantile(0.1)#10%分位數  df.sum()#求和  df.mean()#均值  df.median()#中位數  df.mode()#眾數  df.var()#方差  df.std()#標準差  df.mad()#平均絕對  偏差df.skew()#偏度  df.kurt()#峰度  df.describe()#一次性輸出多個描述性統計指標

下面我們說一下Pandas裡面最神奇萬能的apply函數。

apply函數可以對DataFrame對象進行操作,既可以作用於一行或者一列的元素,也可以作用於單個元素。apply最神奇的地方就是它裡面可以調用函數,我們經常在apply裡面寫一些功能的匿名函數。

import pandas as pd  import numpy as np  s = pd.Series(np.arange(2, 6))  print(s)  print(s.apply(lambda x: 2 * x))

從上面例子的結果中我們看出數據裡面的所有數字都被乘上了2,這就因為我們的apply函數裡面寫了一個匿名函數,將原來的數據變成兩倍(如果你對lambda不懂,可以參考之前文章,介紹python裡面的高級函數的

apply不僅可以適用於整個dataframe,也可以作用於行和列,如果想作用於行,可以添加參數axis=0,如果想作用於列,axis=1。

關於Pandas,我們到這裡就算講完了。歡迎大家前來交流和指點。