數(shù)據(jù)處理工具--Pandas模塊

強(qiáng)大的數(shù)據(jù)處理模塊Pandas慕趴,可以解決數(shù)據(jù)的預(yù)處理工作眨业,如數(shù)據(jù)類型的轉(zhuǎn)換推盛、缺失值的處理、描述性統(tǒng)計(jì)分析和數(shù)據(jù)的匯總等

一、序列與數(shù)據(jù)框的構(gòu)造

Pandas模塊的核心操作對(duì)象為序列和數(shù)據(jù)框抛姑。序列指數(shù)據(jù)集中的一個(gè)字段赞厕,數(shù)據(jù)框?yàn)橹辽俸袃蓚€(gè)字段(或序列)的數(shù)據(jù)集。

1.構(gòu)造序列



通過列表定硝、元祖坑傅、Numpy中的一維數(shù)組構(gòu)造序列均如序列1,第一列為序列的行索引(行號(hào))喷斋,自動(dòng)從0開始唁毒;第二列為序列的實(shí)際值

通過字典構(gòu)造不同,第一列為具體的行名稱星爪,對(duì)應(yīng)字典中的鍵浆西,第二列為序列的實(shí)際值,對(duì)應(yīng)字典中的值顽腾。

還可以通過數(shù)據(jù)框中的某一列構(gòu)建

2.序列元素的獲取

對(duì)一維數(shù)組的索引方法和數(shù)學(xué)以及統(tǒng)計(jì)函數(shù)都可以用到序列上近零,但序列有特有的處理方法。




對(duì)通過字典類型構(gòu)建的抄肖,可用行號(hào)久信,也可用行名稱索引



如果需要對(duì)序列做數(shù)學(xué)函數(shù)計(jì)算,首選numpy模塊

如果需要對(duì)序列做統(tǒng)計(jì)函數(shù)計(jì)算漓摩,首選序列的方法

3.構(gòu)造數(shù)據(jù)框

數(shù)據(jù)框?qū)嶋H是一個(gè)數(shù)據(jù)集裙士,行代表每一條觀測,列代表各個(gè)變量管毙。在一個(gè)數(shù)據(jù)庫中可以存放不同數(shù)據(jù)類型的序列腿椎,而數(shù)組和序列只能存放同質(zhì)數(shù)據(jù)。



手工構(gòu)造數(shù)據(jù)框的話夭咬,首選字典方法啃炸,因?yàn)槠渌椒?gòu)造沒有具體的變量名

還可以通過外部數(shù)據(jù)的讀取構(gòu)造

二、外部數(shù)據(jù)的讀取

1.文本文件的讀取

使用Pandas中的read_table函數(shù)或者read_csv函數(shù)



filepath_or_buffer:指定txt文件或csv文件所在的具體路徑卓舵;
sep:指定原數(shù)據(jù)集中各字段之間的分隔符南用,默認(rèn)為Tab制表符;
header:是否需要將原數(shù)據(jù)集中的第一行作為表頭掏湾,默認(rèn)將第一行用作字段名稱裹虫;
names:如果原數(shù)據(jù)集中沒有字段,可以通過該參數(shù)在數(shù)據(jù)讀取時(shí)給數(shù)據(jù)框添加具體的表頭忘巧;
index_col:指定原數(shù)據(jù)集中的某些列作為數(shù)據(jù)框的行索引(標(biāo)簽)恒界;
usecols:指定需要讀取原數(shù)據(jù)集中的哪些變量名睦刃;
dtype:讀取數(shù)據(jù)時(shí)砚嘴,可以為原數(shù)據(jù)集的每個(gè)字段設(shè)置不同的數(shù)據(jù)類型;
converters:通過字典格式,為數(shù)據(jù)集中的某些字段設(shè)置轉(zhuǎn)換函數(shù)
skiprows:數(shù)據(jù)讀取時(shí)际长,指定需要跳過原數(shù)據(jù)集開頭的行數(shù)耸采;
skipfooter:數(shù)據(jù)讀取時(shí),指定需要跳過原數(shù)據(jù)集末尾的行數(shù)工育;
nrows:指定讀取數(shù)據(jù)的行數(shù)虾宇;
na_values:指定原數(shù)據(jù)集中哪些特征的值作為缺失值;
skip_blank_lines:讀取數(shù)據(jù)時(shí)是否需要跳過原數(shù)據(jù)集中的空白行如绸,默認(rèn)為True嘱朽;
parse_dates:如果參數(shù)值為True,則嘗試解析數(shù)據(jù)框的行索引怔接;如果參數(shù)為列表搪泳,則嘗試解析對(duì)應(yīng)的日期列;如果參數(shù)為嵌套列表扼脐,則將某些列合并為日期列岸军;如果參數(shù)為字典,則解析對(duì)應(yīng)的列(即字典中的值)瓦侮,并生成新的字段名(即字典中的鍵)艰赞;
thousands:指定原始數(shù)據(jù)集中的千分位符;
comment:指定注釋符肚吏,在讀取數(shù)據(jù)時(shí)方妖,如果碰到行首指定的注釋符,則跳過改行罚攀;
encoding:如果文件中含有中文吁断,有時(shí)需要指定字符編碼;

a=pd.read_table("F:\第5章 Python數(shù)據(jù)處理工具--Pandas\第五章 Python數(shù)據(jù)處理工具--Pandas\data_test01.txt",sep=",",skiprows=2,skipfooter=3,comment="#",encoding="utf8",thousands="&",parse_dates={"birthday":[0,1,2]})
a

原數(shù)據(jù)集用逗號(hào)分隔每一列坞生,則改變sep參數(shù)仔役,合并新字段birthday,comment參數(shù)指定跳過的特殊行是己,含有中文的重新編碼又兵,千分位符為了保證數(shù)值型數(shù)據(jù)的正常讀入

2.電子表格的讀取

使用read_excel函數(shù)



