灰太狼的數據世界(三)
- 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,我們到這裡就算講完了。歡迎大家前來交流和指點。