一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

轉(zhuǎn)的數(shù)據(jù)分析相關(guān)的內(nèi)容

 印度阿三17 2019-04-24

?

我們離不開數(shù)據(jù)分析

首先,非常感謝你訂閱了這場(chǎng) chat, 我會(huì)努力準(zhǔn)備,用心書寫,將我過(guò)去的項(xiàng)目經(jīng)歷、學(xué)習(xí)心得,一五一十地、毫無(wú)保留地記錄下來(lái)。并且,我會(huì)盡力寫的通俗易懂,邏輯更有條理一些。不出意外,我還會(huì)反復(fù)修改多次,直到做到最好。

相信訂閱本場(chǎng) chat 的小伙伴中,有的已經(jīng)工作了,可能平時(shí)還要經(jīng)常加班。和你們一樣,我也工作 5 年了,也是經(jīng)常加班。不過(guò),我會(huì)每天抽時(shí)間,寫點(diǎn)技術(shù)文章,也不知怎么地,只有這樣,我才覺得一天過(guò)得充實(shí),才覺得沒有虛度。

最近幾年,做的這些項(xiàng)目,大多與數(shù)據(jù)分析與算法應(yīng)用相關(guān)。崗位雖然是算法工程師,但是與數(shù)據(jù)分析打得交道也很多,雙管齊下,最后才能確保算法的落地。在幾年前,我還想當(dāng)然地認(rèn)為做算法的就應(yīng)該偏重算法研究與應(yīng)用,可能數(shù)據(jù)分析相關(guān)的技術(shù)真的沒那么重要,不過(guò)我很快意識(shí)到自己的錯(cuò)誤,重新將數(shù)據(jù)分析放在一個(gè)重要的位置,去研究學(xué)習(xí)。

結(jié)合過(guò)往經(jīng)歷,說(shuō)下自己對(duì)算法設(shè)計(jì)和數(shù)據(jù)分析工作的一些淺顯體會(huì)。

對(duì)于算法落地而言,個(gè)人認(rèn)為準(zhǔn)確性和穩(wěn)定性是最重要的。在校園時(shí),相信老師都跟我們講過(guò)算法的幾個(gè)重要性質(zhì),比如算法的時(shí)間復(fù)雜度,空間復(fù)雜度,魯棒性等等,都具備了這些性質(zhì)的算法當(dāng)然是一個(gè)好算法。

然而,實(shí)際情況是,實(shí)際場(chǎng)景往往比較復(fù)雜,比如,影響因素及之間的關(guān)系很復(fù)雜;數(shù)據(jù)匱乏不說(shuō),手上的數(shù)據(jù)還有一半是垃圾等等,這一系列難點(diǎn),都加大了我們算法設(shè)計(jì)的難度,哪怕只是設(shè)計(jì)一個(gè)滿足基本場(chǎng)景的算法。這使我明白,設(shè)計(jì)的算法要優(yōu)先保證能得到一個(gè)正確的結(jié)果。

其次,作為工程項(xiàng)目,確保系統(tǒng)的穩(wěn)定性,盡量或者上線后基本沒有 bug 顯得同樣重要。否則,你連覺都睡不好,還提什么其他性能。所以為了穩(wěn)妥起見,大部分算法設(shè)計(jì)都不會(huì)從零做起,大都會(huì)基于成熟穩(wěn)定的開源框架,然后在上面擴(kuò)展,開花結(jié)果。

已經(jīng)說(shuō)的很直白了,還沒有工作的小伙伴,可以思考一下。光鮮的事物背后,未必有它真正看起來(lái)那樣的光彩奪目。

人工智能的強(qiáng)大離不開數(shù)據(jù),既然離不開數(shù)據(jù),自然就少不了數(shù)據(jù)處理與分析的相關(guān)技術(shù),那么公司就一定需要數(shù)據(jù)處理與分析的人員。

數(shù)據(jù)分析為啥如此重要呢? 一句話,喂進(jìn)去的是垃圾,出來(lái)的就是垃圾。機(jī)器學(xué)習(xí)、深度學(xué)習(xí)的算法設(shè)計(jì)的再牛叉,如果進(jìn)去的是垃圾數(shù)據(jù),深度學(xué)習(xí)學(xué)出來(lái)的模型也不會(huì)好到哪里去。

所以,數(shù)據(jù)科學(xué)相關(guān)的技術(shù),工作中是離不開的,未來(lái)只會(huì)越來(lái)越重要。

說(shuō)完我的一些體會(huì)后,我簡(jiǎn)單引出一個(gè)文章展開的思路。

作為數(shù)據(jù)分析的入門課程,首先說(shuō)一下入門數(shù)據(jù)科學(xué)的完整學(xué)習(xí)路線;然后,介紹數(shù)據(jù)分析中花費(fèi)時(shí)間較多的:數(shù)據(jù)清理 (data munging);

學(xué)習(xí)路線、主要任務(wù)介紹完后,接下來(lái)就要開始動(dòng)手實(shí)踐、實(shí)現(xiàn)這些任務(wù)了。Python 作為數(shù)據(jù)分析和人工智能的首選語(yǔ)言,介紹關(guān)于它的一些核心知識(shí),讓幫助入門者快速上手。

為了工作中加速數(shù)據(jù)分析的腳步,依次介紹基于 Python 的科學(xué)計(jì)算庫(kù) NumPy, Pandas, 要想快速上手這些庫(kù),理解它們的機(jī)制是必不可少的,比如 NumPy 的廣播機(jī)制。數(shù)據(jù)分析的另一個(gè)重要任務(wù)就是數(shù)據(jù)可視化,接下來(lái),介紹基于 Python 生態(tài)的可視化庫(kù):Matplotlib, 使用 100 行左右的代碼,來(lái)打包常用的函數(shù)用法。

數(shù)據(jù)分析往往需要做一些回歸分析,分類分析等,作為目前火熱的機(jī)器學(xué)習(xí)、深度學(xué)習(xí),我們通過(guò)一個(gè)經(jīng)典的回歸算法,深刻明白其原理,知道公式推導(dǎo),手寫實(shí)現(xiàn)它。

學(xué)習(xí)這些理論和工具的同時(shí),你也需要開始實(shí)戰(zhàn)了。為此,我們選用哈佛大學(xué)的數(shù)據(jù)分析課,它是開源的,并且授課所用數(shù)據(jù)全部來(lái)自實(shí)際場(chǎng)景,算是最大貼近你的實(shí)際工作日常了,可謂干貨十足!

接下來(lái),你可以去尋找數(shù)據(jù)分析、機(jī)器學(xué)習(xí)相關(guān)的工作了。作為全面的學(xué)習(xí)路線,我還非常用心地為小伙伴們,準(zhǔn)備了 2 個(gè)數(shù)據(jù)分析、機(jī)器學(xué)習(xí)相關(guān)的真實(shí)面試經(jīng)歷。

讓我們開始數(shù)據(jù)分析的學(xué)習(xí)之旅吧!

數(shù)據(jù)分析入門學(xué)習(xí)路線

在開始介紹學(xué)習(xí)路線之前,我想告訴大家,本篇 chat 展開提綱中,已經(jīng)包括了數(shù)據(jù)分析知識(shí)的主要部分,因此,大家應(yīng)該已經(jīng)有一個(gè)大概輪廓了。

每個(gè)人學(xué)習(xí)一門新知識(shí)前,大都想去了解下這門知識(shí)的學(xué)習(xí)思路是怎樣的,都有哪些知識(shí)是必須要學(xué)的。所以,我們也只去論述關(guān)于數(shù)據(jù)分析,那些必須要學(xué)習(xí)的知識(shí),也就是學(xué)好數(shù)據(jù)分析的必備技能。

1.1 統(tǒng)計(jì)學(xué)基本知識(shí)

首先,入門數(shù)據(jù)分析需要必備一些統(tǒng)計(jì)學(xué)的基本知識(shí),在這里我們簡(jiǎn)單列舉幾個(gè)入門級(jí)的重要概念。概率,平均值,中位數(shù),眾數(shù),四分位數(shù),期望,標(biāo)準(zhǔn)差,方差。在這些基本概念上,又衍生出的很多重要概念,比如協(xié)方差,相關(guān)系數(shù)等。

這一些列常用的統(tǒng)計(jì)指標(biāo),都在強(qiáng)大的數(shù)據(jù)分析包 Pandas 中實(shí)現(xiàn)了,非常方便,在下面的 Pandas 介紹章節(jié),會(huì)詳細(xì)列出。

我們看下概率的通俗理解。 概率 P 是對(duì)隨機(jī)事件發(fā)生的可能性的度量。例如,小明在期末考試前,統(tǒng)計(jì)了下自己在今年的數(shù)學(xué)考試成績(jī),結(jié)果顯示得到 80 分以下的次數(shù)為 2 次,得 80 分~ 90 分的次數(shù)為 10 次,得到 90 分以上次數(shù)為 3 次,那么:

小明得到 80 分以下的概率為:
P( < 80 ) = 2/(2 10 3) = 13.3%

80~90分的概率為:
P( 80 ~ 90) = 10/(2 10 3) = 66.7%

90分以上的概率:
P( > 90) = 3/(2 10 3) = 20%

期望值 E,在一個(gè)離散性隨機(jī)變量實(shí)驗(yàn)中,重復(fù)很多次實(shí)驗(yàn),每次實(shí)驗(yàn)的結(jié)果乘以其出現(xiàn)的概率的總和。如上例中,小明在今年的期末考試,我們對(duì)他的期望值大約是多少呢?套用上面的公式,80 分以下的值取一個(gè)代表性的分?jǐn)?shù):70 分,80~90:85 分,90 分以上:95 分,

E =  70 * 0.133   85 * 0.667   95 * 0.2

計(jì)算出的結(jié)果為 85,即期末考試我們對(duì)小明的合理期望是 85 分左右。

方差 ,用來(lái)度量隨機(jī)變量取值和其期望值之間的偏離程度,公式為:

σ2=∑(X?μ)2Nσ2=∑(X?μ)2N

其中:

XX?表示小明的分?jǐn)?shù)這個(gè)隨機(jī)變量?μμ?表示樣本平均值?NN?表示樣本的個(gè)數(shù),即在此等于 15 個(gè)

已經(jīng)知道小明的 15 次考試的分?jǐn)?shù),均值剛才我們也計(jì)算出來(lái)了為 85 分,帶入到上面的公式中,便能得出偏離 85 分的程度大小。

如果方差很大,那么小明在期末考試的分?jǐn)?shù)可能偏離 85 分的可能性就越大;如果方差很小,那么小明很可能期末考試分?jǐn)?shù)在 85 分左右。

當(dāng)然,你還得了解,事件,離散事件,連續(xù)性事件,了解數(shù)據(jù)的常見分布,比如泊松分布,正態(tài)分布等,歸一化等知識(shí)。限于篇幅,在此,我就不一一展開了。我為大家推薦一本精簡(jiǎn)的這方面入門書籍,浙大盛驟等老師合編的《概率論與數(shù)理統(tǒng)計(jì)》這本書,大家可以有選擇地學(xué)習(xí)書中的重要個(gè)概念。

1.2 機(jī)器學(xué)習(xí)基本算法

說(shuō)統(tǒng)計(jì)學(xué)是一種基于事實(shí)的演繹學(xué)問,它是嚴(yán)謹(jǐn)?shù)?,可以給出確切解釋的。不過(guò),機(jī)器學(xué)習(xí)就不一樣了,它是一門歸納思想的學(xué)問,比如深度學(xué)習(xí)得出的模型,你就很難解釋其中的具體參數(shù)為什么取值為某某某。它的應(yīng)用在于可以提供一種預(yù)測(cè),給我們未來(lái)提供一種建設(shè)性的指導(dǎo)。

數(shù)據(jù)分析師需要了解機(jī)器學(xué)習(xí)的基本理論、常見的那十幾種算法,這樣對(duì)于我們做回歸、分類、聚類分析,都是不可缺少的。

直到現(xiàn)在,也有很多小伙伴在公眾號(hào)后臺(tái),問我,該如何入門機(jī)器學(xué)習(xí)。我通常的回答都是,先理解一種基本的算法,包括從算法的原理,公式推導(dǎo),手寫編碼實(shí)現(xiàn)這個(gè)算法,可視化算法的結(jié)果。當(dāng)完成整個(gè)一遍時(shí),你也就差不多入門了,知道機(jī)器學(xué)習(xí)是怎么一回事了。

這種方法,比較直接、奏效,作為過(guò)來(lái)人,當(dāng)時(shí)我也是這么做的,可以說(shuō)實(shí)踐出真知,同樣推薦給還有這方面疑惑的小伙伴,不要再拖延了,沒有一個(gè)神奇魔幻的方法,可以幫助你不用動(dòng)手的,就可以掌握它 。