io:指定電子表格的具體路徑;
sheetname:指定需要讀取電子表格中的第幾個(gè)Sheet卒废,可以傳遞整數(shù)也可以傳遞具體的Sheet名稱沛厨;
header:是否需要將數(shù)據(jù)集的第一行用作表頭,默認(rèn)為是需要的摔认;
skiprows:讀取數(shù)據(jù)時(shí)逆皮,指定跳過的開始行數(shù);
skip_footer:讀取數(shù)據(jù)是参袱,指定跳過的末尾行數(shù)电谣;
index_col:指定哪些列用作數(shù)據(jù)框的行索引(標(biāo)簽)秽梅;
names:如果原數(shù)據(jù)集中沒有字段,可以通過該參數(shù)在數(shù)據(jù)讀取時(shí)給數(shù)據(jù)框添加具體的表頭剿牺;
parse_cols:指定需要解析的字段企垦;
parse_dates:如果參數(shù)值為True,則嘗試解析數(shù)據(jù)框的行索引晒来;如果參數(shù)為列表钞诡,則嘗試解析對(duì)應(yīng)的日期列;如果參數(shù)為嵌套列表湃崩,則將某些列合并為日期列荧降;如果參數(shù)為字典,則解析對(duì)應(yīng)的列(即字典中的值)攒读,并生成新的字段名(即字典中的鍵)誊抛;
na_values:指定原始數(shù)據(jù)中哪些特殊值代表了缺失值;
thousands:指定原始數(shù)據(jù)集中的千分位符整陌;
convert_float:默認(rèn)將所有的數(shù)值型字段轉(zhuǎn)換為浮點(diǎn)型字段拗窃;
converters:通過字典的形式,指定某些列需要轉(zhuǎn)換的形式泌辫;


b=pd.read_excel(io="F:\第5章 Python數(shù)據(jù)處理工具--Pandas\第五章 Python數(shù)據(jù)處理工具--Pandas\data_test02.xlsx",header=None,converters={0:str},names=['ID',"name",'color',"price"])
b

對(duì)于第一列随夸,實(shí)際上是字符型,為了避免數(shù)據(jù)讀入時(shí)自動(dòng)變成數(shù)值型字段震放,需要用converts參數(shù)

3.數(shù)據(jù)庫數(shù)據(jù)的讀取

需要先通過cmd命令輸入pip install pymysql或者pysmsql(分別對(duì)應(yīng)MYSQL和SQL Server)
CASE1:pymysql中的connect



host:指定需要訪問的MySQL服務(wù)器宾毒;
user:指定訪問MySQL數(shù)據(jù)庫的用戶名;
password:指定訪問MySQL數(shù)據(jù)庫的密碼殿遂;
database:指定訪問MySQL數(shù)據(jù)庫的具體庫名诈铛;
port:指定訪問MySQL數(shù)據(jù)庫的端口號(hào);
charset:指定讀取MySQL數(shù)據(jù)庫的字符集墨礁,如果數(shù)據(jù)庫表中含有中文幢竹,一般可以嘗試將該參數(shù)設(shè)置為“utf8”或“gbk”;
CASE2:pymssql中的connect



參數(shù)含義也是一致的恩静,所不同的是pymysql模塊中connect函數(shù)的host參數(shù)表示需要訪問的服務(wù)器焕毫,而pymssql函數(shù)中對(duì)應(yīng)的參數(shù)是server

以MYSQL舉例:


# 讀入MySQL數(shù)據(jù)庫數(shù)據(jù)
# 導(dǎo)入第三方模塊
import pymysql
# 連接MySQL數(shù)據(jù)庫
conn = pymysql.connect(host='localhost', user='root', password='test', 
                database='test', port=3306, charset='utf8')
# 讀取數(shù)據(jù)
user = pd.read_sql('select * from topy', conn)
# 關(guān)閉連接
conn.close()
# 數(shù)據(jù)輸出
user

三、數(shù)據(jù)類型轉(zhuǎn)換及描述統(tǒng)計(jì)

涉及如何了解數(shù)據(jù)驶乾,例如讀入數(shù)據(jù)規(guī)模如何邑飒、各個(gè)變量屬于什么類型、重要統(tǒng)計(jì)指標(biāo)所對(duì)應(yīng)的值级乐、離散變量各唯一值的頻次統(tǒng)計(jì)等等疙咸。
以某平臺(tái)二手車信息為例:

#數(shù)據(jù)讀取
cars=pd.read_table("F:\sec_cars.csv",sep=",")
#預(yù)覽數(shù)據(jù)前5行
cars.head()

后5行數(shù)據(jù)為tail

#查看數(shù)據(jù)行列數(shù)
print(cars.shape)
#查看變量數(shù)據(jù)類型
print(cars.dtypes)

object指字符型,但車牌時(shí)間應(yīng)該為日期型风科,新車價(jià)格應(yīng)該為浮點(diǎn)型撒轮,下面修改

日期類型一般通過pandas模塊中的to_datetime函數(shù)乞旦,format參數(shù)可直接設(shè)置格式

#修改車牌時(shí)間
cars.Boarding_time=pd.to_datetime(cars.Boarding_time,format="%Y年%m月")

新車價(jià)格中含有“萬”字,因此不能直接轉(zhuǎn)為數(shù)據(jù)類型腔召。需要三步走杆查,首先通過str方法將該字段轉(zhuǎn)換成字符串扮惦,然后通過切片手段臀蛛,將“萬”字剔除,最后運(yùn)用astype方法崖蜜,實(shí)現(xiàn)數(shù)據(jù)類型的轉(zhuǎn)換浊仆。

#修改新車價(jià)格
cars.New_price=cars.New_price.str[:-1].astype("float")
#重新查看數(shù)據(jù)類型
cars.dtypes

接下來,需要對(duì)數(shù)據(jù)做到心中有數(shù)豫领,即通過基本的統(tǒng)計(jì)量(如最小值抡柿、均值、中位數(shù)等恐、最大值等)描述出數(shù)據(jù)中所有數(shù)值型變量的特征洲劣。關(guān)于數(shù)據(jù)的描述性分析可以使用describe方法:

