作者:xxw9485
時間:2018/3/10
來源:http://mp.weixin.qq.com/s/pm8503plIouWGAtS3zAM5Q
2、數據框
作爲從事數據相關工作的我們,平時接觸的更多的是一張有板有眼的數據表格,在這裏我們就叫作數據框。在Python中可以通過pandas模塊的DataFrame函數構造數據框。
2.1 數據框的構造
2.1.1 通過列表創建數據框
這種創建數據框的方式,默認沒有列名稱的,不過可以運用DataFrame函數中的columns參數給數據框的每列添加名稱。如果你需要給行加上索引名稱,你可以使用index參數。
# 輸入:
# 構造數據框
import pandas as pd
a = pd.DataFrame([[1,2,3],[10,20,30],[100,200,300],[1,10,100]])
print(a,'\n')
b = pd.DataFrame([[1,2,3],[10,20,30],[100,200,300],[1,10,100]],columns=['v1','v2','v3']) # 添加列名稱
print(b)
# 輸出:
0 1 2
0 1 2 3
1 10 20 30
2 100 200 300
3 1 10 100
v1 v2 v3
0 1 2 3
1 10 20 30
2 100 200 300
3 1 10 100
2.1.2 通過字典創建數據框
這種創建數據框的方式,輸出結果中列名稱順序與構造時的數據不一致,這是因爲字典並非是一種序列,而是一種特殊的鍵值對關係的對象。如果你需要按照指定的列順序排列,仍然可以通過columns參數實現。
# 輸入:
import pandas as pd
a = pd.DataFrame({'id':[1,2,3],'name':['Tom','Lily','Jim'],'age':[20,21,22]})
print(a,'\n')
b = pd.DataFrame({'id':[1,2,3],'name':['Tom','Lily','Jim'],'age':[20,21,22]},columns=['id','name','age'])
print(b)
# 輸出:
age id name
0 20 1 Tom
1 21 2 Lily
2 22 3 Jim
id name age
0 1 Tom 20
1 2 Lily 21
2 3 Jim 22
2.2 數據的讀入
2.2.1 文本文件的讀取
在pandas模塊中有read_table和read_csv兩個函數讀取常見的文本文件。read_table和read_csv兩個函數都可以讀文本文件數據,區別在於默認的sep參數不一致,read_table默認以製表符Tab鍵爲字段間的間隔符,而read_csv默認以逗號爲字段間的間隔符。
# 輸入:
import pandas as pd
books = pd.read_table('book.csv',sep=',',header=None,usecols=[0,1,3],names=['type','title','author'])
print(books.tail(),'\n') # 默認輸出最後5行
print(books.tail(1),'\n') # 輸出最後1行
print(books.head(),'\n') # 默認輸出前5行
print(books.head(1)) # 輸出前1行
# 輸出:
type title author
5 spss spss2015 小明
6 spss spss2016 小明
7 spss spss2017 小明
8 spss spss2018 小明
9 spss spss2019 小明
type title author
9 spss spss2019 小明
type title author
0 spss spss2010 小明
1 spss spss2011 小明
2 spss spss2012 小明
3 spss spss2013 小明
4 spss spss2014 小明
type title author
0 spss spss2010 小明
由於原始數據文件books.txt沒有字段名稱,故設置header=None,並用names參數給表字段加上名稱,usecols則是設置讀取原始數據的哪些列。
2.2.2 電子表格的讀取
pandas模塊中read_excel函數可以非常方便的讀取外部的xls和xlsx電子表格:
# 輸入:
import pandas as pd
a = pd.read_excel(r'D:\Python36\test2018.3.19\test.xlsx',header=None)
print(a.head()) # 數據集的前五行
# 輸出:
0 1 2 3 4
0 上海 紐海信息技術(上海)有限公司 8581 1號店 2000人以上
1 上海 上海點榮金融信息服務有限責任公司 23177 點融網 500-2000人
2 上海 上海晶樵網絡信息技術有限公司 57561 SPD 50-150人
3 上海 杭州數雲信息技術有限公司上海分公司 7502 數雲 150-500人
4 上海 上海銀基富力信息技術有限公司 130876 銀基富力 15-50人
2.2.3 MySQL數據庫數據的讀取
使用Python讀取MySQL數據庫,還需要結合pymysql模塊一起使用。
在MySQL中創建數據:
# 建庫
create database test;
# 調用庫名稱
use test;
# 創建表
create table user_info(
id int,
name varchar(10),
gender varchar(2),
age tinyint,
income smallint);
# 賦值
insert into user_info values
(1,'Tom','M',28,15000),
(2,'Lily','F',27,17000),
(3,'Lucy','F',37,15600),
(4,'Jim','M',29,20000),
運用Python與MySQL創建連接,並讀取數據:
import pymysql
import pandas as pd
# 創建連接
conn = pymysql.connect(host='localhost',port=3306,user='root',password='123456',database='test',charset='utf8')
user_info = pd.read_sql('select * from user_info',conn) # 讀取數據
print(user_info)
# 關閉連接
conn.close()
2.3 數據的概覽信息
- shape屬性和columns屬性返回數據集的行列數及變量名;
- describe屬性可以對數值型變量(include=[‘number’])和離散型變量(include=[‘object’])進行描述性統計;
- info屬性則對數據集的變量類型進行簡單的描述。
2.4 數據篩選
在pandas取出一列有兩種方法,一種是比較普遍適用的名稱索引法,另一種則是點取法。
# 輸入:
import pandas as pd
a = pd.read_excel(r'D:\Python36\test2018.3.19\test.xlsx')
print(a.head(1),'\n') # 數據集的前1行
print(a['city'].head()) #名稱索引法取出某列數據
#print(a.city.head()) #點取法取出某列數據,結果同上
# 輸出:
city company number name people
0 上海 紐海信息技術(上海)有限公司 8581 1號店 2000人以上
0 上海
1 上海
2 上海
3 上海
4 上海
Name: city, dtype: object
如果使用點取法取出數據集中的某列,需要注意的是列的名稱必須是一個整體,例如stu age或stu.age等格式的變量名就不能使用點取法。
如果你需要取出多列數據時,那不管是Python還是R語言只能使用名稱索引或位置索引了。
- 一個變量的觀測篩選:
# 輸入:
print(a.loc[a.people=='2000人以上',:].head())
# 輸出:
city company number name people
0 上海 紐海信息技術(上海)有限公司 8581 1號店 2000人以上
7 上海 上海安碩信息技術股份有限公司 21863 安碩信息(amarsoft) 2000人以上
- 兩個變量的觀測篩選:
# 輸入:
print(a.loc[(a.people=='2000人以上')&(a.name=='1號店'),:])
# 輸出:
city company number name people
0 上海 紐海信息技術(上海)有限公司 8581 1號店 2000人以上
需要注意的是:多個變量的篩選,可以是或(|)關係、可以是且(&)關係還可以是非(~)關係,一定要用圓括號把條件括起來。
- 兩個變量的觀測篩選並篩選部分變量:
# 輸入:
print(a.loc[(a.people=='2000人以上')&(a.name=='1號店'),['city','company']])
# 輸出:
city company
0 上海 紐海信息技術(上海)有限公司
2.5 變量的刪除
有時,在一張表裏你可能需要刪除與建模或分析無關緊要的變量,如用戶id、姓名、郵編號碼等。在Python中,你可以藉助於drop函數非常輕鬆的刪除指定的變量。
# 輸入:
print(a.drop(['number'], axis = 1).head(1))
# 輸出:
city company name people
0 上海 紐海信息技術(上海)有限公司 1號店 2000人以上
注意:該函數默認的axis=0,表示刪除行觀測,如果需要刪除列,就要將axis設置爲1。記住,此時雖然刪除了兩個變量,但數據集本身是沒有變化的,如果你需要改變數據集,需要設置inplace爲True。
2.6 變量重命名
需要更換變量名時,rename函數可以幫助我們解決問題:
# 輸入:
print(a.rename(columns={'city':'城市'}).head(1))
# 輸出:
城市 company number name people
0 上海 紐海信息技術(上海)有限公司 8581 1號店 2000人以上
2.7 數據類型轉化
字符型數值轉數值:可以通過astype函數把字符型變量轉化爲整數型和浮點型。
實例:
# 輸入
print(a.dtypes)
a = a.astype({'number':'object'})
print(a.dtypes)
# 輸出
city object
company object
number int64
name object
people object
dtype: object
city object
company object
number object
name object
people object
dtype: object
2.8 數據集的排序
如果你需要對你的數據集進行排序,Python中pandas模塊也提供了非常好用的sort_values函數。
# 輸入:
print(a.sort_values(by = ['number'],ascending = [True]).head())
# 輸出:
city company number name people
6 上海 上海好體信息科技有限公司 2002 足球魔方 150-500人
3 上海 杭州數雲信息技術有限公司上海分公司 7502 數雲 150-500人
0 上海 紐海信息技術(上海)有限公司 8581 1號店 2000人以上
7 上海 上海安碩信息技術股份有限公司 21863 安碩信息(amarsoft) 2000人以上
1 上海 上海點榮金融信息服務有限責任公司 23177 點融網 500-2000人
2.9 數據去重
在數據清洗中,往往都要檢查一下數據集的觀測行是否有重複,duplicated函數可以用來檢查數據集是否重複,如果重複,則會在重複的行顯示True。然後,通過drop_duplicates函數對數據集的重複觀測進行刪除。這兩個函數均有subset參數,默認對數據集的所有變量進行重複性檢測和刪除,如果你需要指定某些變量的重複性檢查和刪除就可以往subset參數傳遞變量。
# 輸入:
import pandas as pd
data = pd.DataFrame({'name':['liu','li','chen','liu'],
'age':[20,21,22,20],
'gender':['M','M','M','M']})
print(data)
print(data.duplicated()) # 檢查數據集是否重複
print(data.drop_duplicates()) # 刪除重複觀測
print(data.duplicated(subset='gender')) # 指定檢測某個變量是否重複
# 輸出:
age gender name
0 20 M liu
1 21 M li
2 22 M chen
3 20 M liu
0 False
1 False
2 False
3 True
dtype: bool
age gender name
0 20 M liu
1 21 M li
2 22 M chen
0 False
1 True
2 True
3 True
dtype: bool
2.10 數據抽樣
pandas模塊有一個sample函數可以幫助我們完成抽樣的任務,語法:
sample(n = None, frac = None, replace = False, weights = None, random_state = None)
- n:指定抽樣的個數
- frac:指定抽樣的比例
- replace:指定是否有放回的抽樣,默認爲無放回抽樣
- weights:指定每個樣本被抽中的概率,默認每個樣本抽中的概率相等
- random_state :指定抽樣的隨機種子,默認無固定的隨機種子,即每次抽樣的結果不一樣
# 輸入:
import pandas as pd
a = pd.read_excel(r'D:\Python36\test2018.3.19\test.xlsx')
train = a.sample(frac = 0.5, random_state = 1)
print(train,'\n')
test = a.loc[~a.index.isin(train.index),:] # "~"表示非
print(test)
# 輸出:
city company number name people
2 上海 上海晶樵網絡信息技術有限公司 57561 SPD 50-150人
9 上海 五五海淘(上海)科技股份有限公司 58109 55海淘 150-500人
6 上海 上海好體信息科技有限公司 2002 足球魔方 150-500人
4 上海 上海銀基富力信息技術有限公司 130876 銀基富力 15-50人
0 上海 紐海信息技術(上海)有限公司 8581 1號店 2000人以上
city company number name people
1 上海 上海點榮金融信息服務有限責任公司 23177 點融網 500-2000人
3 上海 杭州數雲信息技術有限公司上海分公司 7502 數雲 150-500人
5 上海 上海青之桐投資管理有限公司 28095 青桐資本 50-150人
7 上海 上海安碩信息技術股份有限公司 21863 安碩信息(amarsoft) 2000人以上
8 上海 上海崇杏健康管理諮詢有限公司 121208 上海崇杏 15-50人
訓練集可以直接從sample函數中抽取出來,測試集則通過索引的方式,將訓練集中的行號排除出去。
2.11 頻數統計
頻數統計,顧名思義就是統計某個離散變量各水平的頻次。
# 輸入:
print(a.people.value_counts(),'\n') # 統計各個people小組的人數
print(a.people.value_counts()/sum(a.people.value_counts())) # 統計各個people小組的佔比情況
# 輸出:
150-500人 3
2000人以上 2
50-150人 2
15-50人 2
500-2000人 1
Name: people, dtype: int64
150-500人 0.3
50-150人 0.2
15-50人 0.2
2000人以上 0.2
500-2000人 0.1
Name: people, dtype: float64
需要統計兩個離散變量的交叉統計表時,可以使用pandas模塊提供的crosstab函數。
# 輸入:
b = pd.crosstab(index = a.city, columns = a['people'])
print(b)
# 輸出:
people 15-50人 150-500人 2000人以上 50-150人 500-2000人
city
上海 2 3 2 2 1
2.12 缺失值處理
對於缺失值我們可以通過pandas模塊中的isnull函數監控每個變量是否存在缺失,缺失的比例如何,然後通過pandas模塊中的dropna函數和fillna函數進行刪除或替補處理。
- 首先,我們手工編造一個含缺失值的數據框:
# 輸入:
import pandas as pd
import numpy as np
df = pd.DataFrame([[1,2,3,4],[np.NaN,6,7,np.NaN],[11,np.NaN,12,13],
[100,200,300,400],[20,40,60,np.NaN]], columns = ['x1','x2','x3','x4'])
print(df)
# 輸出:
x1 x2 x3 x4
0 1.0 2.0 3 4.0
1 NaN 6.0 7 NaN
2 11.0 NaN 12 13.0
3 100.0 200.0 300 400.0
4 20.0 40.0 60 NaN
- 其次,使用isnull函數檢查數據集的缺失情況:
# 輸入:
# 整個數據集是否存在缺失
print(any(df.isnull()),'\n')
# 每一列是否有缺失、以及缺失比例
is_null = []
null_ratio = []
for col in df.columns:
is_null.append(any(pd.isnull(df[col])))
null_ratio.append(float(round(sum(pd.isnull(df[col]))/df.shape[0],2)))
print(is_null,'\n', null_ratio, '\n')
# 每一行是否有缺失
is_null = []
for index in list(df.index):
is_null.append(any(pd.isnull(df.iloc[index,:])))
print(is_null,'\n')
# 輸出:
True
[True, True, False, True]
[0.2, 0.2, 0.0, 0.4]
[False, True, True, False, True]
- 最後,對缺失數據進行處理:
刪除法
dropna函數,有兩種刪除模式,一種是對含有缺失的行(任意一列)進行刪除,另一種是刪除那些全是缺失(所有列)的行:
# 輸入:
print(df.dropna(),'\n') # 刪除任何含有缺失的行
print(df.dropna(how = 'all')) # 刪除全是缺失的行
# 輸出:
x1 x2 x3 x4
0 1.0 2.0 3 4.0
3 100.0 200.0 300 400.0
x1 x2 x3 x4
0 1.0 2.0 3 4.0
1 NaN 6.0 7 NaN
2 11.0 NaN 12 13.0
3 100.0 200.0 300 400.0
4 20.0 40.0 60 NaN
替補法
fillna函數提供前向替補、後向替補和函數替補的幾種方法:
# 輸入:
print(df.fillna(method='ffill'),'\n') # 前向替補
print(df.fillna(method='bfill'),'\n') # 後向替補
# 不同的列用不同的函數替補
print(df.fillna(value = {'x1':df.x1.mean(),
'x2':df.x2.median(),
'x4':df.x4.max()}))
# 輸出:
x1 x2 x3 x4
0 1.0 2.0 3 4.0
1 1.0 6.0 7 4.0
2 11.0 6.0 12 13.0
3 100.0 200.0 300 400.0
4 20.0 40.0 60 400.0
x1 x2 x3 x4
0 1.0 2.0 3 4.0
1 11.0 6.0 7 13.0
2 11.0 200.0 12 13.0
3 100.0 200.0 300 400.0
4 20.0 40.0 60 NaN
x1 x2 x3 x4
0 1.0 2.0 3 4.0
1 33.0 6.0 7 400.0
2 11.0 23.0 12 13.0
3 100.0 200.0 300 400.0
4 20.0 40.0 60 400.0
2.13 數據映射
映射函數apply的目的就是將用戶指定的函數運用到數據集的縱軸(即各個變量)或橫軸(即各個行)。實例:
# 輸入:
# 查看各列和各行是否有缺失
# 創建一個判斷對象是否含缺失的匿名函數
import pandas as pd
import numpy as np
df = pd.DataFrame([[1,2,3,4],[np.NaN,6,7,np.NaN],[11,np.NaN,12,13],
[100,200,300,400],[20,40,60,np.NaN]], columns = ['x1','x2','x3','x4'])
isnull = lambda x : any(pd.isnull(x))
print(df.apply(func = isnull, axis = 0),'\n') # axis=0表示將isnull函數映射到各列
print(df.apply(func = isnull, axis = 1)) # axis=1表示將isnull函數映射到各行
# 輸出:
x1 True
x2 True
x3 False
x4 True
dtype: bool
0 False
1 True
2 True
3 False
4 True
dtype: bool
需要計算每個學生的總成績,或各科的平均分,也可以用apply函數實現。實例:
# 輸入:
import pandas as pd
import numpy as np
df = pd.DataFrame([['a',99,88,77],['b',98,87,76],['c',100,90,80],
['d',95,80,85],['e',90,89,99]], columns = ['name','chinese','math','english'])
print(df)
df['total'] = df.iloc[:,1:5].apply(func = np.sum, axis = 1) # 每個學生的總成績
print(df)
avg = df.iloc[:,1:5].apply(func = np.mean, axis = 0) # 每門學科的平均成績
print(avg)
# 輸出:
name chinese math english
0 a 99 88 77
1 b 98 87 76
2 c 100 90 80
3 d 95 80 85
4 e 90 89 99
name chinese math english total
0 a 99 88 77 264
1 b 98 87 76 261
2 c 100 90 80 270
3 d 95 80 85 260
4 e 90 89 99 278
chinese 96.4
math 86.8
english 83.4
total 266.6
dtype: float64
2.14 數據彙總
如果你想要做類似SQL中的聚合操作,pandas也提供了實現該功能的函數,即groupby函數與aggregate函數的搭配使用。
# 輸入
import pandas as pd
import numpy as np
df = pd.DataFrame([['a','f',99,88,77],['b','m',98,87,76],['c','m',100,90,80],
['d','f',95,80,85],['e','m',90,89,99]], columns = ['name','sex','chinese','math','english'])
# 對性別gender做分組統計各數值型變量的平均值
groupby_gender = df.groupby(['sex'])
b = groupby_gender.aggregate(np.mean)
print(b)
# 對性別gender和班級class兩個變量做分組統計各數值型變量的平均值
grouped = df.groupby(['sex','name'])
c = grouped.aggregate(np.mean)
print(c)
# 對chinese算平均值,對math算中位數
d = grouped.aggregate({'chinese':np.mean,'math':np.median})
print(d)
# 輸出
chinese math english
sex
f 97.0 84.000000 81.0
m 96.0 88.666667 85.0
chinese math english
sex name
f a 99 88 77
d 95 80 85
m b 98 87 76
c 100 90 80
e 90 89 99
chinese math
sex name
f a 99 88
d 95 80
m b 98 87
c 100 90
e 90 89
2.15 數據集的縱向合併
如果你手中有多張數據結構一致的excel表格,你需要將這些表格合併到一起,你會怎麼做?複製粘貼?是不是太慢了,這裏教你使用Python完成數據的批量合併。
實例:
import os
import pandas as pd
# 指定數據文件所在的路徑
path = 'D:\\data file\\data1\\'
# 羅列路徑下的文件名稱
filenames = os.listdir(path)
# 通過for循環完成數據的堆疊
dataframes = []
for file in filenames:
dataframes.append(pd.read_excle(path + file))
alldata = pd.concat(dataframes, ignore_index=True)
alldata.head()
注意:pd.concat函數的第一個參數一定要是一個可迭代對象。故在代碼中對dataframe初始化爲列表結構。
2.16 數據集的橫向擴展
如果你所需的數據集來自於多張表,而這些表之間存在一些公共的字段用於觀測行的匹配,換句話說,你需要在excel使用vlookup這樣的函數完成數據的連接。藉助於pandas中merge函數完成兩個數據集的連接。如果你的兩張表有公共字段,而且字段名稱完全一致,merge函數會自動查詢這些字段,並以這些字段作爲連接的依據。如果兩張表中含公共字段,但名稱不一致,如Id與id,這個時候就需要left_on和right_on兩個參數的使用了。
語法:
pd.merge(left, right, how='inner', on=None, left_on=None, right_on=None,
left_index=False, right_index=False,sort=False,
suffixes=('_x','_y'), copy=True, indicator=False)
- left,right:爲需要連接的兩張表;
- how:默認對兩張表進行內連,‘right’,‘left’爲右連和左連;
- on:指定關聯兩張表的公共字段;
- left_on,right_on:指定left表和right表中需要關聯的字段;
- left_index,right_index:指定left表和right表中需要關聯的行索引
實例:
# 有公共字段且字段名稱一樣的兩個數據集的連接
merge_data = pd.merge(user_info, economy_info, how = 'left')
merge_data.head()
# 有公共字段且字段名稱不一樣的兩個數據集的連接
merge_data2 = pd.merge(user_info, economy_info, how = 'left', left_on = 'ID', right_on = 'id')
merge_data2.head()
2.17 離散變量的啞變量處理
在建模過程中,往往會有一些離散變量,如學歷、收入等級,用戶會員等級。這些變量直接放入到模型中(如迴歸模型)是有問題的(即使你已經用1,2,3…等數據表示),爲解決這個問題,我們通常是將這些變量進行啞變量處理。如果離散變量有N種水平,就需要構造N-1個變量,每一個變量均用0和1的值來表示。這時需要用到pandas模塊中的get_dummies函數。
實例:
# 輸入:
import pandas as pd
import numpy as np
a = pd.DataFrame([['a','f',99,88,77],['b','m',98,87,76],['c','m',100,90,80],
['d','f',95,80,85],['e','m',90,89,99]], columns = ['name','sex','chinese','math','english'])
print(a)
b = pd.get_dummies(a, columns = ['sex']).head() # 啞變量處理
print(b)
c = b.drop(['sex_f'], axis = 1).head() # 刪除字段sex_f
print(c)
# 輸出:
name sex chinese math english
0 a f 99 88 77
1 b m 98 87 76
2 c m 100 90 80
3 d f 95 80 85
4 e m 90 89 99
name chinese math english sex_f sex_m
0 a 99 88 77 1 0
1 b 98 87 76 0 1
2 c 100 90 80 0 1
3 d 95 80 85 1 0
4 e 90 89 99 0 1
name chinese math english sex_m
0 a 99 88 77 0
1 b 98 87 76 1
2 c 100 90 80 1
3 d 95 80 85 0
4 e 90 89 99 1
千萬記得,如果你的變量進行了啞變量處理,建模時要記得刪除原離散變量中的某一個水平,如性別中刪除sex_f。刪除的變量,就表示性別中,以女性(f)爲參照組。
2.18 連續變量的分段
把連續變量進行分段處理,如年齡需要分成未成年、青年、中年和老年;收入需要分成低收入羣體、中等收入羣體和高收入羣體,這時可以用到pandas.cut()函數。
語法:
pandas.cut(x, bins, right=True, labels=None, retbins=False, precision=3,include_lowest=False)
- x:表示需要切割處理的變量;
- bins:表示切割後的邊界值,即分組情況;
- right:等於False時表示分段的數據區間不包含上限;
- labels:對應bins切割區間的標籤
實例:
# 輸入:
import numpy as np
import pandas as pd
np.random.seed(1)
age = np.random.randint(low = 12, high = 80, size =1000) # 隨機生成一個年齡的字段
age = pd.Series(age) # 化爲序列
print(age.head(),'\n')
age_cut = pd.cut(age, bins = [0,18,45,60,80], right = False, labels = ['未成年','青年','中年','老年'])
print(age_cut.head()) # 把年齡序列切割爲四個區間,18歲以下爲未成年;18~45歲爲青年;45~60歲爲中年;60歲以上爲老年
# 輸出:
0 49
1 24
2 21
3 17
4 76
dtype: int32
0 中年
1 青年
2 青年
3 未成年
4 老年
dtype: category
Categories (4, object): [未成年 < 青年 < 中年 < 老年]