從現(xiàn)在開始學(xué)習(xí)和動(dòng)手,參考接下來(lái)的介紹機(jī)器學(xué)習(xí)的章節(jié),我會(huì)附上完整的代碼,你只需要從頭敲一遍,差不多你就可以入門機(jī)器學(xué)習(xí)了。越直接,越奏效,先上路,再上道!

1.3 編程語(yǔ)言及工具

如果說(shuō)數(shù)學(xué)是純理論,可能只需要?jiǎng)幽X的學(xué)問地話,計(jì)算機(jī)和它最不同的一點(diǎn)就是,需要?jiǎng)邮?。記?linux 大神托瓦茲,作為世界上最著名的程序員、計(jì)算機(jī)科學(xué)家,linux 內(nèi)核和 git 的主要發(fā)明人。他就曾經(jīng)說(shuō)過(guò),talk is poor, show me the code.

的確,計(jì)算機(jī)屬于工科學(xué)問,動(dòng)手編碼的能力非常重要,現(xiàn)在越來(lái)越多的理工科博士,也開始注重編碼能力了,而且有的編碼能力也是超強(qiáng),寫出來(lái)的代碼可讀性、可擴(kuò)展性都很好。這在過(guò)去,博士能做到這個(gè)的,大概還不是太多(這是個(gè)人觀察得出,未經(jīng)數(shù)據(jù)考證,結(jié)論可能有誤 ),或許,當(dāng)前,博士找工作面臨壓力也很大,物競(jìng)天擇,適者生存,民營(yíng)、私企不會(huì)養(yǎng)一個(gè)閑人。

數(shù)據(jù)分析和機(jī)器學(xué)習(xí)領(lǐng)域,同樣需要能熟練使用至少一門變成語(yǔ)言,目前此領(lǐng)域,使用較多的就是 Python 和 R 語(yǔ)言。Python 又適合與機(jī)器學(xué)習(xí)領(lǐng)域,所以數(shù)據(jù)分析相關(guān)的從業(yè)人員,目前使用 Python 的也較多,當(dāng)然 R 語(yǔ)言也不少?;?Python 的生態(tài)環(huán)境也很不錯(cuò),有很多數(shù)據(jù)科學(xué)包,比如文中提到的 NumPy、SciPy、Pandas 等等。

入行前,多多動(dòng)手實(shí)踐一些項(xiàng)目和名校的開源課程,可以驅(qū)動(dòng)我們掌握它們,畢竟面對(duì)一些實(shí)際需求,這樣做目標(biāo)明確,自然會(huì)驅(qū)使你去掌握這些包的更多功能和 API 使用。

總結(jié),這個(gè)數(shù)據(jù)分析的入門路線,主要分為三部分,現(xiàn)在相信小伙伴們已經(jīng)目標(biāo)已經(jīng)很明確了。

下面,看下數(shù)據(jù)分析的重頭戲,數(shù)據(jù)整理(data munging)。

數(shù)據(jù)分析重頭戲之?dāng)?shù)據(jù)整理

數(shù)據(jù)整理,英文名稱 data munging,是指在獲取到的原數(shù)據(jù)基礎(chǔ)上,理解這些業(yè)務(wù)數(shù)據(jù),整理清洗它們,作為接下來(lái)算法建模的輸入數(shù)據(jù)。在文章剛開始,我們就提到過(guò),這部分工作的重要性,絕不亞于算法模型,時(shí)間占比可能大于算法選擇和設(shè)計(jì)環(huán)節(jié)。

2.1 理解你的業(yè)務(wù)數(shù)據(jù)

我們?cè)谀玫叫枰治龅臄?shù)據(jù)后,千萬(wàn)不要急于立刻開始做回歸、分類、聚類分析。

第一步應(yīng)該是認(rèn)真理解業(yè)務(wù)數(shù)據(jù),可以試著理解去每個(gè)特征,觀察每個(gè)特征,理解它們對(duì)結(jié)果的影響程度。

然后,慢慢研究多個(gè)特征組合后,它們對(duì)結(jié)果的影響。借助上個(gè)章節(jié)提到的,常用的統(tǒng)計(jì)學(xué)指標(biāo),比如四分位,繪制箱形圖,可以幫助我們尋找樣本的取值分布。

同時(shí),可以借助另一個(gè)強(qiáng)大的可視化工具: seaborn ,繪制每個(gè)特征變量間的相關(guān)系數(shù)熱圖 heatmap,幫助我們更好的理解數(shù)據(jù),如下圖所示:

colormap = plt.cm.RdBu
plt.figure(figsize=(14,12))
sns.heatmap(train.astype(float).corr(),linewidths=0.1,vmax=1.0, square=True, cmap=colormap, linecolor='white', annot=True)

enter image description here

2.2 明確各個(gè)特征的類型

明確我們的數(shù)據(jù)類型,也是數(shù)據(jù)整理階段的必備任務(wù)之一。

如果這些數(shù)據(jù)類型不是算法部分期望的數(shù)據(jù)類型,你還得想辦法編碼成想要的。比如常見的數(shù)據(jù)自增列 id 這類數(shù)據(jù),是否有必要放到你的算法模型中,因?yàn)檫@類數(shù)字很可能被當(dāng)作數(shù)字讀入。

某些列的取值類型,雖然已經(jīng)是數(shù)字了,它們的取值大小表示什么含義你也要仔細(xì)捉摸。因?yàn)椋瑪?shù)字的相近相鄰,并不一定代表另一種層面的相鄰。

有些列是類別型變量(categorical variable),例如著名的 Kaggle 泰坦尼克生還預(yù)測(cè)比賽中,乘客上船地點(diǎn) Embarked 這個(gè)變量就是類別型變量。如果給 Embarked 變量用 Embarked 編碼為 1、2、3 ,這樣編碼是不合理的。

一般這種類型的編碼方式有 one-hot 編碼,dummy variable 兩種方式。

2.3 找出異常數(shù)據(jù)

有時(shí)候我們的數(shù)據(jù)存在異常值,并且這種概率挺大的。這實(shí)際上會(huì)導(dǎo)致結(jié)果出現(xiàn)偏差。比如,統(tǒng)計(jì)中國(guó)家庭人均收入時(shí),如果源數(shù)據(jù)里面,有王建林,馬云等這種富豪,那么,人均收入的均值就會(huì)受到極大的影響,這個(gè)時(shí)候最好,繪制箱形圖,看一看百分位數(shù)。

了解數(shù)據(jù)范圍,設(shè)定最大值、最小值限度是很非常重要的。

2.4 不得不面對(duì)缺失值

現(xiàn)實(shí)生產(chǎn)環(huán)境中,拿到的數(shù)據(jù)恰好完整無(wú)損、沒有任何缺失數(shù)據(jù)的概率,和買彩票中將的概率差不多。

數(shù)據(jù)缺失的原因太多了,業(yè)務(wù)系統(tǒng)版本迭代, 之前的某些字段不再使用了,自然它們的取值就變?yōu)?null 了;再或者,壓根某些數(shù)據(jù)字段在抽樣周期里,就是沒有寫入數(shù)據(jù)......

處理缺失數(shù)據(jù),最好弄明白它們?yōu)槭裁慈笔Я耍热?,像上面說(shuō)道的,如果是在抽樣周期里,這些字段取值缺失了,那么可以咨詢業(yè)務(wù)人員,這些字段大概率會(huì)取得哪些值。

接下來(lái),填充缺失數(shù)據(jù),比如均值填充,或者,為缺失的數(shù)據(jù)創(chuàng)建一類特殊值。

極端情況下,如果發(fā)現(xiàn)模型的效果受此字段影響較大,發(fā)現(xiàn)徹底刪除此字段效果更好,那完全剔除可能是不錯(cuò)的選擇。不過(guò)這樣做也有風(fēng)險(xiǎn),可能為模型帶來(lái)更大的偏差。

2.5 令人頭疼的數(shù)據(jù)不均衡

理論和實(shí)際總是有差距的,理論上很多算法都存在一個(gè)基本假設(shè),即數(shù)據(jù)分布總是均勻的。這個(gè)美好的假設(shè),在實(shí)際中,真的存在嗎?很可能不是!

算法基于不均衡的數(shù)據(jù)學(xué)習(xí)出來(lái)的模型,在實(shí)際的預(yù)測(cè)集上,效果往往差于訓(xùn)練集上的效果。實(shí)際數(shù)據(jù)往往分布得很不均勻,存在所謂的?“長(zhǎng)尾現(xiàn)象”,又稱:“二八原理”。

就不均衡解決的難易程度而言,數(shù)據(jù)量越大,不均衡的問題越容易解決,相反,數(shù)據(jù)量很小,再不均衡,解決起來(lái)就比較困難了,比如典型的太空中是否有生命跡象這個(gè)事情,壓根就沒有太多相關(guān)的因素?cái)?shù)據(jù),如果某個(gè)特征的取值遠(yuǎn)多于另外一種,處理這種數(shù)據(jù)不均衡問題,就比較困難了。

所有以上 5 個(gè)方面的問題,對(duì)于一個(gè)數(shù)據(jù)分析師或數(shù)據(jù)科學(xué)家而言,都是需要認(rèn)真處理對(duì)待的。限于篇幅,每個(gè)方面的詳細(xì)解決技術(shù),大家可以自行搜索相關(guān)文獻(xiàn)和技術(shù)博客,一般大都有對(duì)應(yīng)的解決措施。通過(guò)這個(gè) chat,你能知道數(shù)據(jù)整理工作主要有這 5 個(gè)方面或者任務(wù),等著你去探索解決,基本也就可以了。

當(dāng)然,數(shù)據(jù)分析完成數(shù)據(jù)整理后,接下來(lái)的主要任務(wù):特征工程,也是非常重要的。大家也可以查詢相關(guān)資料,記得在我的公眾號(hào)里,關(guān)于這個(gè)話題,曾經(jīng)不只一次的探討過(guò),大家可以參考,一起交流。

接下來(lái),開始介紹編程工具環(huán)節(jié),繼續(xù)我們的數(shù)據(jù)分析探索之旅。

Python 入門必備知識(shí)

Python 語(yǔ)言主要的特點(diǎn),通俗的說(shuō)就是語(yǔ)法簡(jiǎn)潔,開發(fā)效率高,一般數(shù)據(jù)分析,機(jī)器學(xué)習(xí),深度學(xué)習(xí)會(huì)選用 Python 語(yǔ)言,同時(shí)基于 Python 的開發(fā)生態(tài)環(huán)境比較友好。

下面,從 Python 語(yǔ)言的特點(diǎn),以及平時(shí)使用較多的幾個(gè)典型對(duì)象展開,這些都是入門必備的功能,掌握這些你就可以說(shuō)自己入門 Python 了。

不過(guò),為了兼顧已經(jīng)比較熟悉 Python 的小伙伴,我打算留有一定篇幅介紹一些 Python 的進(jìn)階功能,它們作為 Python 的重要特性,在平時(shí)工作中也會(huì)用到。

3.1 解釋型Vs編譯型

Python 是解釋型語(yǔ)言,對(duì)于 Python 剛剛?cè)腴T的小伙伴,可能對(duì)解釋性有些疑惑。不過(guò),沒關(guān)系,我們可以通過(guò)大家已經(jīng)熟悉的編譯型語(yǔ)言,來(lái)幫助我們理解 Python 的解釋性。

編譯型語(yǔ)言,如 C 、Java,它們會(huì)在編譯階段做類型匹配檢查等,因此,數(shù)據(jù)類型不匹配導(dǎo)致的編譯錯(cuò)誤,在編譯階段就會(huì)被檢查出來(lái),例如:

Intger a = 0;
Double b = 0.0;
a = b; // Double類型的變量 b 試圖賦值給 Integer 型的變量 a, 編譯報(bào)錯(cuò)
         // 因?yàn)?Integer 類型 和 Double 類型 不存在繼承關(guān)系,
         // 類型不能互轉(zhuǎn)

但是,Python 就不會(huì)在編譯階段做類型匹配檢查,比如,Python 實(shí)現(xiàn)上面的幾行語(yǔ)句,會(huì)這樣寫:

a = 0 # 不做任何類型聲明
b = 0.
a = b # 這種賦值,Python 會(huì)有問題嗎?

答案是不會(huì)的。此處就體現(xiàn)了 Python 的解釋特性,當(dāng)我們把 0 賦值給 a 時(shí),Python 解釋器會(huì)把它 a 解釋為 int 型,可以使用內(nèi)置函數(shù) type(variable) 顯示地檢查 variable 的類型:

In [70]: type(a)
Out[70]: int

In [69]: type(b)
Out[69]: float

In [71]: a = b # 在把 float 型 b 賦值給 a 后, # a 就被解釋為float