#數(shù)據(jù)的描述性統(tǒng)計(jì)
cars.describe()

進(jìn)一步了解數(shù)據(jù)的形狀分布,如數(shù)據(jù)是否有偏以及是否屬于“尖峰厚尾”的特征课蔬,一次性統(tǒng)計(jì)數(shù)值型變量的偏度和峰度

columns方法用于返回?cái)?shù)據(jù)集的所有變量名囱稽,通過布爾索引和切片方法獲得所有的數(shù)值型變量

#篩選出所有數(shù)值型變量
num_variables=cars.columns[cars.dtypes!="object"][1:]
num_variables

在自定義函數(shù)中,運(yùn)用到了計(jì)算偏度的skew方法和計(jì)算峰度的kurt方法二跋,然后將計(jì)算結(jié)果組合到序列中

#自定義函數(shù)战惊,計(jì)算偏度和峰度
def skew_kurt(x):
 skewness=x.skew()
 kurtsis=x.kurt()
 return pd.Series([skewness,kurtsis],index=["skew","kurt"])

使用apply方法,該方法的目的就是對(duì)指定軸(axis=0扎即,即垂直方向的各列)進(jìn)行統(tǒng)計(jì)運(yùn)算(運(yùn)算函數(shù)即自定義函數(shù))

cars[num_variables].apply(func=skew_kurt,axis=0)

以上的統(tǒng)計(jì)分析全都是針對(duì)數(shù)值型變量的吞获,對(duì)于字符型變量(如二手車品牌Brand、排放量Discharge等)可以使用describe方法谚鄙,所不同是各拷,需要將“object”以列表的形式傳遞給include參數(shù)

#離散型變量的統(tǒng)計(jì)描述
cars.describe(include=["object"])

如上結(jié)果包含離散變量的四個(gè)統(tǒng)計(jì)值,分別是非缺失觀測數(shù)闷营、唯一水平數(shù)撤逢、頻次最高的離散值和具體的頻次。以二手車品牌為例粮坞,一共有10,984輛二手車蚊荣,包含104種品牌,其中別克品牌最多莫杈,高達(dá)1,346輛互例。

進(jìn)一步需要統(tǒng)計(jì)的是各個(gè)離散值的頻次,甚至是對(duì)應(yīng)的頻率筝闹。以二手車品的標(biāo)準(zhǔn)排量Discharge為例

#離散變量頻次統(tǒng)計(jì)
Freq=cars.Discharge.value_counts()
#總記錄媳叨,總頻次
cars.shape[0]
Freq_ratio = Freq/cars.shape[0]
Freq_df = pd.DataFrame({'Freq':Freq,'Freq_ratio':Freq_ratio})
Freq_df.head()

構(gòu)成的數(shù)據(jù)框包含兩列腥光,分別是二手車各種標(biāo)準(zhǔn)排量對(duì)應(yīng)的頻次和頻率,數(shù)據(jù)框的行索引(標(biāo)簽)就是二手車不同的標(biāo)準(zhǔn)排量糊秆。如果讀者需要把行標(biāo)簽設(shè)置為數(shù)據(jù)框中的列武福,可以使用reset_index方法,inplace參數(shù)設(shè)置為True痘番,表示直接對(duì)原始數(shù)據(jù)集進(jìn)行操作捉片,影響到原數(shù)據(jù)集的變化,否則返回的只是變化預(yù)覽

#將行索引重設(shè)為變量
Freq_df.reset_index(inplace=True)
#重新查看數(shù)據(jù)框
Freq_df.head()

四汞舱、字符與日期數(shù)據(jù)的處理

如何基于數(shù)據(jù)框操作字符型變量伍纫,以及有關(guān)日期型數(shù)據(jù)的處理,例如如何從日期型變量中取出年份昂芜、月份莹规、星期幾等,如何計(jì)算兩個(gè)日期間的時(shí)間差

df=pd.read_excel("F:\data_test03.xlsx")
#查看數(shù)據(jù)前五行
df.head()
#查看數(shù)據(jù)類型
df.dtypes

下面修改生日birthday為日期型泌神,電話號(hào)碼tel為字符串

#修改birthday
df.birthday=pd.to_datetime(df.birthday,format="%Y/%m/%d")
#修改tel
df.tel=df.tel.astype("str")
#重新查看數(shù)據(jù)類型
df.dtypes

對(duì)于年齡和工齡的計(jì)算良漱,需要將當(dāng)前日期與出生日期和開始工作日期作減法運(yùn)算,而當(dāng)前日期的獲得欢际,則使用了Pandas子模塊datetime中的today函數(shù)母市。由于計(jì)算的是相隔的年數(shù),所以還需進(jìn)一步取出日期中的年份dt.year

#根據(jù)出生日期新增年齡
df["age"]=pd.datetime.today().year-df.birthday.dt.year
#根據(jù)開始工作日期新增工齡
df["workage"]=pd.datetime.today().year-df.start_work.dt.year

將手機(jī)號(hào)tel的中間四位隱藏起來幼苛,是字符串中的替換法(replace),由于替換法所處理的對(duì)象都是變量中的每一個(gè)觀測窒篱,屬于重復(fù)性工作,所以考慮使用序列的apply方法舶沿。需要注意的是墙杯,apply方法中的func參數(shù),都是使用匿名函數(shù)括荡,對(duì)于隱藏手機(jī)號(hào)中間四位的思路就是用星號(hào)替換手機(jī)號(hào)的中間四位

#隱藏電話號(hào)碼中間4位
df.tel = df.tel.apply(func = lambda x : x.replace(x[3:7],"****"))

對(duì)于郵箱域名的獲取高镐,是字符串中的分割法(split),其思路就是按照郵箱中的@符風(fēng)格畸冲,然后取出第二個(gè)元素(即列表索引為1)

#取出郵箱域名,新增一列
df["email_domain"]=df.email.apply(func = lambda x: x.split("@")[1])

從other變量中獲取人員的專業(yè)信息嫉髓,使用了字符串的正則表達(dá)式,不管是字符串“方法”還是字符串正則邑闲,在使用前都需要對(duì)變量使用一次str方法算行。findall是匹配查詢函數(shù),然后正則符號(hào)(.*?)用于分組苫耸,默認(rèn)返回括號(hào)內(nèi)的匹配內(nèi)容

# 取出人員的專業(yè)信息
df['profession'] = df.other.str.findall('專業(yè):(.*?)州邢,')

刪除數(shù)據(jù)集中的某些變量,可以使用數(shù)據(jù)框的drop方法褪子。該方法接受的第一個(gè)參數(shù)就是被刪除的變量列表量淌,尤其要注意的是骗村,需要將axis參數(shù)設(shè)置為1,因?yàn)槟籨rop方法是用來刪除數(shù)據(jù)框中的行記錄

# 去除birthday呀枢、start_work和other變量
df.drop(['birthday','start_work','other'], axis = 1, inplace = True)
#重新查看前五行
df.head()

針對(duì)日期型數(shù)據(jù)羅列一些常用的“方法”:


五胚股、常用的數(shù)據(jù)清洗方法

數(shù)據(jù)集是否存在重復(fù)、是否存在缺失、數(shù)據(jù)是否具有完整性和一致性、數(shù)據(jù)中是否存在異常值等

1.重復(fù)觀測處理

df=pd.read_excel("F:\data_test04.xlsx")
#查看數(shù)據(jù)
df

any函數(shù)表示的是在多個(gè)條件判斷中,只要有一個(gè)條件為True,則any函數(shù)的結(jié)果就為True

#檢測是否有重復(fù)觀測
any(df.duplicated())

刪除重復(fù)項(xiàng)满钟,nplace=True就表示直接在原始數(shù)據(jù)集上作操作

# 刪除重復(fù)項(xiàng)
df.drop_duplicates(inplace = True)
df

原先的10行觀測,盡管排重后得到7行觀測谷浅,被刪除的行號(hào)為3秘血、8和9、

2.缺失值處理

導(dǎo)致觀測的缺失可能有兩方面原因紧唱,一方面是人為原因(如記錄過程中的遺漏活尊、個(gè)人隱私而不愿透露等),另一方面是機(jī)器或設(shè)備的故障所導(dǎo)致(如斷電或設(shè)備老化等原因)漏益。

一般而言蛹锰,當(dāng)遇到缺失值(Python中用NaN表示)時(shí),可以采用三種方法處置绰疤,分別是刪除法铜犬、替換法和插補(bǔ)法。刪除法是指當(dāng)缺失的觀測比例非常低時(shí)(如5%以內(nèi))轻庆,直接刪除存在缺失的觀測癣猾,或者當(dāng)某些變量的缺失比例非常高時(shí)(如85%以上),直接刪除這些缺失的變量余爆;替換法是指用某種常數(shù)直接替換那些缺失值纷宇,例如,對(duì)連續(xù)變量而言蛾方,可以使用均值或中位數(shù)替換像捶,對(duì)于離散變量,可以使用眾數(shù)替換桩砰;插補(bǔ)法是指根據(jù)其他非缺失的變量或觀測來預(yù)測缺失值拓春,常見的插補(bǔ)法有回歸插補(bǔ)法、K近鄰插補(bǔ)法亚隅、拉格朗日插補(bǔ)法等硼莽。

CASE1:刪除法

df=pd.read_excel("F:\data_test05.xlsx")
#查看是否有缺失數(shù)據(jù)
any(df.isnull())

分別使用兩種方法實(shí)現(xiàn)數(shù)據(jù)集中缺失值的處理,行刪除法枢步,即將所有含缺失值的行記錄全部刪除沉删,使用dropna方法渐尿;變量刪除法,由于原數(shù)據(jù)集中age變量的缺失值最多矾瑰,所以使用drop方法將age變量刪除

#行刪除法
df.dropna()
#變量刪除法
df.drop("age",axis=1)

CASE2:替換法
缺失值的替換需要借助于fillna方法砖茸,該方法中的method參數(shù),可以接受'ffill'和'bfill'兩種值殴穴,分別代表前向填充和后向填充凉夯。前向填充是指用缺失值的前一個(gè)值替換(如左圖所示),而后向填充則表示用缺失值的后一個(gè)值替換(如右圖所示)采幌。右圖中的最后一個(gè)記錄仍包含缺失值劲够,是因?yàn)楹笙蛱畛浞ㄕ也坏皆撊笔е档暮笠粋€(gè)值用于替換。在作者看來休傍,缺失值的前向填充或后向填充一般適用于時(shí)間序列型的數(shù)據(jù)集征绎,因?yàn)檫@樣的數(shù)據(jù)前后具有連貫性,而一般的獨(dú)立性樣本并不適用該方法磨取。

# 替換法之前向替換
df.fillna(method = 'ffill')
# 替換法之后向替換
df.fillna(method = 'bfill')

另一種替換手段人柿,仍然是使用fillna方法,只不過不再使用method參數(shù)忙厌,而是使用value參數(shù)凫岖。使用一個(gè)常數(shù)0替換所有的缺失值。

#使用常數(shù)0替換
df.fillna(value=0)

或者采用更加靈活的替換方法逢净,即分別對(duì)各缺失變量使用不同的替換值(需要采用字典的方式傳遞給value參數(shù))哥放,性別使用眾數(shù)替換,年齡使用均值替換爹土,收入使用中位數(shù)替換甥雕。

#使用統(tǒng)計(jì)值替換
df.fillna(value={'gender':df.gender.mode()[0], 'age':df.age.mean(), 'income':df.income.median()})