In [72]: type(a)
Out[72]: float

在把 float 型 b 賦值給 a 后, a 就被解釋為 float. 相信此時(shí),你已經(jīng)對(duì) Python 的解釋型有一定了解了,下面說(shuō)一些 Python 最常用的對(duì)象及其方法。

3.2 Python 最常用的對(duì)象

Python 最常用的幾個(gè)對(duì)象: list、dict、tuple 以及它們?nèi)叩撵`活組合。list 可以看作是線性表和鏈表的結(jié)合體,dict 可以看作是 key-value 對(duì)的組合,tuple 是不可更改的 "list"(注意,這種表述未必嚴(yán)謹(jǐn),但個(gè)人認(rèn)為比較通俗易懂,尤其對(duì)于入門者而言)。

上面提到 Python 用于數(shù)據(jù)分析,機(jī)器學(xué)習(xí),非常方便。我們平時(shí)需要處理的數(shù)據(jù)怎么也有成千上萬(wàn)行,要想利用這些數(shù)據(jù)做分析,不可避免地當(dāng)要將它們緩存到內(nèi)存中。很顯然,最直接的存儲(chǔ)結(jié)構(gòu)必然是容器。無(wú)一例外,list、dict、tuple 都是 Python 中構(gòu)建好的容器,都是可迭代的對(duì)象,它們因此被使用頻次高也就不足為奇了。

簡(jiǎn)單來(lái)說(shuō),我們使用 [] 創(chuàng)建一個(gè) list,使用 {} 創(chuàng)建一個(gè) dict,使用 () 創(chuàng)建一個(gè) tuple。創(chuàng)建好我們的容器后,下一步就要知道如何添加、刪除、更新、查詢?cè)L問里面的元素。

3.2.1 list 核心知識(shí)

先說(shuō)說(shuō) list 的這些操作:

In [73]: a = [[1,3,5],[7,4,2]] # 創(chuàng)建二維數(shù)組 a                                                                  
In [74]: a
Out[74]: [[1, 3, 5], [7, 4, 2]]

In [75]: a.append([0,8,3])  # 插入元素[0,8,3]

In [76]:
Out[76]: [[1, 3, 5], [7, 4, 2], [0, 8, 3]]

注意 append 操作直接插入到 a 的末尾,而不是 a 的副本的末尾,這樣做無(wú)疑節(jié)省了內(nèi)存空間。面向?qū)ο缶幊桑还苁?C 、Java、Python 都會(huì)有這類問題,務(wù)必要清楚操作是在 a 上修改,還是在 a 的副本上修改,各有用處,此處不再詳細(xì)展開討論,后面的進(jìn)階課程,我們可以再展開。

如果想批量增加元素,可以使用 extend,如下所示,我們先使用 copy 下 a ,返回 b ,注意 list 實(shí)例的 copy 一律屬于淺>拷貝(shallow copy),注意這種拷貝帶來(lái)的副作用,在此我們也不詳細(xì)展開,后續(xù)我們可以找時(shí)間討論無(wú)論哪種面向?qū)ο蟮恼Z(yǔ)言都存在的 shallow copy and deep copy 問題,以及如何選用哪種 copy 節(jié)省內(nèi)存空間的同時(shí),也能按預(yù)期實(shí)現(xiàn)目標(biāo)。可以看到 b.extend(a) 后,b 內(nèi)批量導(dǎo)入了 a。

In [100]: a
Out[100]: [[1, 3, 5], [7, 4, 2], [0, 8, 3]]

In [101]: b = a.copy()

In [102]: b
Out[102]: [[1, 3, 5], [7, 4, 2], [0, 8, 3]]

In [103]: b.extend(a)

In [104]: b
Out[104]: [[1, 3, 5], [7, 4, 2], [0, 8, 3], [1, 3, 5], [7, 4, 2], [0, 8,3]]

list 提供的刪除元素方法有 pop,它默認(rèn)刪除 list 實(shí)例的最后一個(gè)元素,基于此,可以模擬棧(first in last out)的功能,因此 Python 中沒有內(nèi)置單獨(dú)的棧對(duì)象。

In [94]: last = a.pop()

In [95]: a
Out[95]: [[1, 3, 5], [7, 4, 2]]

In [96]: last
Out[96]: [0, 8, 3]

pop 后返回了刪除的最后一個(gè)元素,last。

除了 pop 的默認(rèn)刪除最后一個(gè)元素,如果想刪除某個(gè)指定元素呢? remove 可以實(shí)現(xiàn)。它們具體使用如下:

In [111]: a.remove([7,4,2])

In [112]: a
Out[112]: [[1, 3, 5], [0, 8, 3]]

In [115]: a.remove(a[0])

In [116]: a
Out[116]: [[0, 8, 3]]

可以看到,它可以實(shí)現(xiàn)刪除制定的某個(gè)元素。

更新 list 的某個(gè)元素值,只需要索引到這個(gè)元素,然后重新賦值即可。所以更新操作的關(guān)鍵還是要知道如何訪問某個(gè)或某些元素,Python 為此提供了強(qiáng)大的單個(gè)下標(biāo)索引和切片索引機(jī)制。

如下所示, list 的 insert 可以實(shí)現(xiàn)在指定索引位置添加元素,a[1] 返回第一維的索引編號(hào)從 0 開始的,索引為 1 的元素, a[1][0] 返回其第二維的索引為 0 的元素。而 a[1][:2] 返回其第二維的索引為 0, 1,注意不包括 2 的切片。

In [121]: a.insert(0,[1,3,5])
In [122]: a
Out[122]: [[1, 3, 5], [0, 8, 3]]

In [123]: a[1]
Out[123]: [0, 8, 3]

In [124]: a[1][0]
Out[124]: 0

In [125]: a[1][:2]
Out[125]: [0, 8]

語(yǔ)言也是一門底層系統(tǒng),工程角度看,就像開頭提到的,系統(tǒng)的健壯性是重要的。比如 C 、Java、C# 等語(yǔ)言,數(shù)組訪問拋出的一個(gè)比較常見的錯(cuò)誤就是 outOfIndex,超出數(shù)組訪問界限。不過(guò),Python 沒有像這些語(yǔ)言那樣,也內(nèi)置了這個(gè)異常,而是選擇沉默,把該返回的返回給我們,對(duì)越界不理會(huì)。比如:

In [126]: a[1][:200]
Out[126]: [0, 8, 3]

很顯然,第二維度的長(zhǎng)度為 3, 在索引到 200 時(shí),顯然會(huì)越界,但是 Python 不會(huì)拋出任何異常,而是正常返回這一維度的所 有元素即可。

Python 的 list 存儲(chǔ)的元素可以為不同類型(hetergeneous), 而不像 C 、Java、C# 那樣要求是同質(zhì)(homogeneous)的。

In [127]: a = [1,'de']

In [128]: a
Out[128]: [1, 'de']
3.2.2 dict 核心知識(shí)

dict 就是一種字典結(jié)構(gòu),key 唯一。

創(chuàng)建一個(gè) dict ,在此介紹兩種,一種直接 {},另一種 dict 構(gòu)造函數(shù)創(chuàng)建,如下:

In [131]: d = {'a':[1,2,3], 'b':['gz','lg','zx']}

In [132]: d
Out[132]: {'a': [1, 2, 3], 'b': ['gz', 'lg', 'zx']}

另一種 dict 構(gòu)造函數(shù)創(chuàng)建,如下,第一個(gè)參數(shù)指定 keys,第二個(gè)參數(shù)指定 value。

In [174]: d = dict.fromkeys(['a','b'],[1,2,5])

In [175]: d
Out[175]: {'a': [1, 2, 5], 'b': [1, 2, 5]}

接下來(lái),依次介紹字典內(nèi)元素的增加、刪除、更新、訪問。增加元素對(duì)于 dict 而言就是增加一個(gè)鍵值對(duì),如下所示:

In [3]: d = dict.fromkeys(['a','b'],[1,2,3])                                    
In [4]: d                                                                       
Out[4]: {'a': [1, 2, 3], 'b': [1, 2, 3]}

In [5]: d['c'] = ['gz','lg']                                                    

In [6]: d                                                                       
Out[6]: {'a': [1, 2, 3], 'b': [1, 2, 3], 'c': ['gz', 'lg']}

Python 中的 dict,如果添加一個(gè)鍵值對(duì)時(shí),原字典中此鍵已經(jīng)存在,則直接更新,比較方便,如下:

In [1]: d = dict.fromkeys(['a','b'],[1,2,3])                                    

In [2]: d['c'] = ['gz','lg']                                                    

In [3]: d                                                                       
Out[3]: {'a': [1, 2, 3], 'b': [1, 2, 3], 'c': ['gz', 'lg']}

In [4]: d['b'] = [3,5,8]                                                        

In [5]: d                                                                       
Out[5]: {'a': [1, 2, 3], 'b': [3, 5, 8], 'c': ['gz', 'lg']}

想要?jiǎng)h除字典中的某個(gè)鍵值對(duì)時(shí),使用 pop,傳入想要?jiǎng)h除的鍵值對(duì)的鍵,如下:

In [7]: d                                                                       
Out[7]: {'a': [1, 2, 3], 'b': [3, 5, 8], 'c': ['gz', 'lg']}

In [8]: d.pop('b')                                                              
Out[8]: [3, 5, 8]

In [9]: d                                                                       
Out[9]: {'a': [1, 2, 3], 'c': ['gz', 'lg']}

如果字典中不存在此鍵,則返回設(shè)置的默認(rèn)值,比如我們自己設(shè)置的: 'key is not in dict' , 如下:

In [9]: d                                                                       
Out[9]: {'a': [1, 2, 3], 'c': ['gz', 'lg']}

In [10]: d.pop('b','key is not in dict')                                        
Out[10]: 'key is not in dict'

訪問鍵值對(duì),只能通過(guò)鍵,訪問對(duì)應(yīng)的值,如下:

In [11]: d['a']                                                                 
Out[11]: [1, 2, 3]

dict 是可迭代的對(duì)象類型,可以通過(guò) for 遍歷每個(gè)鍵值對(duì),如下直接訪問每個(gè)鍵:

In [12]: for i in d: 
    ...:     print(i) 
    ...:                                                                        
a
c

要想訪問每個(gè)鍵值對(duì),可以借助字典的 items() 訪問,items 方法返回字典內(nèi)每項(xiàng)的視圖:

items(...) method of builtins.dict instance
    D.items() -> a set-like object providing a view on D's items

items 方法遍歷獲得鍵值對(duì),如下:

In [13]: help(d.items)                                                          
In [14]: for item in d.items(): 
    ...:     print(item) 
    ...:                                                                        
('a', [1, 2, 3])
('c', ['gz', 'lg'])
3.2.3 tuple 和 set 簡(jiǎn)介

tuple 對(duì)象是以 () 創(chuàng)建的,set 對(duì)象是以 {} 創(chuàng)建的,下面簡(jiǎn)單認(rèn)識(shí)下它們:

In [20]: t = ('a',[1,4,6],{'b':[4,2,0]}) #tuple有3個(gè)元素                                       
In [21]: t                                                                      
Out[21]: ('a', [1, 4, 6], {'b': [4, 2, 0]})

In [22]: s = {1,4,6} # 創(chuàng)建 set                                                            
In [23]: s                                                                      
Out[23]: {1, 4, 6}

簡(jiǎn)單來(lái)說(shuō),tuple 是不可更改的對(duì)象(immutable),也就是一旦創(chuàng)建,里面的元素就不能再改動(dòng)了。set 是無(wú)重復(fù)元素的集合體,是可更改的對(duì)象(mutable),它和 list、dict 一樣都是 mutable 的對(duì)象。關(guān)于 immutable 和 mutable 的性質(zhì),使用注意事項(xiàng),在此不再詳細(xì)展開,后續(xù)進(jìn)階課程里,我們可以詳細(xì)討論。

3.3 Python 入門必備知識(shí)點(diǎn)

介紹完了Python 內(nèi)的幾個(gè)核心對(duì)象后,下面來(lái)認(rèn)識(shí) Python 語(yǔ)言入門的幾個(gè)語(yǔ)法特性,可以說(shuō)它們是入門 Python 的必備知識(shí)了。

3.3.1 對(duì)象上的特殊函數(shù)

此小節(jié)介紹的這些,可以算是進(jìn)階部分,剛?cè)腴T的小伙伴可以后面再來(lái)回顧。

常用的 Python 解釋器 CPython ,底層都是使用 C 開發(fā)的,如 list、dict、tuple、set,其實(shí)就是一個(gè)結(jié)構(gòu)體。

細(xì)心的小伙伴可能會(huì)觀察到,list 的里面存在一些特殊函數(shù),它們都以雙劃線__開頭,雙劃線結(jié)尾,這類方法可以看做為對(duì)象上的特殊方法。我們新建一個(gè)的類上,默認(rèn)都存在這類特殊方法。

接下來(lái),演示如何實(shí)現(xiàn)這類特殊的函數(shù)。

In [37]: class student: 
    ...:     def __init__(self,name): 
    ...:         self.name = name 
    ...:     def __len__(self): 
    ...:         return len(self.name) 

In [38]: xiaoming = student('xiaoming')                                         
In [39]: len(xiaoming)                                                          
Out[39]: 8

如上,重新實(shí)現(xiàn)對(duì)象上的默認(rèn)方法 __init__?和?__len__.

在這里為大家起個(gè)頭,更多其他特殊方法,大家可以自行研究,后續(xù)我們可以再展開討論。

3.3.2 列表生成式

Python 的列表表達(dá)式,可以生成 list 對(duì)象,基本語(yǔ)法和用法如下:

In [40]: [abs(i) for i in [-4,3,1,-9,2]]                                        
Out[40]: [4, 3, 1, 9, 2]

結(jié)合 if 和 else,寫起來(lái)更加簡(jiǎn)潔,如下:

In [42]: [i 1 if i>0 else i 1 for i in [-4,3,1,-9,2]] 

Out[42]: [-3, 4, 2, -8, 3]
3.3.3 位置參數(shù)和關(guān)鍵字參數(shù)

如果介紹 Python 入門,不介紹函數(shù)的位置參數(shù) ( positional argument ) 和關(guān)鍵字參數(shù)( keyword argument ) ,總是感覺缺少點(diǎn)什么,它們?cè)?Python 函數(shù)中到處可見,理解和使用它們,為我們?nèi)蘸笊钊?Python 打下堅(jiān)實(shí)的根基。

我們?cè)?Python 中到處可見類似這樣的函數(shù):

 In [43]: def fun(*args, **kwargs): 
    ...:     print(args,kwargs)                                                                   

*args表示位置參數(shù),**kwargs表示關(guān)鍵字參數(shù)。

相比于 Java, C 語(yǔ)言,這類參數(shù)為我們帶來(lái)很大的便利,當(dāng)我們不知道形參的個(gè)數(shù)時(shí),可以聲明這樣的形參。

具體使用,如下:

 In [44]: fun([4,3,1],name = 'gz', color = 'red')  

([4, 3, 1],) {'name': 'gz', 'color': 'red'}

可以看到位置參數(shù) args 被傳入?[4,3,1],并且被載入到 tuple 對(duì)象 args 中,而關(guān)鍵字參數(shù)統(tǒng)一被傳入了 dict 對(duì)象 kwargs 中。

使用位置參數(shù)和關(guān)鍵字參數(shù),需要注意一點(diǎn),位置參數(shù)不能位于關(guān)鍵字參數(shù)后面,否則會(huì)彈出 SyntaxError ,如下:

In [45]: fun(name = 'gz', [4,3,1])                                              
  File "<ipython-input-45-cd568523bb4d>", line 1
    fun(name = 'gz', [4,3,1])
                    ^
SyntaxError: positional argument follows keyword argument

關(guān)于 Python,主要介紹了 Python 語(yǔ)言入門必備的知識(shí),包括了解 Python 的解釋性;最常用的核心對(duì)象,比如 list, dict, tuple, set;一些重要的使用必備知識(shí)點(diǎn)需要了解,比如對(duì)象上特殊方法,列表生成式,位置參數(shù)和關(guān)鍵字參數(shù)等。

這些可能還不夠,還有一些重要的特性,比如 Python 的生成器(generator),面向函數(shù)式編程模塊等,我們可以接下來(lái)在進(jìn)階課程中介紹。

NumPy 入門必備知識(shí)

Python 已經(jīng)夠強(qiáng)大,用 Python 做數(shù)據(jù)分析時(shí),發(fā)現(xiàn)需要寫不少 for 循環(huán),尤其當(dāng)嵌套起來(lái)時(shí),不但影響開發(fā)效率,還會(huì)影響代碼的可讀性。

后來(lái),出現(xiàn)了很多基于 Python 開發(fā)的科學(xué)計(jì)算庫(kù),用于數(shù)據(jù)分析最優(yōu)秀的工具包之一當(dāng)屬 Pandas,它對(duì) R 語(yǔ)言也非常友好。

Pandas 庫(kù)是基于 NumPy 和 Python 開發(fā)的,它借鑒了很多 NumPy 的設(shè)計(jì)理念,因此,介紹 Pandas 前,我們先了解 NumPy 的入門必備知識(shí)。

4.1 ndarray 對(duì)象

NumPy 系統(tǒng)封裝了一個(gè)強(qiáng)大的類似于多維數(shù)組的對(duì)象。使 NumPy 前,需要先安裝 NumPy 包,推薦通過(guò)安裝 anaconda 使用各個(gè)常用的包。

import numpy as np # 導(dǎo)入 NumPy 包,起個(gè)別名為 np

創(chuàng)建一個(gè) ndarray 對(duì)象,如下:

In [47]: n1d = np.array([1,4,5])                                                
In [48]: n1d                                                                    
Out[48]: array([1, 4, 5])

n1d 實(shí)例支持的一些數(shù)值操作與原聲的 Python 有所不同,比如乘法操作,在 Python 中?*,實(shí)現(xiàn)元素的復(fù)制:

In [49]: [1,4,5]*3                                                              
Out[49]: [1, 4, 5, 1, 4, 5, 1, 4, 5]

而在 NumPy 中 ndarray 數(shù)組支持的?*,實(shí)現(xiàn)的功能如下,每個(gè)元素都乘以 3.

In [50]: n1d*3                                                                  
Out[50]: array([ 3, 12, 15])

如果在 Python 中實(shí)現(xiàn)這個(gè)效果,我們需要循環(huán)遍歷每個(gè)元素來(lái)完成,如這樣實(shí)現(xiàn):

In [52]: [i*3 for i in [1,4,5]]                                                 
Out[52]: [3, 12, 15]

這種實(shí)現(xiàn)方式,沒有 NumPy 實(shí)現(xiàn)的更簡(jiǎn)潔,這正體現(xiàn)了 NumPy 的一種設(shè)計(jì)思想:向量化(vectorization).

下面介紹 NumPy 的這個(gè)重要設(shè)計(jì)思想。

4.2 NumPy 的向量化增強(qiáng)

再通過(guò)一些例子感受下,向量化設(shè)計(jì)給我們帶來(lái)的便捷。

linspace 默認(rèn)線性切分 50 份,且默認(rèn)包含邊界值 10.

In [57]: b = np.linspace(0,10)                                                  

In [58]: b                                                                      
Out[58]: 
array([ 0.        ,  0.20408163,  0.40816327,  0.6122449 ,  0.81632653,
        1.02040816,  1.2244898 ,  1.42857143,  1.63265306,  1.83673469,
        2.04081633,  2.24489796,  2.44897959,  2.65306122,  2.85714286,
        3.06122449,  3.26530612,  3.46938776,  3.67346939,  3.87755102,
        4.08163265,  4.28571429,  4.48979592,  4.69387755,  4.89795918,
        5.10204082,  5.30612245,  5.51020408,  5.71428571,  5.91836735,
        6.12244898,  6.32653061,  6.53061224,  6.73469388,  6.93877551,
        7.14285714,  7.34693878,  7.55102041,  7.75510204,  7.95918367,
        8.16326531,  8.36734694,  8.57142857,  8.7755102 ,  8.97959184,
        9.18367347,  9.3877551 ,  9.59183673,  9.79591837, 10.        ])

b 1 操作,默認(rèn)每個(gè)元素都加1,這其中還涉及到 NumPy 的廣播機(jī)制,會(huì)在接下來(lái)小節(jié)中介紹。

In [59]: b   1                                                                  
Out[59]: 
array([ 1.        ,  1.20408163,  1.40816327,  1.6122449 ,  1.81632653,
        2.02040816,  2.2244898 ,  2.42857143,  2.63265306,  2.83673469,
        3.04081633,  3.24489796,  3.44897959,  3.65306122,  3.85714286,
        4.06122449,  4.26530612,  4.46938776,  4.67346939,  4.87755102,
        5.08163265,  5.28571429,  5.48979592,  5.69387755,  5.89795918,
        6.10204082,  6.30612245,  6.51020408,  6.71428571,  6.91836735,
        7.12244898,  7.32653061,  7.53061224,  7.73469388,  7.93877551,
        8.14285714,  8.34693878,  8.55102041,  8.75510204,  8.95918367,
        9.16326531,  9.36734694,  9.57142857,  9.7755102 ,  9.97959184,
       10.18367347, 10.3877551 , 10.59183673, 10.79591837, 11.        ])

到目前,你可能對(duì)向量化有一定認(rèn)識(shí)了。用 Python 寫的原生函數(shù),默認(rèn)參數(shù)只接受單個(gè)元素,比如:

In [61]: def myabs(a): 
    ...:     return abs(a) 
    ...:                                                                        
In [62]: myabs(-5)                                                              
Out[62]: 5

如果傳入一個(gè) list,就會(huì)報(bào)錯(cuò):

In [63]: myabs([1,4,-3])                                                        
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-63-f7385068c934> in <module>
----> 1 myabs([1,4,-3])

<ipython-input-61-860035516c2e> in myabs(a)
      1 def myabs(a):
----> 2     return abs(a)
      3 

TypeError: bad operand type for abs(): 'list'

那么如何增強(qiáng) myabs 函數(shù)功能,使之具備處理 list 的能力呢?可以通過(guò) NumPy 的向量化函數(shù) vectorize 實(shí)現(xiàn),如下所示,非常方便。

In [64]: zq_myabs = np.vectorize(myabs)                                         
In [65]: zq_myabs([1,3,-5])                                                     
Out[65]: array([1, 3, 5])

以上就是 NumPy 的向量化設(shè)計(jì)機(jī)制,下面介紹 NumPy 中另一個(gè)強(qiáng)大的設(shè)計(jì)機(jī)制:傳播(broadcast),這個(gè)機(jī)制不僅存在于 NumPy 中,Pandas, TensorFlow 中也都有。

作為 NumPy 入門者,這個(gè)機(jī)制理解起來(lái)可能有一定困難,不過(guò)它真的太重要了,一定要慢慢理解它,這是成為一個(gè) NumPy 專家的必備知識(shí)。

4.3 NumPy 的傳播機(jī)制

先看一個(gè)例子:

In [66]: a = np.array([[1],[-5],[3]])                                           
In [67]: a                                                                      
Out[67]: 
array([[ 1],
       [-5],
       [ 3]])

In [68]: b = np.array([[5,2,4,9]])                                              
In [69]: b                                                                      
Out[69]: array([[5, 2, 4, 9]])

In [70]: a   b                                                                  
Out[70]: 
array([[ 6,  3,  5, 10],
       [ 0, -3, -1,  4],
       [ 8,  5,  7, 12]])

對(duì)剛接觸 NumPy 的小伙伴,可能看到 a b 的結(jié)果有點(diǎn)發(fā)蒙,感覺這是一個(gè)神奇的操作,不知怎么回事。

滿足以下任意一種情況,都可能發(fā)生廣播: 1. 如果兩個(gè)數(shù)組的末尾維度(trailing dimension)的長(zhǎng)度相符;

  1. 參與計(jì)算的某個(gè)維度長(zhǎng)度為 1

廣播會(huì)在缺失和(或)長(zhǎng)度為 1 的維度上進(jìn)行。

再回頭上面那個(gè)例子,分析下廣播是如何發(fā)生的。首先檢查它們是否滿足可廣播的條件。

檢查 a 的 shape

a = np.array([[1],[-5],[3]]) 

In [71]: a.shape     
Out[71]: (3, 1)

檢查 b 的 shape

b = np.array([[5,2,4,9]]) 

In [72]: b.shape                              
Out[72]: (1, 4)

容易發(fā)現(xiàn),參與計(jì)算的兩個(gè)對(duì)象都出現(xiàn)了某個(gè)維度長(zhǎng)度為1的情況,因此滿足發(fā)生傳播的條件。

根據(jù)廣播機(jī)制,廣播會(huì)發(fā)生在缺失或長(zhǎng)度為 1 的維度上進(jìn)行,比如 a 會(huì)在第二個(gè)維度上擴(kuò)展成為 4, shape 變?yōu)?(3,4),擴(kuò)展后的形狀為:

In [75]: ae                                                                     
Out[75]: 
array([[ 1,  1,  1,  1],
       [-5, -5, -5, -5],
       [ 3,  3,  3,  3]])

b 同理會(huì)在第一個(gè)維度上擴(kuò)展為 3, shape 也會(huì)變?yōu)?(3,4),擴(kuò)展后的形狀如下:

In [78]: be                                                                     
Out[78]: 
array([[5, 2, 4, 9],
       [5, 2, 4, 9],
       [5, 2, 4, 9]])

這樣,對(duì)應(yīng)元素就可以相加了,如下:

In [79]: ae   be                                                                
Out[79]: 
array([[ 6,  3,  5, 10],
       [ 0, -3, -1,  4],
       [ 8,  5,  7, 12]])

最后一個(gè)細(xì)節(jié),NumPy 的 ndarray 對(duì)象每個(gè)元素類型必須是一致的。這一點(diǎn)不同于原生的 Python,可以不同類型的元素出現(xiàn)在同一個(gè) list 中。

以上就是 NumPy 的必備精華知識(shí),接下來(lái)介紹數(shù)據(jù)分析利器:Pandas。

Pandas 數(shù)據(jù)分析必備入門知識(shí)

Pandas 成為了 Python 數(shù)據(jù)分析的必備工具包。下面介紹它的兩大對(duì)象,以及一些常用的數(shù)據(jù)分析函數(shù)。

5.1 類一維數(shù)組 Series

Series 是 pandas 兩大數(shù)據(jù)結(jié)構(gòu)中(DataFrame,Series)的一種,我們先從 Series 的定義說(shuō)起,Series 是一種類似于一維數(shù)組的對(duì)象,它由一組數(shù)據(jù)(各種 NumPy 數(shù)據(jù)類型)以及一組與之相關(guān)的數(shù)據(jù)標(biāo)簽和索引組成。

Series 對(duì)象也是一個(gè) NumPy 的數(shù)組,因此 NumPy 的數(shù)組處理函數(shù)可以直接對(duì) Series 進(jìn)行處理。

與此同時(shí),Series 除了可以使用位置索引作為下標(biāo)存取元素之外,還可以使用標(biāo)簽下標(biāo)存取元素,這一點(diǎn)和字典相似,每個(gè) Series 對(duì)象都由兩個(gè)數(shù)組組成: 1. index:它是從 NumPy 數(shù)組繼承的 Index 對(duì)象,保存標(biāo)簽信息。 2. values:保存值的 NumPy 數(shù)組。

接下來(lái),分別介紹 Series 內(nèi)元素的增加、刪除、修改、訪問。

5.1.1 創(chuàng)建 Series

Series 的標(biāo)準(zhǔn)構(gòu)造函數(shù), 列舉常用的幾個(gè)參數(shù):

Series(data=None, index=None, dtype=None, name=None)

其中,data 為數(shù)據(jù)部分,index 為標(biāo)簽部分,省略下默認(rèn)為自增整數(shù)索引,dtype 為 str, numpy.dtype, or ExtensionDtype。

創(chuàng)建一個(gè) series,如下:

In [85]: ps = pd.Series(data=[-3,2,1],index=['a','f','b'],dtype=np.float32)     

In [86]: ps                                                                     
Out[86]: 
a   -3.0
f    2.0
b    1.0
dtype: float32
5.1.2 增加元素

在 ps 基礎(chǔ)上增加一個(gè)元素,使用 append,如下:

In [112]: ps.append(pd.Series(data=[-8.0],index=['f']))                         
Out[112]: 
a    4.0
f    2.0
b    1.0
f   -8.0
dtype: float64

可以看到,Pandas 允許包含重復(fù)的標(biāo)簽

In [114]: psn = ps.append(pd.Series(data=[-8.0],index=['f']))                   

In [115]: psn                                                                   
Out[115]: 
a    4.0
f    2.0
b    1.0
f   -8.0
dtype: float64

In [116]: psn['f']                                                              
Out[116]: 
f    2.0
f   -8.0
dtype: float64

利用標(biāo)簽訪問元素,返回所有帶標(biāo)簽的數(shù)據(jù)。

5.1.3 刪除元素

使用 drop 刪除指定標(biāo)簽的數(shù)據(jù),如下:

In [119]: ps                                                                    
Out[119]: 
a    4.0
f    2.0
b    1.0
dtype: float32

In [120]: psd = ps.drop('f')                                                    
In [121]: psd                                                                  
Out[121]: 
a    4.0
b    1.0
dtype: float32

注意不管是 append 操作,還是 drop 操作,都是發(fā)生在原數(shù)據(jù)的副本上,不是原數(shù)據(jù)上。

5.1.3 修改元素

修改數(shù)據(jù),直接通過(guò)修改的標(biāo)簽,更新對(duì)應(yīng)的數(shù)據(jù),就可以,如下所示:

In [123]: psn                                                                   
Out[123]: 
a    4.0
f    2.0
b    1.0
f   -8.0
dtype: float64

In [124]: psn['f'] = 10.0                                                       
In [125]: psn                                                                   
Out[125]: 
a     4.0
f    10.0
b     1.0
f    10.0
dtype: float64

標(biāo)簽相同的數(shù)據(jù)都被修改

5.1.4 訪問元素

訪問元素,Pandas 提供兩種方法,一是通過(guò)默認(rèn)的整數(shù)索引,或者在 Series 對(duì)象未被顯示的指定 label 時(shí),都是通過(guò)索引訪問;另一種方式是通過(guò)標(biāo)簽訪問。

In [126]: ps                                                                    
Out[126]: 
a    4.0
f    2.0
b    1.0
dtype: float32

In [128]: ps[2] # 索引訪問                              
Out[128]: 1.0

In [127]: ps['b']  # 標(biāo)簽訪問                                                             
Out[127]: 1.0

5.2 類二維數(shù)組 DataFrame

DataFrame 是 Pandas 的兩個(gè)重要數(shù)據(jù)結(jié)構(gòu)的另一個(gè),可以看做是 Series 的容器。

DataFrame 同時(shí)具有行、列標(biāo)簽,是二維的數(shù)組,行方向軸 axis 為 0, 列方向 axis 為 1,如下:

axis : {0 or 'index', 1 or 'columns'}
5.2.1 創(chuàng)建 DataFrame

DataFrame 構(gòu)造函數(shù)如下:

DataFrame(data=None, index=None, columns=None, dtype=None, copy=False)

參數(shù)意義與 Series 相似,不再贅述。創(chuàng)建 DataFrame 的常用方法:

In [134]: df = pd.DataFrame([['gz',4.0,'2019-01-01'],['lg',1.2,'2019-06-01']],in
     ...: dex = ['a','f'], columns = ['nm', 'y','da'])                          

In [135]: df                                                                    
Out[135]: 
   nm    y          da
a  gz  4.0  2019-01-01
f  lg  1.2  2019-06-01

也可以通過(guò)字典傳入,得到一樣的數(shù)據(jù)框,如下:

In [136]: df2 = pd.DataFrame({'nm':['gz','lg'],'y':[4.0,1.2], 'da':['2019-01-01'
     ...: , '2019-06-01']},index = ['a','f'])                                   

In [137]: df2                                                                   
Out[137]: 
   nm    y          da
a  gz  4.0  2019-01-01
f  lg  1.2  2019-06-01
5.2.1 增加數(shù)據(jù)

通過(guò)增加一個(gè) Series,擴(kuò)充到 DataFrame 中,如下所示:

In [143]: dfn = df.append(pd.Series(data=['zx',3.6,'2019-05-01'],index=['nm','y'
     ...: ,'da'],name='b'))                                                     

In [144]: dfn                                                                   
Out[144]: 
   nm    y          da
a  gz  4.0  2019-01-01
f  lg  1.2  2019-06-01
b  zx  3.6  2019-05-01

Series 的 index 與數(shù)據(jù)框的 column 對(duì)齊,name 與數(shù)據(jù)框的 index 對(duì)齊。

5.2.2 刪除數(shù)據(jù)

與 Series 刪除類似,也是使用 drop 刪除指定索引或標(biāo)簽的數(shù)據(jù),如下,注意刪除仍然是在 dfn 的副本上進(jìn)行的,像下面這樣刪除對(duì) dfn 沒有任何影響。

In [145]: dfn.drop('b')                                                         
Out[145]: 
   nm    y          da
a  gz  4.0  2019-01-01
f  lg  1.2  2019-06-01

如果要?jiǎng)h除某列,需要設(shè)定 axis 為 1, 如下所示:

In [147]: dfn.drop('y',axis=1)                                                  
Out[147]: 
   nm          da
a  gz  2019-01-01
f  lg  2019-06-01
b  zx  2019-05-01
5.2.3 修改數(shù)據(jù)

修改依然是先通過(guò)索引或標(biāo)簽定位到數(shù)據(jù),然后修改,如下所示:

In [151]: dfn.loc['a','da']='2019-04-01'                                        
In [152]: dfn                                                                   
Out[152]: 
   nm    y          da
a  gz  4.0  2019-04-01
f  lg  1.2  2019-06-01
b  zx  3.6  2019-05-01

修改數(shù)據(jù)作為入門,理解到這里或許可以了。但是要想進(jìn)階或真正成為 Pandas 專家,必須要了解一個(gè)關(guān)鍵點(diǎn):鏈?zhǔn)劫x值( chained assignment),大家可以自己先去查一查,在入門課程中,我們暫時(shí)不展開,后面進(jìn)階課程中會(huì)詳細(xì)聊一聊。

5.2.4 訪問數(shù)據(jù)

最新幾個(gè)版本,Pandas 推薦使用訪問接口 iloc、loc、訪問數(shù)據(jù),詳細(xì)使用如下:

In [153]: df                                                                    
Out[153]: 
   nm    y          da
a  gz  4.0  2019-01-01
f  lg  1.2  2019-06-01

In [154]: df.iloc[1,:]                                                          
Out[154]: 
nm            lg
y            1.2
da    2019-06-01
Name: f, dtype: object

In [155]: df.loc['f',:]                                                         
Out[155]: 
nm            lg
y            1.2
da    2019-06-01
Name: f, dtype: object

In [156]: df.loc['f','nm']                                                      
Out[156]: 'lg'

5.3 必備的 20 個(gè)統(tǒng)計(jì)學(xué)函數(shù)

文章一開始,我們提到入門數(shù)據(jù)分析,需要了解一定的統(tǒng)計(jì)學(xué)知識(shí),常用的統(tǒng)計(jì)指標(biāo),比如眾數(shù)、均值、方差、四分位數(shù)等。好消息是,Pandas 中都實(shí)現(xiàn)類似這些統(tǒng)計(jì)指標(biāo),下面分別列舉:

函數(shù)英文術(shù)語(yǔ)中文
count Number of non-null observations 觀測(cè)值的個(gè)數(shù)
sum Sum of values 求和
mean Mean of values 求平均值
mad Mean absolute deviation 平均絕對(duì)方差
median Arithmetic median of values 中位數(shù)
min Minimum 最小值
max Maximum 最大值
mode Mode 眾數(shù)
abs Absolute Value 絕對(duì)值
prod Product of values 乘積
std Bessel-corrected sample standard deviation 標(biāo)準(zhǔn)差
var Unbiased variance 方差
sem Standard error of the mean 標(biāo)準(zhǔn)誤差
skew Sample skewness (3rd moment) 偏度系數(shù)
kurt Sample kurtosis (4th moment) 峰度
quantile Sample quantile (value at %) 分位數(shù)
cumsum Cumulative sum 累加
cumprod Cumulative product 累乘
cummax Cumulative maximum 累最大值
cummin Cumulative minimum 累最小值
cov() covariance 協(xié)方差
corr() correlation 相關(guān)系數(shù)
rank() rank by values 排名
pct_change() time change 時(shí)間序列變化

以上 20 個(gè),都在 Pandas 中對(duì)應(yīng)有詳細(xì)的意義解釋,大家可以自己去研究,在此不再詳細(xì)展開。

5.4 必備的缺失值處理技巧

Pandas 提供了一些便利的函數(shù),可以幫助我們快速按照設(shè)想處理、解決空值。

空值處理的第一招:快速確認(rèn)數(shù)據(jù)集中是不是存在空值。有兩個(gè)函數(shù) isnull、notnull,可以幫助我們快速定位數(shù)據(jù)集中每個(gè)元素是否為空值。

數(shù)據(jù)源如下所示:

In [165]: dfn                                                                   
Out[165]: 
   nm    y          da
a  gz  NaN  2019-04-01
f  lg  1.2         NaN
b  zx  3.6  2019-05-01

檢測(cè)哪些位置存在空值,如下:

In [166]: pd.isnull(dfn)                                                        
Out[166]: 
      nm      y     da
a  False   True  False
f  False  False   True
b  False  False  False

Pandas 對(duì)象某列或某行,直接拿 np.nan , None 判斷元素是否為空,發(fā)現(xiàn)返回的都是 False。注意:這樣做是不可取的!

第二招,假設(shè)存在空值,可以使用 Pandas 中的 fillna 函數(shù)填充空值,fillna 有一個(gè)關(guān)鍵參數(shù): method,當(dāng)設(shè)置 method 為 pad 時(shí),表示怎樣填充呢? 從上一個(gè)有效數(shù)據(jù)傳播到下一個(gè)有效數(shù)據(jù)行。

如下,使用默認(rèn)值 1.0 填充 y 列:

In [174]: dfn['y'] = dfn['y'].fillna(1.0)                                       
In [175]: dfn                                                                   
Out[175]: 
   nm    y          da
a  gz  1.0  2019-04-01
f  lg  1.2         NaN
b  zx  3.6  2019-05-01

第三招,檢測(cè)到了空值數(shù)據(jù),但是不想做任何填充,而是僅僅想丟棄這些空值數(shù)據(jù),Pandas 提供了 dropna 函數(shù)做這件事情。里面有兩個(gè)關(guān)鍵參數(shù):axis, how, 例如組合:axis = 0,how = any,表示某行只要某個(gè)元素為空值,就丟棄。

In [177]: dfn                                                                   
Out[177]: 
   nm    y          da
a  gz  1.0  2019-04-01
f  lg  1.2         NaN
b  zx  3.6  2019-05-01

In [178]: dfn.dropna(axis=0,how='any')                                          
Out[178]: 
   nm    y          da
a  gz  1.0  2019-04-01
b  zx  3.6  2019-05-01

5.5 必備的數(shù)據(jù)透視處理函數(shù)

Pandas 也有類似 Excel 中提供的數(shù)據(jù)透視功能。參考官方給出的一個(gè)數(shù)據(jù),介紹下 pivot_table 函數(shù)如何實(shí)現(xiàn)數(shù)據(jù)透視的。

構(gòu)造數(shù)據(jù):

In [182]: df = pd.DataFrame({"A": ["foo", "foo", "foo", "foo", "foo", 
     ...: ...                          "bar", "bar", "bar", "bar"], 
     ...: ...                    "B": ["one", "one", "one", "two", "two", 
     ...: ...                          "one", "one", "two", "two"], 
     ...: ...                    "C": ["small", "large", "large", "small", 
     ...: ...                          "small", "large", "small", "small", 
     ...: ...                          "large"], 
     ...: ...                    "D": [1, 2, 2, 3, 3, 4, 5, 6, 7], 
     ...: ...                    "E": [2, 4, 5, 5, 6, 6, 8, 9, 9]})             

In [183]: df                                                                    
Out[183]: 
     A    B      C  D  E
0  foo  one  small  1  2
1  foo  one  large  2  4
2  foo  one  large  2  5
3  foo  two  small  3  5
4  foo  two  small  3  6
5  bar  one  large  4  6
6  bar  one  small  5  8
7  bar  two  small  6  9
8  bar  two  large  7  9
In [216]: pd.pivot_table(df, values=['D','E'], index=['A','B'], columns='C',aggf
     ...: unc=[np.mean,np.max])                             

結(jié)果如下所示:

Out[216]: 
         mean                    amax                  
            D           E           D           E      
C       large small large small large small large small
A   B                                                  
bar one   4.0   5.0   6.0   8.0   4.0   5.0   6.0   8.0
    two   7.0   6.0   9.0   9.0   7.0   6.0   9.0   9.0
foo one   2.0   1.0   4.5   2.0   2.0   1.0   5.0   2.0
    two   NaN   3.0   NaN   5.5   NaN   3.0   NaN   6.0 

下面分步解析數(shù)據(jù)透視的過(guò)程

我們數(shù)據(jù)透視是以 A 和 B 兩列為 index,一旦選定,內(nèi)部實(shí)現(xiàn)中會(huì)根據(jù) A 和 B 形成一個(gè)多級(jí)索引,并對(duì)數(shù)據(jù)分組。第二維度,也就是 axis 為 1 的維度,設(shè)置為 C 列,這樣數(shù)據(jù)會(huì)被重構(gòu)為這種二維表,并且如果聚合函數(shù)缺省情況下,默認(rèn)統(tǒng)計(jì)平均值。

In [188]: pd.pivot_table(df, index=['A','B'],columns='C')                       

結(jié)果如下所示:

Out[206]: 
            D           E      
C       large small large small
A   B                          
bar one   4.0   5.0   6.0   8.0
    two   7.0   6.0   9.0   9.0
foo one   2.0   1.0   4.5   2.0
    two   NaN   3.0   NaN   5.5

當(dāng)為 pivot_table 設(shè)置上 values 來(lái)自哪些列,同時(shí)定義聚合函數(shù)后,就最終得到數(shù)據(jù)的透視結(jié)果。

以上就是 Pandas 里的一些關(guān)于數(shù)據(jù)分析的核心功能,當(dāng)然還有很多必備的功能,比如分組,排序,數(shù)據(jù)分箱,編碼......我們以后再聊。

Matplotlib

matplotlib 是基于 Python 語(yǔ)言的開源項(xiàng)目,旨在為 Python 提供一個(gè)數(shù)據(jù)繪圖包。

實(shí)際上,matplotlib 的對(duì)象體系嚴(yán)謹(jǐn)而有趣,為使用者提供了巨大的發(fā)揮空間。在熟悉了核心對(duì)象之后,可以輕易的定制圖像。

接下來(lái),介紹 matplotlib API 的核心對(duì)象,并介紹如何使用這些對(duì)象來(lái)實(shí)現(xiàn)繪圖。

6.1 必備的繪圖理論知識(shí)

先看一段代碼:

# object-oriented plot
from matplotlib.figure import Figure
from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas

fig = Figure()
canvas = FigureCanvas(fig)
ax = fig.add_axes([0.1, 0.1, 0.8, 0.8])
line,  = ax.plot([0,1], [0,1])
ax.set_title("a straight line ")
ax.set_xlabel("x label")
ax.set_ylabel("y label")
canvas.print_figure('chatpic1.jpg')

上面這段代碼,至少構(gòu)建了四個(gè)對(duì)象: fig( Figure 類), canvas( FigureCanvas 類), ax( Axes 類), line(Line2D 類)。

在 matplotlib 中,整個(gè)圖像為一個(gè)Figure?對(duì)象,在?Figure?對(duì)象中可以包含一個(gè)或多個(gè)?Axes?對(duì)象,每個(gè)Axes對(duì)象都是一個(gè)擁有自己坐標(biāo)系統(tǒng)的繪圖區(qū)域。

Axes?由?xaxis,?yaxis,?title,?data?構(gòu)成,xaxis?由坐標(biāo)軸的線 ,tick以及label構(gòu)成,如下圖所示:

enter image description here

上段代碼中,ax = fig.add_axes([0.1, 0.1, 0.8, 0.8]),參數(shù)含義代表比例,分別表示:圖形區(qū)域的左邊界距離整個(gè) figure 左側(cè) 10% ,底部 10%,寬度和高度都為整個(gè) figure 寬度和高度的 80%。

rect : sequence of float
        The dimensions [left, bottom, width, height] of the new axes. All
        quantities are in fractions of figure width and height.

canvas 對(duì)象,代表了真正進(jìn)行繪圖的后端(backend)。

在具備這些繪圖的基本理論知識(shí)后,再去使用 matplotlib 庫(kù)時(shí),就順手多了。

6.2 繪圖必備 100 行代碼

Matplotlib 中提供了一個(gè)類似于 Matlab 的繪圖模塊,非常易用,尤其是對(duì)于入門者,非常容易上手。

如果熟練使用這個(gè)模塊,繪制常見的數(shù)據(jù)分析可視化圖,已經(jīng)基本沒有任何問題了。

下面,我們參考哈佛大學(xué)關(guān)于這部分的課程材料,結(jié)合平時(shí)常用的,提煉成 100 行代碼,應(yīng)該是最精簡(jiǎn)的可視化 100 行代碼了。

導(dǎo)入繪圖模塊:

import matplotlib
import matplotlib.pyplot as plt           

導(dǎo)入 NumPy 模塊:

import numpy as np   

準(zhǔn)備數(shù)據(jù):

x = np.linspace(0, 5, 10) 
y = x ** 2  

繪制折線圖:

plt.plot(x, y, 'r') 
plt.xlabel('x') 
plt.ylabel('y') 
plt.title('title') 
plt.show() 

enter image description here第一種繪制多圖的方法:

plt.subplot(1,2,1) 
plt.plot(x, y, 'r--') 
plt.subplot(1,2,2) 
plt.plot(y, x, 'g*-') 
plt.show()   

enter image description here

第二種繪制多圖的方法:

fig = plt.figure()

axes1 = fig.add_axes([0.1, 0.1, 0.8, 0.8]) # main axes
axes2 = fig.add_axes([0.2, 0.5, 0.4, 0.3]) # insert axes

# 主圖
axes1.plot(x, y, 'r')
axes1.set_xlabel('x')
axes1.set_ylabel('y')
axes1.set_title('title')

# 插入的圖
axes2.plot(y, x, 'g')
axes2.set_xlabel('y')
axes2.set_ylabel('x')
axes2.set_title('insert title')

enter image description here

第三種繪制多圖的方法:

fig, axes = plt.subplots(nrows=1, ncols=2)

for ax in axes:
    ax.plot(x, y, 'r')
    ax.set_xlabel('x')
    ax.set_ylabel('y')
    ax.set_title('title')

enter image description here

保存圖片:

fig.savefig("chatpic33.png")

設(shè)置圖例: legend

fig, ax = plt.subplots()

ax.plot(x, x**2, label="y = x**2")
ax.plot(x, x**3, label="y = x**3")
ax.legend(loc=2); # 上、左角
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_title('title');

enter image description here

設(shè)置字體,大?。?/strong>

matplotlib.rcParams.update({'font.size': 18, 'font.family': 'serif'})

設(shè)置 latex 格式:

ax.plot(x, x**2, label=r"`$y = \alpha^2$`")

設(shè)置顏色,線條:

fig, ax = plt.subplots()

ax.plot(x, x 1, color="red", alpha=0.5) # 半透明紅色
ax.plot(x, x 2, color="#1155dd")        # 十六進(jìn)制RGB
ax.plot(x, x 3, color="#15cc55")        

enter image description here

添加網(wǎng)格 grid:

fig, axes = plt.subplots(1, 2, figsize=(10,3))

# 默認(rèn)網(wǎng)格顯示
axes[0].plot(x, x**2, x, x**3, lw=2)
axes[0].grid(True)

# 定制網(wǎng)格顯示
axes[1].plot(x, x**2, x, x**3, lw=2)
axes[1].grid(color='b', alpha=0.5, linestyle='dashed', linewidth=0.5)

enter image description here

雙軸顯示:

fig, ax1 = plt.subplots()

ax1.plot(x, x**2, lw=2, color="blue")
ax1.set_ylabel(r"area `$(m^2)$`", fontsize=18, color="blue")
for label in ax1.get_yticklabels():
    label.set_color("blue")

ax2 = ax1.twinx()
ax2.plot(x, x**3, lw=2, color="red")
ax2.set_ylabel(r"volume `$(m^3)$`", fontsize=18, color="red")
for label in ax2.get_yticklabels():
    label.set_color("red")

enter image description here

更多的二維圖形展示:

xx = np.linspace(-0.75, 1., 100)

n = np.array([0,1,2,3,4,5])

fig, axes = plt.subplots(1, 4, figsize=(12,3))

axes[0].scatter(xx, xx   0.25*np.random.randn(len(xx)))
axes[0].set_title("scatter")

axes[1].step(n, n**2, lw=2)
axes[1].set_title("step")

axes[2].bar(n, n**2, align="center", width=0.5, alpha=0.5)
axes[2].set_title("bar")

axes[3].fill_between(x, x**2, x**3, color="green", alpha=0.5);
axes[3].set_title("fill_between")

enter image description here

文本標(biāo)注:

fig, ax = plt.subplots()

ax.plot(xx, xx**2, xx, xx**3)

ax.text(0.15, 0.2, r"`$y=x^2$`", fontsize=20, color="blue")
ax.text(0.65, 0.1, r"`$y=x^3$`", fontsize=20, color="green");

enter image description here

三維圖繪制:

from mpl_toolkits.mplot3d.axes3d import Axes3D

alpha = 0.7
phi_ext = 2 * np.pi * 0.5

def flux_qubit_potential(phi_m, phi_p):
    return 2   alpha - 2 * np.cos(phi_p) * np.cos(phi_m) - alpha * np.cos(phi_ext - 2*phi_p)

phi_m = np.linspace(0, 2*np.pi, 100)
phi_p = np.linspace(0, 2*np.pi, 100)

X,Y = np.meshgrid(phi_p, phi_m)
Z = flux_qubit_potential(X, Y).T

fig = plt.figure(figsize=(14,6))

ax = fig.add_subplot(1, 2, 1, projection='3d')

p = ax.plot_surface(X, Y, Z, rstride=4, cstride=4, linewidth=0)


ax = fig.add_subplot(1, 2, 2, projection='3d')
p = ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap=matplotlib.cm.coolwarm, linewidth=0, antialiased=False)

cb = fig.colorbar(p, shrink=0.5)

enter image description here

機(jī)器學(xué)習(xí)線性回歸模型

數(shù)據(jù)分析也和機(jī)器學(xué)習(xí)密不可分,對(duì)于手上的數(shù)據(jù),我們想了解它最后回歸哪個(gè)模型,此時(shí)機(jī)器學(xué)習(xí)的回歸算法就是不二之選。

接下來(lái),先介紹一些機(jī)器學(xué)習(xí)的基本概念,幫助不熟悉機(jī)器學(xué)習(xí)的小伙伴快速做個(gè)概念普及。

7.1 11 個(gè)必備基本概念

  1. 數(shù)據(jù)集(data set) 記錄的集合,假如我們用 3 個(gè)特征,分別為色澤,根蒂,響聲來(lái)描述西瓜的特點(diǎn),并且拿到了基于這3個(gè)特征的 10 萬(wàn)條記錄。如果記錄到.csv文件中,這個(gè)文件的結(jié)構(gòu)可以記為: fruit[100000][3] ,這樣一個(gè)二維數(shù)組,行數(shù)為 10 萬(wàn),列數(shù)為 3(因?yàn)橛?3 個(gè)特征)。

  2. 屬性(attribute) 反映事件或?qū)ο笤谀撤矫娴谋憩F(xiàn)或性質(zhì)的事項(xiàng),例如色澤,根蒂,響聲等,又稱為特征(feature)。屬性上的取值,如青綠,濁響等,稱為屬性值(attribute value)。

  3. 樣本空間(sample space) 又稱為屬性空間(attribute space),或輸入空間。它可以理解為訓(xùn)練數(shù)據(jù)中實(shí)際出現(xiàn)的所有屬性值構(gòu)成的集合空間,如上文中提到的 10 萬(wàn)條西瓜記錄,每條記錄有 3 個(gè)屬性取值,組成了一個(gè) fruit[100000][3] 的樣本空間。

  4. 假設(shè)空間(hypothetical space) 和樣本空間有點(diǎn)類似,它是理論上的所有可能屬性值構(gòu)成的集合空間。

  5. 特征向量(feature vector) 假如將色澤,根蒂,敲聲三個(gè)屬性作為三個(gè)坐標(biāo)軸 x1, x2, x3,每個(gè)西瓜對(duì)應(yīng)一個(gè)空間點(diǎn)(一個(gè)坐標(biāo)向量),每個(gè)這種示例稱為一個(gè)特征向量,記為 (x1, x2, x3 )。

  6. 標(biāo)記(label) 關(guān)于示例結(jié)果的信息,比如判斷一個(gè)西瓜是好瓜,那么這個(gè)西瓜便擁有了標(biāo)記示例,這個(gè)西瓜便成了樣例(example)。一般用 Xi , yi 表示第 i 個(gè)樣例,其中 yi 是示例 Xi 的標(biāo)記。

  7. 學(xué)習(xí)(learning) 從數(shù)據(jù)中學(xué)得模型的過(guò)程,又稱為訓(xùn)練(training)。正如上文所示,10萬(wàn)條西瓜數(shù)據(jù)集,根據(jù)它的三個(gè)特征,和每條特征的標(biāo)記,經(jīng)過(guò)計(jì)算最后得到了一個(gè) f,通過(guò)這個(gè) f 我們能預(yù)測(cè)第 10001 個(gè)西瓜是否是好瓜,這個(gè)過(guò)程被稱為學(xué)習(xí)。

  8. 訓(xùn)練數(shù)據(jù) (training data) 訓(xùn)練過(guò)程中使用的數(shù)據(jù),其中每個(gè)樣本稱為一個(gè)訓(xùn)練樣本(training sample),訓(xùn)練樣本組成的集合稱為訓(xùn)練集(training set)。通過(guò)這些訓(xùn)練數(shù)據(jù)通過(guò)學(xué)習(xí),最終得出一個(gè) f,也就是我們學(xué)到的模型。與之相對(duì)應(yīng)的是測(cè)試數(shù)據(jù),為了測(cè)試通過(guò)訓(xùn)練數(shù)據(jù)得到的f準(zhǔn)確度能高不高,我們特意預(yù)留出一些數(shù)據(jù)用來(lái)專門測(cè)試用,這部分?jǐn)?shù)據(jù)就被稱為測(cè)試數(shù)據(jù)。

  9. 回歸(regression) 如果預(yù)測(cè)的是連續(xù)值,例如預(yù)測(cè)西瓜的成熟度 ,它必然是個(gè)大于 0 的小數(shù)值,比如成熟度為 0.9,0.75,抑或是根據(jù)房屋面積,使用年限兩個(gè)特征預(yù)測(cè)某個(gè)房屋的價(jià)值,類似這種預(yù)測(cè)稱為回歸。

  10. 分類(classification) 如果我們要預(yù)測(cè)的是離散值,等于 0,1,2,3 等這類離散值,例如好瓜,壞瓜,稱此類學(xué)習(xí)任務(wù)為分類。如果分類的結(jié)果為兩類,又稱此分類為二分類,通常稱其中一個(gè)為正類(positive class),另一個(gè)為反類(negative class)。

  11. 聚類(clustering) 沒有標(biāo)記的記錄集,并且我們還想學(xué)習(xí)這類數(shù)據(jù)集,比如想從里頭挖出點(diǎn)有用的東西來(lái)。然后我們根據(jù)某些特征和算法將訓(xùn)練中的西瓜分成若干組,自動(dòng)形成了幾簇,這些簇可能對(duì)應(yīng)一些潛在的概念,比如淺色瓜,深色瓜,本地瓜,這些概念我們都是事先不知道的。

7.2 三 個(gè)假定

我們拿到數(shù)據(jù)后,做完數(shù)據(jù)整理(前面章節(jié)中提到)和特征分析后,接下來(lái)想知道這些數(shù)據(jù)特征對(duì)目標(biāo)函數(shù)的影響模型,即做數(shù)據(jù)回歸。

為了簡(jiǎn)化我們的模型,選用線性數(shù)學(xué)模型。

為了保證線性數(shù)學(xué)模型能夠取得成功,有兩個(gè)前提假定非常重要。

  1. 假設(shè)真實(shí)值與預(yù)測(cè)值的誤差項(xiàng)????服從高斯分布,它直接影響線性回歸模型是否取得成功,因?yàn)槿绻麛?shù)據(jù)都是離散的,用線性回歸預(yù)測(cè)準(zhǔn)確度肯定不好。

  2. 預(yù)測(cè)的數(shù)據(jù)分布和訓(xùn)練時(shí)用到的數(shù)據(jù)分布是相同的

  3. 假定每個(gè)樣本之間發(fā)生與否都是無(wú)關(guān)的,這樣確保每個(gè)樣本發(fā)生都是獨(dú)立的。

7.3 建立線性回歸模型

因?yàn)榈?ii?個(gè)樣本的誤差項(xiàng)??(i)?(i)?服從高斯分布,因此可得:

f(?(i))=1√2πσe(??(i)22σ2)f(?(i))=12πσe(??(i)22σ2)

因?yàn)榻⒌氖蔷€性數(shù)學(xué)模型,因此第?ii?個(gè)樣本根據(jù)模型預(yù)測(cè)值為:

enter image description here

又知,誤差項(xiàng)(又稱代價(jià)函數(shù)或成本函數(shù)):

?(i)=f(x(i)|θ)?y(i)?(i)=f(x(i)|θ)?y(i)以上式子中:x(i),yix(i),yi?分別表示第?ii?個(gè)樣本的實(shí)際取值,nn?表示特征的個(gè)數(shù)

綜上可得:?enter image description here

至此,我們得到一個(gè)只含有?n 1n 1?個(gè)特征參數(shù)的等式,ff?表示誤差取值的概率。

一般選用最大似然估計(jì)求權(quán)重參數(shù),接下來(lái)介紹。

7.4 最大似然估計(jì)求參數(shù)

最大似然估計(jì)就是根據(jù)讓已經(jīng)發(fā)生的數(shù)據(jù)取值概率最大,上面說(shuō)到的第 3 個(gè)假定就是樣本是否發(fā)生是各自獨(dú)立的,所以?mm?個(gè)樣本誤差的概率 f(?(i))f(?(i))?都出現(xiàn)的概率可以轉(zhuǎn)化為概率的乘積:

m∏i=1f(?(i))∏i=1mf(?(i))

顯示中樣本個(gè)數(shù)?mm?很大,因?yàn)橛质歉怕?,所以相乘的結(jié)果會(huì)很小,一般轉(zhuǎn)化為對(duì)數(shù),因此,又稱最大對(duì)數(shù)似然估計(jì),可得公式為:

avatar

結(jié)合已經(jīng)得出的公式:

avatar最終得到:

avatar

上式,就變?yōu)橹缓?nn?個(gè)未知權(quán)重參數(shù),求解最大值的優(yōu)化問題。 [help me with MathJax]

7.5 梯度下降求解優(yōu)化問題

梯度下降求解的是最小值,因此需要對(duì)上節(jié)式子取反后求最小值,故:?avatar

接下來(lái),求出?J(θi)J(θi)?對(duì)權(quán)重參數(shù)?θiθi?的偏導(dǎo)數(shù),這個(gè)不難求,回想下高中知識(shí),便可以得出。

每次迭代時(shí)步,θiθi?的更新公式:?avatar

其中?ηη?就是學(xué)習(xí)率

至此公式推導(dǎo)全部結(jié)束,下面手寫編碼實(shí)現(xiàn)。

7.6 手寫不調(diào)包實(shí)現(xiàn)的 5 個(gè)算子

算法框架包括以下 5 個(gè)算子:

'model' 建立的線性回歸模型

'cost' 代價(jià)函數(shù)

'gradient'  梯度公式

'theta update'  參數(shù)更新公式

'stop stratege'  迭代停止策略:代價(jià)函數(shù)小于閾值法

下面分別寫出以上五步的具體實(shí)現(xiàn)代碼,

model

def model(theta,X):

    theta = np.array(theta)

    return X.dot(theta)

cost

def cost(m,theta,X,y):

    'print(theta)'

    ele = y - model(theta,X)

    item = ele**2

    item_sum = np.sum(item)

    return item_sum/2/m

gradient

def gradient(m,theta,X,y,cols):

    grad_theta = []

    for j in range(cols):

        grad = (y-model(theta,X)).dot(X[:,j])

        grad_sum = np.sum(grad)    

        grad_theta.append(-grad_sum/m)

    return np.array(grad_theta)

theta update

def theta_update(grad_theta,theta,sigma):

    return theta - sigma * grad_theta

stop stratege

def stop_stratege(cost,cost_update,threshold):

    return cost-cost_update < threshold

7.7 手寫不調(diào)包實(shí)現(xiàn)的整體算法框架

OLS 算法整體框架如下所示

def OLS(X,y,threshold):

    start = time.clock()

    '樣本個(gè)數(shù)'

    m=100

    '設(shè)置權(quán)重參數(shù)的初始值'

    theta = [0,0,0]

    '迭代步數(shù)'

    iters = 0;

    '記錄代價(jià)函數(shù)的值'

    cost_record=[]

    '學(xué)習(xí)率'

    sigma = 0.0001

    cost_val = cost(m,theta,X,y)

    cost_record.append(cost_val)

    while True:

        grad = gradient(m,theta,X,y,3)

        '參數(shù)更新'

        theta = theta_update(grad,theta,sigma)

        cost_update = cost(m,theta,X,y)

        if stop_stratege(cost_val,cost_update,threshold):

            break

        iters=iters 1

        cost_val = cost_update

        cost_record.append(cost_val)

    end = time.clock()

    print("OLS convergence duration: %f s" % (end - start))

    return cost_record, iters,theta

面試及資料分享

在介紹零基礎(chǔ)完整入門數(shù)據(jù)分析的基本理論,工具包使用,機(jī)器學(xué)習(xí)的一個(gè)算法完整算法模型后,你需要多去動(dòng)手實(shí)踐,強(qiáng)化這些基本的方法論。

然后,你就可以著手準(zhǔn)備面試了。下面分享一些面試真人實(shí)錄,感謝公眾號(hào)內(nèi)一些鐵粉貢獻(xiàn)的寶貴面試材料。

下面節(jié)選的這個(gè)面試難度中等偏上,這個(gè)崗位主要還是偏算法多一些,對(duì)數(shù)據(jù)的處理分析考核少了一些。

之所以節(jié)選這個(gè)面試,是因?yàn)橄胍蠹抑R(shí)面更廣一些,因?yàn)榍懊嫠v主要偏數(shù)據(jù)分析,借助這個(gè)面試大家可以了解到更多與數(shù)據(jù)挖掘相關(guān)的一些面試常問到的算法。

大家快來(lái)看看了解多少吧,不會(huì)的也不要慌張,先把這些這篇面試中提問到的搞清楚。

8.1 數(shù)據(jù)挖掘工程師面試實(shí)錄

感謝公眾號(hào)鐵粉地球球長(zhǎng)貢獻(xiàn)的面試經(jīng)歷。

面試某獨(dú)角獸公司校招,面試地點(diǎn)是在北京某高校里面。

8.1.1 一 面
  1. 邏輯回歸損失函數(shù) 我的回答:對(duì)數(shù)損失,或者預(yù)測(cè)值與實(shí)際值的交叉熵?fù)p失。

  2. 如果樣本不均衡,需要在損失函數(shù)上做操作,該怎么處理? 我的回答:這個(gè)之前沒遇到過(guò),不過(guò)處理樣本均衡可以通過(guò)下采樣和上采樣等方法。

  3. 伯努利分布概率為 P,執(zhí)行 N 次中 k 次發(fā)生,用極大似然估計(jì)估算P的值 我的回答:在紙上寫出了二項(xiàng)式分布的概率函數(shù)作為似然函數(shù),P 為參數(shù),求 argmax, (似然函數(shù)求導(dǎo)為零得到)P=k/N。

  4. L1, L2 正則化。L1 正則化項(xiàng)怎么求導(dǎo) 我的回答:L1, L2 正則化主要為了防止過(guò)擬合,控制模型復(fù)雜度,使其具有更好的泛化能力。L2 正則化從貝葉斯理論看,參數(shù)分布服從高斯先驗(yàn)。L2 范數(shù)是各個(gè)參數(shù)平方和,是每個(gè)w2i<Cwi2<C的條件下最小化訓(xùn)練損失(經(jīng)驗(yàn)損失)Loss,根據(jù)拉格朗日乘子法可以得到L = 訓(xùn)練損失 入 L2 范數(shù);L2 能起到壓縮參數(shù)的作用。L2 正則化從貝葉斯理論看,參數(shù)分布服從拉普拉斯先驗(yàn)。L1 范數(shù)是各個(gè)參數(shù)絕對(duì)值之和,是每個(gè)|wi|<C|wi|<C?的條件下最小化訓(xùn)練損失(經(jīng)驗(yàn)損失)Loss,根據(jù)拉格朗日乘子法可以得到L = 訓(xùn)練損失 入L1 范數(shù);L1 范數(shù)能起到是參數(shù)稀疏化作用,又是可以作為特征選擇。同時(shí),L0 正則化是真正起到稀疏化作用,可以認(rèn)為 L1 正則化是 L0 正則化的近似,因?yàn)長(zhǎng)0 正則化是NP問題,可能是非凸的,而且不易求導(dǎo)比較難用凸優(yōu)化求解。L1 正則化在 0 點(diǎn)出不可導(dǎo),一般做近似平滑處理,其他點(diǎn)得到 W 的符號(hào)。 (當(dāng)時(shí)感覺回答完這個(gè)問題,進(jìn)二面沒啥問題了)

  5. 決策樹算法以及防止過(guò)擬合方法。信息增益率比信息增益多了什么? 我的回答:我先介紹了自信息,信息熵(自信息的期望),信息增益等相關(guān)概念?;谛畔⒃鲆娴?ID3,基于信息增益率的 C4.5,基于基尼指數(shù)的 CART 等剪枝:后剪枝,預(yù)剪枝(調(diào)節(jié)樹的深度,葉子的樣本個(gè)數(shù)等方式),隨機(jī)森林 Bagging 信息增益率相比于信息增益可以認(rèn)為做了一個(gè)約束,除以原樣本信息熵,避免用信息增益因類別過(guò)多一下子就全部分開,分成很矮,葉子很多的樹(這里表達(dá)可能不太準(zhǔn)確)。

  6. 寫出 SVM 損失函數(shù),如果過(guò)擬合,怎么參數(shù)調(diào)整 C 我的回答:我寫出了正則項(xiàng),讓他給點(diǎn)提示。他說(shuō)合頁(yè)損失,給我畫了損失函數(shù)圖并和 LeRu 做比較。C求和?yif(xi) 12||w||yif(xi) 12||w||,如果過(guò)擬合,應(yīng)該減小 C。這里如果除以 C,那么參數(shù)就被整合到了正則項(xiàng)里面,可能更好理解。還有如果因用到核函數(shù)過(guò)擬合,降低核函數(shù)復(fù)雜度。 [help me with MathJax]

  7. 隨機(jī)森林與 boosting 區(qū)別 我的回答:他們都是集成學(xué)習(xí)方法,學(xué)習(xí)多個(gè)有差異且有一定精確度(>50%)的弱分類器。主要區(qū)別隨機(jī)森林用到并行,boosting 通常情況下串行(這個(gè)不是很完整)。

  8. Xgboost在GBDT基礎(chǔ)上做了哪些改進(jìn) 我的回答:Xgboost 是陳天奇大神在 GBDT 基礎(chǔ)上提出來(lái)的,最大差別損失函數(shù)用到了二階導(dǎo)數(shù)的信息。在特征粒度裂解上用到了并行處理,加快速度。特征裂解位置預(yù)先計(jì)算,做了排序并緩存,按百分位選擇,而不是像 GBDT 全部遍歷貪心選擇。用到的損失函數(shù)用到自定義的 GINI 系數(shù)。同時(shí)基分類器不僅僅是回歸樹,可以是加了 L1L2 正則化的線性分類器等 (在網(wǎng)上看了好多改進(jìn),說(shuō)了這幾個(gè)主要的)。

8.1.2 二 面
  1. 求 sqrt()

  2. 一個(gè)數(shù)組,求除了某元素自身位置之外的其他元素累積,生成一個(gè)同長(zhǎng)度的數(shù)組。要求不能用除法,時(shí)間復(fù)雜度 O(n),輔助空間 O(1)

  3. 又問了 SVM 參數(shù)怎么調(diào)

  4. 又問了決策樹怎么防止過(guò)擬合

  5. 問了 L1,L2 正則化的作用,為什么

  6. 決策樹算法:特征是連續(xù)值,特征是離散值的處理

  7. 一道幾何概型的簡(jiǎn)單題 (畫個(gè)圖求面積比)

  8. 趣味題,如果一把槍彈夾里有六個(gè)子彈,其中有兩個(gè)子彈會(huì)打死人,四個(gè)不會(huì)有受傷。假如面試官打了自己一槍沒死,現(xiàn)在把槍交給你,你得朝自己開一槍,問開槍之前,你是否會(huì)讓彈夾旋轉(zhuǎn),切換子彈。

8.1.3 三面

就問了一個(gè)問題:如何用int_8位整型數(shù)據(jù),模擬兩個(gè)int_32位整型數(shù)據(jù)相乘(寫代碼實(shí)現(xiàn)) (給了許多提示還是沒寫出來(lái),掛了。)

8.2 推薦哈佛大學(xué)數(shù)據(jù)分析課程

這個(gè)課程是專門選用 Python 做數(shù)據(jù)分析的,并且上課選擇的材料,使用的是現(xiàn)實(shí)中的數(shù)據(jù),所以極其寶貴。大家一定要好好利用。

下面是課程的大綱:

enter image description here

課程網(wǎng)址:

哈佛大學(xué)數(shù)據(jù)分析課程入口

小結(jié)

chat 開頭我們介紹到現(xiàn)實(shí)社會(huì)是離不開數(shù)據(jù)分析的,然后介紹了數(shù)據(jù)分析入門學(xué)習(xí)路線,從三方便準(zhǔn)備,分別是統(tǒng)計(jì)學(xué)基本知識(shí)、機(jī)器學(xué)習(xí)基本算法、編程語(yǔ)言及工具。

第二章介紹了數(shù)據(jù)分析重頭戲:數(shù)據(jù)整理,分別探討了,理解你的業(yè)務(wù)數(shù)據(jù),明確各個(gè)特征的類型,找出異常數(shù)據(jù),不得不面對(duì)缺失值,令人頭疼的數(shù)據(jù)不均衡問題。

第三章介紹了 Python 入門必備知識(shí),包括理解解釋型和編譯型, Python 最常用的對(duì)象,包括:list 核心知識(shí),dict 核心知識(shí),tuple 和 set 簡(jiǎn)介。Python 入門必備知識(shí)點(diǎn),包括:對(duì)象上的特殊函數(shù),列表生成式

第四章介紹了 NumPy 入門必備知識(shí),包括 ndarray 對(duì)象,以及 NumPy 的最重要的兩大機(jī)制: 向量化增強(qiáng),NumPy 的傳播機(jī)制。

第五章介紹了 Pandas 數(shù)據(jù)分析必備入門知識(shí)。類一維數(shù)組 Series,包括創(chuàng)建Series、增加元素、刪除元素、修改元素、訪問元素。類二維數(shù)組 DataFrame 包括:創(chuàng)建 DataFrame、增加數(shù)據(jù)、刪除數(shù)據(jù)、修改數(shù)據(jù)、訪問數(shù)據(jù)。后面介紹了必備的 20 個(gè)統(tǒng)計(jì)學(xué)函數(shù),必備的缺失值處理技巧、必備的數(shù)據(jù)透視處理函數(shù)。

第六章介紹了 Matplotlib 的必備的繪圖理論知識(shí),根據(jù)哈佛大學(xué)的經(jīng)典課程,總結(jié)了繪圖必備 100 行代碼,包括展示了 14 幅圖,其中多圖繪制,各種二維和三維圖可視化,顏色、字體設(shè)置,latex符號(hào)設(shè)置,網(wǎng)格設(shè)置等。

第七章,介紹了 機(jī)器學(xué)習(xí)線性回歸模型,包括介紹了 11 個(gè)必備基本概念。線性回歸模型的 3 個(gè)假定,基于假定,建立線性回歸模型,最大似然估計(jì)求參數(shù),利用梯度下降求解優(yōu)化問題,最后手寫不調(diào)包實(shí)現(xiàn) 5 個(gè)算子,還有最終的整體算法框架

第八章介紹了面試和資料分享,面試數(shù)據(jù)挖掘工程師的真實(shí)實(shí)錄,包括一 面、二 面、三面。最后推薦了哈佛大學(xué)的一門經(jīng)典數(shù)據(jù)分析課程。

最后感謝大家的參與,文中的難免出現(xiàn)表述不準(zhǔn)確之處,歡迎小伙伴們批評(píng)指正。

預(yù)祝在校的學(xué)弟學(xué)妹,學(xué)業(yè)有成;工作的兄弟姐妹,工作順利!

如果覺得 chat 還可以的,還算走心的,歡迎幫助點(diǎn)贊和轉(zhuǎn)發(fā),讓這篇 chat 可以幫助到更多小伙伴。

來(lái)源:http://www./content-4-172751.html

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多

    婷婷伊人综合中文字幕| 久久中文字幕中文字幕中文| 国产自拍欧美日韩在线观看| 插进她的身体里在线观看骚| 国产精品偷拍一区二区| 视频一区二区三区自拍偷| 高清不卡一卡二卡区在线| 国产亚洲中文日韩欧美综合网| 亚洲精品国男人在线视频| 日本加勒比在线播放一区| 国产精品欧美激情在线播放| 加勒比人妻精品一区二区| 欧美丰满大屁股一区二区三区| 日本国产欧美精品视频| 亚洲男人的天堂久久a| 日本加勒比中文在线观看| 日本女人亚洲国产性高潮视频| 日韩不卡一区二区三区色图| 不卡在线播放一区二区三区| 热情的邻居在线中文字幕| 日韩免费av一区二区三区| 大胆裸体写真一区二区| 草草视频精品在线观看| 国产成人精品一区二三区在线观看| 国产精品一区二区传媒蜜臀| 熟女体下毛荫荫黑森林自拍| 欧美精品亚洲精品日韩专区| 亚洲中文字幕剧情在线播放| 国内欲色一区二区三区| 老司机激情五月天在线不卡 | 中日韩美一级特黄大片| 亚洲综合色在线视频香蕉视频 | 色播五月激情五月婷婷| 国产成人精品午夜福利av免费| 日韩性生活视频免费在线观看| 国产爆操白丝美女在线观看| 亚洲av熟女国产一区二区三区站| 夫妻性生活真人动作视频| 99久久精品国产日本| 免费观看潮喷到高潮大叫| 国产av一区二区三区四区五区|