需要說明的是,如上代碼并沒有實(shí)際改變df數(shù)據(jù)框的結(jié)果着饥,因?yàn)閐ropna犀农、drop和fillna方法并沒有使inplace參數(shù)設(shè)置為True。讀者可以在實(shí)際的學(xué)習(xí)和工作中挑選一個(gè)適當(dāng)?shù)娜笔е堤幚矸椒ㄔ椎簦缓髮⒃摲椒ㄖ械膇nplace參數(shù)設(shè)置為True呵哨,進(jìn)而可以真正的改變你所處理的數(shù)據(jù)集。

3.異常值處理

異常值是指那些遠(yuǎn)離正常值的觀測轨奄,即“不合群”觀測孟害。導(dǎo)致異常值的出現(xiàn)一般是人為的記錄錯(cuò)誤或者是設(shè)備的故障等,異常值的出現(xiàn)會(huì)對(duì)模型的創(chuàng)建和預(yù)測產(chǎn)生嚴(yán)重的后果挪拟。當(dāng)然異常值也不一定都是壞事挨务,有些情況下,通過尋找異常值就能夠給業(yè)務(wù)帶來良好的發(fā)展,如銷毀“釣魚”網(wǎng)站谎柄、關(guān)閉“薅羊毛”用戶的權(quán)限等丁侄。

對(duì)于異常值的檢測,一般采用兩種方法:
一種是n個(gè)標(biāo)準(zhǔn)差法朝巫,標(biāo)準(zhǔn)差法的判斷公式是outlinear>|x ?±nσ|鸿摇,其中x ?為樣本均值,σ為樣本標(biāo)準(zhǔn)差劈猿,當(dāng)n=2時(shí)拙吉,滿足條件的觀測就是異常值,當(dāng)n=3時(shí)揪荣,滿足條件的觀測就是極端異常值筷黔;
另一種是箱線圖判別法,箱線圖的判斷公式是outlinear>Q3+ nIQR或者outlinear<Q1- nIQR仗颈,其中Q1為下四分位數(shù)(25%)佛舱,Q3為上四位數(shù)(75%),IQR為四分位差(上四分位數(shù)與下四分位數(shù)的差)揽乱,當(dāng)n=1.5時(shí)名眉,滿足條件的觀測為異常值粟矿,當(dāng)n=3時(shí)凰棉,滿足條件的觀測即為極端異常值。



這兩種方法的選擇標(biāo)準(zhǔn)如下陌粹,如果數(shù)據(jù)近似服從正態(tài)分布時(shí)撒犀,優(yōu)先選擇n個(gè)標(biāo)準(zhǔn)差法,因?yàn)閿?shù)據(jù)的分布相對(duì)比較對(duì)稱掏秩;否則優(yōu)先選擇箱線圖法或舞,因?yàn)榉治粩?shù)并不會(huì)受到極端值的影響。當(dāng)數(shù)據(jù)存在異常時(shí)蒙幻,一般可以使用刪除法將異常值刪除(前提是異常觀測的比例不能太大)映凳、替換法(可以考慮使用低于判別上限的最大值或高于判別下限的最小值替換、使用均值或中位數(shù)替換等)邮破。

sun=pd.read_table("F:\sunspots.csv",sep=",")
sun.head()
# 異常值檢測之標(biāo)準(zhǔn)差法
xbar = sunspots.counts.mean()
xstd = sunspots.counts.std()
print('標(biāo)準(zhǔn)差法異常值上限檢測:\n',any(sunspots.counts > xbar + 2 * xstd))
print('標(biāo)準(zhǔn)差法異常值下限檢測:\n',any(sunspots.counts < xbar - 2 * xstd))
# 異常值檢測之箱線圖法
Q1 = sunspots.counts.quantile(q = 0.25)
Q3 = sunspots.counts.quantile(q = 0.75)
IQR = Q3 - Q1
print('箱線圖法異常值上限檢測:\n',any(sunspots.counts > Q3 + 1.5 * IQR))
print('箱線圖法異常值下限檢測:\n',any(sunspots.counts < Q1 - 1.5 * IQR))

不管是標(biāo)準(zhǔn)差檢驗(yàn)法還是箱線圖檢驗(yàn)法诈豌,都發(fā)現(xiàn)太陽黑子數(shù)據(jù)中存在異常值,而且異常值都是超過上限臨界值的抒和。

接下來矫渔,通過繪制太陽黑子數(shù)量的直方圖和核密度曲線圖,用于檢驗(yàn)數(shù)據(jù)是否近似服從正態(tài)分布摧莽,進(jìn)而選擇一個(gè)最終的異常值判別方法:

#導(dǎo)入繪圖模塊
import matplotlib.pyplot as plt
#設(shè)置繪圖風(fēng)格
plt.style.use("ggplot")
#繪制直方圖
sun.counts.plot(kind="hist",bins=30,normed=True)
#繪制核密度圖
sun.counts.plot(kind="kde")
#圖形展現(xiàn)
plt.show()

不管是直方圖還是核密度曲線庙洼,所呈現(xiàn)的數(shù)據(jù)分布形狀都是有偏的,并且屬于右偏∮凸唬基于此蚁袭,這里就選擇箱線圖法用以判定太陽黑子數(shù)據(jù)中的那些異常值。接下來要做的就是選用刪除法或替換法來處理這些異常值

此處使用低于判別上限的最大值或高于判別下限的最小值替換

# 箱線圖中的異常值判別上限
UL = Q3 + 1.5 * IQR
print('判別異常值的上限臨界值:\n',UL)
# 從數(shù)據(jù)中找出低于判別上限的最大值
replace_value = sun.counts[sun.counts < UL].max()
print('用以替換異常值的數(shù)據(jù):\n',replace_value)
# 替換超過判別上限異常值
sun.counts[sun.counts > UL] = replace_value

如果使用箱線圖法判別異常值石咬,則認(rèn)定太陽黑子數(shù)目一年內(nèi)超過148.85時(shí)即認(rèn)為是異常值年份撕阎,對(duì)于這些年份的異常值使用141.7替換。

六碌补、數(shù)據(jù)子集的獲取

通常虏束,在Pandas模塊中實(shí)現(xiàn)數(shù)據(jù)框子集的獲取可以使用iloc、loc和ix三種“方法”厦章,這三種方法既可以對(duì)數(shù)據(jù)行作篩選镇匀,也可以實(shí)現(xiàn)變量的挑選,它們的語法可以表示成[rows_select, cols_select]袜啃。

iloc只能通過行號(hào)和列號(hào)進(jìn)行數(shù)據(jù)的篩選汗侵,讀者可以將iloc中的“i”理解為“integer”,即只能向[rows_select, cols_select]指定整數(shù)列表群发。該索引方式與數(shù)組的索引方式類似晰韵,都是從0開始、可以間隔取號(hào)熟妓、對(duì)于切片仍然無法取到上限雪猪。

loc要比iloc靈活一些,讀者可以將loc中的“l(fā)”理解為“l(fā)abel”起愈,即可以向[rows_select, cols_select]指定具體的行標(biāo)簽(行名稱)和列標(biāo)簽(字段名)只恨,注意,這里是標(biāo)簽不再是索引抬虽。而且官觅,還可以將rows_select指定為具體的篩選條件,在iloc中是無法做到的阐污。

ix是iloc和loc的混合休涤,讀者可以將ix理解為“mix”,該“方法”吸收了iloc和loc的優(yōu)點(diǎn)笛辟,使數(shù)據(jù)框子集的獲取更加的靈活功氨。

1.原始數(shù)據(jù)的行號(hào)與行標(biāo)簽(名稱)一致

# 構(gòu)造數(shù)據(jù)集
df1 = pd.DataFrame({'name':['張三','李四','王二','丁一','李五'], 
                    'gender':['男','女','女','女','男'], 
                    'age':[23,26,22,25,27]}, columns = ['name','gender','age'])
df

取出數(shù)據(jù)集中間三行,并且返回姓名和年齡指定的兩列
①iloc即索引的方法

df1.iloc[1:4,[0,2]]

②loc不再是索引隘膘,直接對(duì)應(yīng)行名稱

df1.loc[1:3, ['name','age']]

③ix效果同loc疑故,但對(duì)變量名的篩選可用列號(hào)也可用具體變量名稱

df1.ix[1:3,[0,2]]
#或者
df1.ix[1:3,['name','age']]

2.原始數(shù)據(jù)的行號(hào)與行標(biāo)簽(名稱)不一致/沒有行號(hào)

# 將員工的姓名用作行標(biāo)簽
df2 = df1.set_index('name')
df2

取出數(shù)據(jù)集的中間三行
①iloc即索引的方法

df2.iloc[1:4,:]

②loc使用行標(biāo)簽,不可再寫行號(hào)

df2.loc[['李四','王二','丁一'],:]

③ix此時(shí)同iloc

df2.ix[1:4,:]

3.取出所有男性的性別和年齡

對(duì)某些列做條件篩選弯菊,只能使用loc和ix

df1.loc[df1.gender == '男',['name','age']]
df1.ix[df1.gender == '男',['name','age']]

七纵势、透視表功能

pd.pivot_table(data, values=None, index=None, columns=None, 
               aggfunc='mean', fill_value=None, margins=False, 
               dropna=True, margins_name='All')

data:指定需要構(gòu)造透視表的數(shù)據(jù)集踱阿;
values:指定需要拉入“數(shù)值”框的字段列表;
index:指定需要拉入“行標(biāo)簽”框的字段列表钦铁;
columns:指定需要拉入“列標(biāo)簽”框的字段列表软舌;
aggfunc:指定數(shù)值的統(tǒng)計(jì)函數(shù),默認(rèn)為統(tǒng)計(jì)均值牛曹,也可以指定Numpy模塊中的其他統(tǒng)計(jì)函數(shù)佛点;
fill_value:指定一個(gè)標(biāo)量,用于填充缺失值黎比;
margins:bool類型參數(shù)超营,是否需要顯示行或列的總計(jì)值,默認(rèn)為False阅虫;
dropna:bool類型參數(shù)演闭,是否需要?jiǎng)h除整列為缺失的字段,默認(rèn)為True颓帝;
margins_name:指定行或列的總計(jì)名稱米碰,默認(rèn)為All;

1.單個(gè)分組變量的均值統(tǒng)計(jì)

基于單個(gè)分組變量color的匯總統(tǒng)計(jì)(price的均值)

diamonds=pd.read_table("F:\diamonds.csv",sep=",")
diamonds.head()
# 單個(gè)分組變量的均值統(tǒng)計(jì)
pd.pivot_table(data = diamonds, index = 'color', values = 'price', margins = True, margins_name = '總計(jì)')

2.兩個(gè)分組變量的列聯(lián)表

對(duì)于列聯(lián)表來說购城,行和列都需要指定某個(gè)分組變量吕座,所以index參數(shù)和columns參數(shù)都需要指定一個(gè)分組變量。并且統(tǒng)計(jì)的不再是某個(gè)變量的均值瘪板,而是觀測個(gè)數(shù)吴趴,所以aggfunc參數(shù)需要指定numpy模塊中的size函數(shù)。通過這樣的參數(shù)設(shè)置

# 兩個(gè)分組變量的列聯(lián)表
# 導(dǎo)入numpy模塊
import numpy as np
pd.pivot_table(data = diamonds, index = 'clarity', columns = 'cut', values = 'carat', 
               aggfunc = np.size,margins = True, margins_name = '總計(jì)')

八篷帅、表之間的合并和連接

對(duì)于多表之間的縱向合并史侣,則必須確保多表的列數(shù)和數(shù)據(jù)類型一致;對(duì)于多表之間的水平擴(kuò)展魏身,則必須保證多表要有共同的匹配字段。Pandas模塊同樣提供了關(guān)于多表之間的合并和連接操作函數(shù)蚪腐,分別是concat函數(shù)和merge函數(shù)箭昵。

1.合并函數(shù)concat

pd.concat(objs, axis=0, join='outer', join_axes=None, ignore_index=False, keys=None)

objs:指定需要合并的對(duì)象,可以是序列回季、數(shù)據(jù)框或面板數(shù)據(jù)構(gòu)成的列表家制;
axis:指定數(shù)據(jù)合并的軸,默認(rèn)為0泡一,表示合并多個(gè)數(shù)據(jù)的行颤殴,如果為1,則表示合并多個(gè)數(shù)據(jù)的列鼻忠;
join:指定合并的方式涵但,默認(rèn)為outer,表示合并所有數(shù)據(jù),如果改為inner矮瘟,表示合并公共部分的數(shù)據(jù)瞳脓;
join_axes:合并數(shù)據(jù)后,指定保留的數(shù)據(jù)軸澈侠;
ignore_index:bool類型的參數(shù)劫侧,表示是否忽略原數(shù)據(jù)集的索引,默認(rèn)為False哨啃,如果設(shè)為True烧栋,則表示忽略原索引并生成新索引;
keys:為合并后的數(shù)據(jù)添加新索引拳球,用于區(qū)分各個(gè)數(shù)據(jù)部分劲弦;

# 構(gòu)造數(shù)據(jù)集df1和df2
df1 = pd.DataFrame({'name':['張三','李四','王二'], 'age':[21,25,22], 'gender':['男','女','男']})
df2 = pd.DataFrame({'name':['丁一','趙五'], 'age':[23,22], 'gender':['女','女']})
# 數(shù)據(jù)集的縱向合并
pd.concat([df1,df2] , keys = ['df1','df2'])

為了區(qū)分合并后的df1數(shù)據(jù)集和df2數(shù)據(jù)集,代碼中的concat函數(shù)使用了keys參數(shù)醇坝,如果再設(shè)置參數(shù)ignore_index為True邑跪,此時(shí)keys參數(shù)將不再有效

pd.concat([df1,df2] , keys = ['df1','df2'],ignore_index=True)

2.連接函數(shù)merge

函數(shù)的最大缺點(diǎn)是,每次只能操作兩張數(shù)據(jù)表的連接呼猪,如果有n張表需要連接画畅,則必須經(jīng)過n-1次的merge函數(shù)使用

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'))

left:指定需要連接的主表;
right:指定需要連接的輔表宋距;
how:指定連接方式轴踱,默認(rèn)為inner內(nèi)連,還有其他選項(xiàng)谚赎,如左連left淫僻、右連right和外連outer;
on:指定連接兩張表的共同字段壶唤;
left_on:指定主表中需要連接的共同字段雳灵;
right_on:指定輔表中需要連接的共同字段;
left_index:bool類型參數(shù)闸盔,是否將主表中的行索引用作表連接的共同字段悯辙,默認(rèn)為False;
right_index:bool類型參數(shù)迎吵,是否將輔表中的行索引用作表連接的共同字段躲撰,默認(rèn)為False;
sort:bool類型參數(shù)击费,是否對(duì)連接后的數(shù)據(jù)按照共同字段排序拢蛋,默認(rèn)為False
suffixes:如果數(shù)據(jù)連接的結(jié)果中存在重疊的變量名,則使用各自的前綴進(jìn)行區(qū)分蔫巩;

# 構(gòu)造數(shù)據(jù)集
df3 = pd.DataFrame({'id':[1,2,3,4,5],'name':['張三','李四','王二','丁一','趙五'],'age':[27,24,25,23,25],'gender':['男','男','男','女','女']})
df4 = pd.DataFrame({'Id':[1,2,2,4,4,4,5],'kemu':['科目1','科目1','科目2','科目1','科目2','科目3','科目1'],'score':[83,81,87,75,86,74,88]})
df5 = pd.DataFrame({'id':[1,3,5],'name':['張三','王二','趙五'],'income':[13500,18000,15000]})
# 三表的數(shù)據(jù)連接
# 首先df3和df4連接
merge1 = pd.merge(left = df3, right = df4, how = 'left', left_on='id', right_on='Id')
merge1
# 再將連接結(jié)果與df5連接
merge2 = pd.merge(left = merge1, right = df5, how = 'left')
merge2

如果需要將這三張表橫向擴(kuò)展到一張寬表中谆棱,需要經(jīng)過兩次的merge操作快压。如上代碼所示,第一次merge連接了df3和df4础锐,由于兩張表的共同字段不一致嗓节,所以需要分別指定left_on和right_on的參數(shù)值;第二次merge連接了首次的結(jié)果和df5皆警,此時(shí)并不需要指定left_on和right_on參數(shù)拦宣,是因?yàn)榈谝淮蔚膍erge結(jié)果就包含了id變量,所以merge時(shí)會(huì)自動(dòng)挑選完全一致的變量用于表連接信姓。

九鸵隧、分組聚合操作

在數(shù)據(jù)庫中還有一種非常常見的操作就是分組聚合,即根據(jù)某些個(gè)分組變量意推,對(duì)數(shù)值型變量進(jìn)行分組統(tǒng)計(jì)豆瘫。以珠寶數(shù)據(jù)為例,統(tǒng)計(jì)各顏色和刀工組合下的珠寶數(shù)量菊值、最小x外驱、平均價(jià)格和最大深度

需結(jié)合使用Pandas模塊中的groupby“方法”和aggregate“方法”

使用Pandas實(shí)現(xiàn)分組聚合需要分兩步走,第一步是指定分組變量腻窒,可以通過數(shù)據(jù)框的groupby“方法”完成昵宇;第二步是對(duì)不同的數(shù)值變量計(jì)算各自的統(tǒng)計(jì)值,在第二步中儿子,需要跟讀者說明的是瓦哎,必須以字典的形式控制變量名稱和統(tǒng)計(jì)函數(shù)

# 通過groupby方法,指定分組變量
grouped = diamonds.groupby(by = ['color','cut'])
# 對(duì)分組變量進(jìn)行統(tǒng)計(jì)匯總
result = grouped.aggregate({'color':np.size, 'x':np.min, 'price':np.mean, 'depth':np.max})
result

....

# 數(shù)據(jù)集重命名
result.rename(columns={'color':'counts','x':'min_x','price':'avg_price','depth':'max_depth'}, inplace=True)
result

...
分組變量color和cut成了數(shù)據(jù)框的行索引柔逼。如果需要將這兩個(gè)行索引轉(zhuǎn)換為數(shù)據(jù)框的變量名蒋譬,可以使用數(shù)據(jù)框的reset_index方法

# 將行索引變量數(shù)據(jù)框的變量
result.reset_index(inplace=True)
result

...

總結(jié)

pandas模塊

Series  生成序列類型的函數(shù)
DataFrame   生成數(shù)據(jù)框類型的函數(shù)
read_table  讀取文本文件的函數(shù),如txt愉适、csv等
read_csv    讀取文本文件的函數(shù)犯助,如txt、csv等
read_excel  讀取電子表格的函數(shù)

pymysql/pmssql模塊

connect 數(shù)據(jù)庫與Python的連接函數(shù)
close   關(guān)閉數(shù)據(jù)庫與Python之間連接的“方法”

pandas模塊

read_sql    讀取數(shù)據(jù)庫數(shù)據(jù)的函數(shù)
head/tail   顯示數(shù)據(jù)框首/末幾行的“方法”
shape   返回?cái)?shù)據(jù)框行列數(shù)的“方法”
dtypes  返回?cái)?shù)據(jù)框中各變量數(shù)據(jù)類型的“方法”
to_datetime 將變量轉(zhuǎn)換為日期時(shí)間型的函數(shù)
astype  將變量轉(zhuǎn)換為其他類型的“方法”
describe    統(tǒng)計(jì)性描述的“方法”
columns 返回?cái)?shù)據(jù)框變量名的“方法”
index   返回?cái)?shù)據(jù)框行索引的“方法”
apply   序列或數(shù)據(jù)框的映射“方法”
value_counts    序列值頻次統(tǒng)計(jì)的“方法”
reset_index 將行索引轉(zhuǎn)換為變量的“方法”
duplicated  檢驗(yàn)觀測是否重復(fù)的“方法”
drop_duplicates 刪除重復(fù)項(xiàng)的“方法”
drop    刪除變量名或觀測的“方法”
dropna  刪除缺失值的“方法”
fillna  填充缺失值的“方法”
quantile    統(tǒng)計(jì)序列分位數(shù)的“方法”
plot    序列或數(shù)據(jù)框的繪圖“方法”
iloc/loc/ix 數(shù)據(jù)框子集獲取的“方法”
pivot_table 構(gòu)建透視表的函數(shù)
concat  實(shí)現(xiàn)多表縱向合并的函數(shù)
merge   實(shí)現(xiàn)兩表水平擴(kuò)展的函數(shù)
groupby 分組聚合時(shí)儡毕,指定分組變量的“方法”
aggregate   指定聚合統(tǒng)計(jì)的“方法”
rename  修改數(shù)據(jù)框變量名的“方法”
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末也切,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子腰湾,更是在濱河造成了極大的恐慌,老刑警劉巖疆股,帶你破解...
    沈念sama閱讀 217,406評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件费坊,死亡現(xiàn)場離奇詭異,居然都是意外死亡旬痹,警方通過查閱死者的電腦和手機(jī)附井,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,732評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門讨越,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人永毅,你說我怎么就攤上這事把跨。” “怎么了沼死?”我有些...
    開封第一講書人閱讀 163,711評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵着逐,是天一觀的道長。 經(jīng)常有香客問我意蛀,道長耸别,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,380評(píng)論 1 293
  • 正文 為了忘掉前任县钥,我火速辦了婚禮秀姐,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘若贮。我一直安慰自己省有,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,432評(píng)論 6 392
  • 文/花漫 我一把揭開白布谴麦。 她就那樣靜靜地躺著蠢沿,像睡著了一般。 火紅的嫁衣襯著肌膚如雪细移。 梳的紋絲不亂的頭發(fā)上搏予,一...
    開封第一講書人閱讀 51,301評(píng)論 1 301
  • 那天,我揣著相機(jī)與錄音弧轧,去河邊找鬼雪侥。 笑死,一個(gè)胖子當(dāng)著我的面吹牛精绎,可吹牛的內(nèi)容都是我干的速缨。 我是一名探鬼主播,決...
    沈念sama閱讀 40,145評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼代乃,長吁一口氣:“原來是場噩夢啊……” “哼旬牲!你這毒婦竟也來了罪佳?” 一聲冷哼從身側(cè)響起遂黍,我...
    開封第一講書人閱讀 39,008評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎叛氨,沒想到半個(gè)月后堕仔,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體擂橘,經(jīng)...
    沈念sama閱讀 45,443評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,649評(píng)論 3 334
  • 正文 我和宋清朗相戀三年摩骨,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了通贞。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片朗若。...
    茶點(diǎn)故事閱讀 39,795評(píng)論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖昌罩,靈堂內(nèi)的尸體忽然破棺而出哭懈,到底是詐尸還是另有隱情,我是刑警寧澤茎用,帶...
    沈念sama閱讀 35,501評(píng)論 5 345
  • 正文 年R本政府宣布遣总,位于F島的核電站,受9級(jí)特大地震影響绘搞,放射性物質(zhì)發(fā)生泄漏彤避。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,119評(píng)論 3 328
  • 文/蒙蒙 一夯辖、第九天 我趴在偏房一處隱蔽的房頂上張望琉预。 院中可真熱鬧,春花似錦蒿褂、人聲如沸圆米。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,731評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽娄帖。三九已至,卻和暖如春昙楚,著一層夾襖步出監(jiān)牢的瞬間近速,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,865評(píng)論 1 269
  • 我被黑心中介騙來泰國打工堪旧, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留削葱,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,899評(píng)論 2 370
  • 正文 我出身青樓淳梦,卻偏偏與公主長得像析砸,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子爆袍,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,724評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容