利用Pandas動(dòng)手學(xué)數(shù)據(jù)分析學(xué)習(xí)記錄
本文首發(fā)在知識(shí)星球打卡內(nèi)容上(BrainTechnology星球),此文章中所有鏈接均通過博客進(jìn)行訪問。

本文學(xué)習(xí)主要為打卡內(nèi)容使用,非教程課程。
本學(xué)習(xí)教程來源:https://gitee.com/datawhalechina/hands-on-data-analysis
本內(nèi)容任務(wù)安排
Task01:數(shù)據(jù)加載及探索性數(shù)據(jù)分析(2天)
了解數(shù)據(jù)加載以及數(shù)據(jù)觀察
掌握pandas基礎(chǔ)
完成探索性數(shù)據(jù)分析
主要學(xué)習(xí)內(nèi)容是:課程的第一章123節(jié)
Task02:數(shù)據(jù)清洗及特征處理(2天)
掌握數(shù)據(jù)清洗的方法
了解特征觀察與處理
主要學(xué)習(xí)內(nèi)容是:課程的第二章的第1部分(數(shù)據(jù)清洗及特征處理)
Task03:數(shù)據(jù)重構(gòu)(2天)
了解數(shù)據(jù)重構(gòu)的方法
使用groupby做數(shù)據(jù)運(yùn)算
主要學(xué)習(xí)內(nèi)容是:課程的第二章第2、3部分(數(shù)據(jù)重構(gòu))
Task04:數(shù)據(jù)可視化(2天)
了解可視化的目的
知道各種圖形可用于的場(chǎng)景
實(shí)戰(zhàn)數(shù)據(jù)可視化的基本庫(kù)
主要學(xué)習(xí)內(nèi)容是:課程的第二章第4部分(數(shù)據(jù)可視化)
Task05:數(shù)據(jù)建模及模型評(píng)估(2天)
了解數(shù)據(jù)建模
使用sklearn完成分類模型的建模
了解模型評(píng)估
使用sklearn完成模型評(píng)估
主要學(xué)習(xí)內(nèi)容是:課程的第三章(數(shù)據(jù)建模及模型評(píng)估)
本次學(xué)習(xí)根據(jù)課程大綱安排,將在2021年9月12日-2021年9月22日完成學(xué)習(xí)
以下內(nèi)容為打卡學(xué)習(xí)內(nèi)容:
首先在學(xué)習(xí)之前需要一些先前知識(shí),懂一點(diǎn)Python和pandas的使用,可以參考學(xué)習(xí)輔助資料網(wǎng)址:http://joyfulpandas.datawhale.club/Content/ch1.html
Task 00 安裝jupyter和熟悉以上網(wǎng)址
我當(dāng)前使用的電腦是MacBook Pro ,因此只需要安裝好anaconda就會(huì)自帶Jupyter,在終端中可輸入jupyter notebook/jupyter-notebook或者python3 -m IPython notebook即可打開
準(zhǔn)備資料內(nèi)容:圖書《Python for Data Analysis》第六章
Task 01 數(shù)據(jù)加載及探索性數(shù)據(jù)分析
第一章第一節(jié)
#數(shù)據(jù)集下載https://www.kaggle.com/c/titanic/overview
#第一步導(dǎo)入numpy和pandas
import numpy as np
import pandas as pd
#第二步加載數(shù)據(jù)
#相對(duì)路徑
df = pd.read_csv('train.csv')
df.head(3)
#絕對(duì)路徑
df = pd.read_csv('/Users/chenrui/Desktop/hands-on-data-analysis-master/第一單元項(xiàng)目集合/train.csv')
df.head(3)
#嘗試使用os.getcwd()查看當(dāng)前工作路徑時(shí),需要先import os
#第三步逐塊讀取
chunker = pd.read_csv('train.csv',chunksize = 1000)
#思考:什么是逐塊讀?。繛槭裁匆饓K讀取呢?
#設(shè)置chunksize參數(shù),來控制每次迭代數(shù)據(jù)的大小
chunker = pd.read_csv("train.csv",chunksize=1000)
for piece in chunker:
print(type(piece))
#<class 'pandas.core.frame.DataFrame'>
print(len(piece))
#891
#第四步將表頭改成中文
df = pd.read_csv('train.csv', names=['乘客ID','是否幸存','倉(cāng)位等級(jí)','姓名','性別','年齡','兄弟姐妹個(gè)數(shù)','父母子女個(gè)數(shù)','船票信息','票價(jià)','客艙','登船港口'],index_col='乘客ID',header=0)
df.head()
#查看數(shù)據(jù)基本信息
df.info()
#查看表格前十行和后15行數(shù)據(jù)
df.head(10)
df.tail(15)
#判斷數(shù)據(jù)是否為空,判斷數(shù)據(jù)是否為空,為空的地方返回True,其余地方返回False
df.isnull().head()
#思考:對(duì)于一個(gè)數(shù)據(jù),還可以從哪些方面來觀察?
df.describe()
#獲取每列數(shù)據(jù)的統(tǒng)計(jì)特征
# .describe()即可查看每列數(shù)據(jù)
'''
(1)總行數(shù)統(tǒng)計(jì)count
(2)平均值mean
(3)標(biāo)準(zhǔn)差std
(4)最小值min
(5)25%分位值“25%”
(6)50%分位值“50%”
(7)75%分位值“75%”
(8)最大值max
'''
#保存數(shù)據(jù)
df.to_csv('train_test.csv')

第一章第二節(jié)
認(rèn)識(shí)數(shù)據(jù),了解數(shù)據(jù)字段含義
#任務(wù)一:pandas中有兩個(gè)數(shù)據(jù)類型DateFrame和Series
#series:類似于1維數(shù)組,由索引+數(shù)值組成
#dataframe是非常常見的一個(gè)表格型數(shù)據(jù)結(jié)構(gòu),每一列可以是不同的數(shù)值類型,有行索引、列索引。提到它就會(huì)自然想到Pandas這個(gè)包。平常用Python處理xlsx、csv文件,讀出來的就是dataframe格式。
#參考鏈接:https://zhuanlan.zhihu.com/p/41092771
#加載庫(kù)
import numpy as np
import pandas as pd
#Series的展示
sdata = {'0hio':35000,'Texas':71000,'0regon':16000,'Utah':5000}
example_1 = pd.Series(sdata)
example_1
#DataFrame的展示
data = {'state': ['Ohio', 'Ohio', 'Ohio', 'Nevada', 'Nevada', 'Nevada'],
'year': [2000, 2001, 2002, 2001, 2002, 2003],'pop': [1.5, 1.7, 3.6, 2.4, 2.9, 3.2]}
example_2 = pd.DataFrame(data)
example_2
#任務(wù)二:加載數(shù)據(jù)集“train.csv”文件
#使用相對(duì)路徑加載,并展示前三行數(shù)據(jù)
df = pd.read_csv('train.csv')
df.head(3)
#任務(wù)三:查看DataFrame數(shù)據(jù)的每列名稱
df.columns
#任務(wù)四:查看“Cabin”這列數(shù)據(jù)的所有值
df['Cabin'].head(3) #第一種方法讀取
df.Cabin.head(3) #第二種方法讀取
#任務(wù)五:加載數(shù)據(jù)集“test_1.csv”,對(duì)比train.csv,
test_1 = pd.read_csv('test_1.csv')
test_1.head(3)
#刪除多余的列
del test_1['a']
test_1.head(3)
#思考:還有其他的刪除多余的列的方式嗎?
#使用drop方法進(jìn)行隱藏,加上參數(shù)inplace = True,則將原數(shù)據(jù)覆蓋。
#test_1.drop('a',axis = 1,inplace = True)
test_1.drop('a',axis=1,inplace=True)
test_1.head(3)
#任務(wù)六:將【“Passengerld”,"Name","Age","Ticket"】這幾個(gè)元素隱藏
df.drop(['PassengerId','Name','Age','Ticket'],axis = 1).head(3)
#篩選的邏輯,選出所需要信息,舍棄無用信息。
#任務(wù)一:以“Age”為篩選條件,顯示年齡在10歲以下的乘客信息
df[df["Age"] < 10].head(3)
#任務(wù)二: 以"Age"為條件,將年齡在10歲以上和50歲以下的乘客信息顯示出來,并將這個(gè)數(shù)據(jù)命名為midage
midage = df[(df["Age"]>10)& (df["Age"]<50)]
midage.head(3)
#任務(wù)三:使用reset_index重置索引,顯示數(shù)據(jù)
midage = midage.reset_index(drop=True)
midage.head(3)
#任務(wù)四:使用loc方法將midage數(shù)據(jù)的第100,105,108行的"Pclass","Name"和"Sex"的數(shù)據(jù)顯示出來
midage.loc[[100,105,108],['Pclass','Name','Sex']]
#任務(wù)五:使用iloc方法將midage的數(shù)據(jù)中第100,105,108行的"Pclass","Name"和"Sex"的數(shù)據(jù)顯示出來
midage.iloc[[100,105,108],[2,3,4]]
#思考:對(duì)比iloc和loc的異同
#loc函數(shù)主要基于行標(biāo)簽和列標(biāo)簽(x_label、y_label)進(jìn)行索引:使用loc函數(shù),索引的是字符串。
#iloc函數(shù)主要基于行索引和列索引(index,columns) 都是從 0 開始:而且,iloc函數(shù)索引的數(shù)據(jù)是int整型,因此是Python默認(rèn)的前閉后開。注意只能說int型,也就是數(shù)字,輸入字符的話是會(huì)報(bào)錯(cuò)的。
第一章第三節(jié)
利用pandas進(jìn)行排序、計(jì)算及描述describe()的使用,本節(jié)內(nèi)容參考《利用Python進(jìn)行數(shù)據(jù)分析》第五章
#加載庫(kù)
import numpy as np
import pandas as pd
#載入之前保存的train_chinese.csv數(shù)據(jù),關(guān)于泰坦尼克號(hào)的任務(wù),我們就使用這個(gè)數(shù)據(jù)
text = pd.read_csv('train_chinese.csv')#相對(duì)路徑
text.head(3)
#任務(wù)一:利用pandas進(jìn)行數(shù)據(jù)排序,升序
#構(gòu)建一個(gè)都為數(shù)字的DataFrame數(shù)據(jù)
frame = pd.DataFrame(np.arange(8).reshape((2, 4)),
index=['2', '1'],
columns=['d', 'a', 'b', 'c'])
frame
#代碼解析
'''
pd.DataFrame() :創(chuàng)建一個(gè)DataFrame對(duì)象
np.arange(8).reshape((2, 4)) : 生成一個(gè)二維數(shù)組(2*4),第一列:0,1,2,3 第二列:4,5,6,7
index=['2, 1] :DataFrame 對(duì)象的索引列
columns=['d', 'a', 'b', 'c'] :DataFrame 對(duì)象的索引行
'''
# 將構(gòu)建的DataFrame中的數(shù)據(jù)根據(jù)某一列,升序排列,可以看到sort_values這個(gè)函數(shù)中by參數(shù)指向要排列的列,ascending參數(shù)指向排序的方式(升序還是降序)
frame.sort_values(by='c', ascending=True)
# 讓行索引升序排序
frame.sort_index()
# 讓列索引升序排序
frame.sort_index(axis=1)
# 讓列索引降序排序
frame.sort_index(axis=1, ascending=False)
# 讓任選兩列數(shù)據(jù)同時(shí)降序排序
frame.sort_values(by=['a', 'c'], ascending=False)
#任務(wù)二:對(duì)train.csv數(shù)據(jù)按票價(jià)和年齡兩列進(jìn)行降序排列,sort_values這個(gè)函數(shù)中by參數(shù)
text.sort_values(by=['票價(jià)', '年齡'], ascending=False).head(3)
#任務(wù)三:利用pandas進(jìn)行算術(shù)計(jì)算,計(jì)算兩個(gè)DataFrame數(shù)據(jù)
frame1_a = pd.DataFrame(np.arange(9.).reshape(3, 3),
columns=['a', 'b', 'c'],
index=['one', 'two', 'three'])
frame1_b = pd.DataFrame(np.arange(12.).reshape(4, 3),
columns=['a', 'e', 'c'],
index=['first', 'one', 'two', 'second'])
frame1_a
frame1_b
#將framel_a和frame_b進(jìn)行相加
frame1_a + frame1_b
#任務(wù)4:計(jì)算train.csv中在船上最大家族有多少人,相加計(jì)算個(gè)數(shù)
max(text['兄弟姐妹個(gè)數(shù)'] + text['父母子女個(gè)數(shù)'])
#任務(wù)5:學(xué)會(huì)使用pandas describe()函數(shù)查看數(shù)據(jù)基本統(tǒng)計(jì)信息
frame2 = pd.DataFrame([[1.4, np.nan],
[7.1, -4.5],
[np.nan, np.nan],
[0.75, -1.3]
], index=['a', 'b', 'c', 'd'], columns=['one', 'two'])
frame2
#使用describe()函數(shù)查看基本信息
frame2.describe()
'''
count : 樣本數(shù)據(jù)大小
mean : 樣本數(shù)據(jù)的平均值
std : 樣本數(shù)據(jù)的標(biāo)準(zhǔn)差
min : 樣本數(shù)據(jù)的最小值
25% : 樣本數(shù)據(jù)25%的時(shí)候的值
50% : 樣本數(shù)據(jù)50%的時(shí)候的值
75% : 樣本數(shù)據(jù)75%的時(shí)候的值
max : 樣本數(shù)據(jù)的最大值
'''
#任務(wù)6:查看數(shù)據(jù)中票價(jià)、父母子女的基本統(tǒng)計(jì)
'''
看看泰坦尼克號(hào)數(shù)據(jù)集中 票價(jià) 這列數(shù)據(jù)的基本統(tǒng)計(jì)數(shù)據(jù)
'''
text['票價(jià)'].describe()
text['父母子女個(gè)數(shù)'].describe()
本章節(jié)內(nèi)容主要介紹了Python中的數(shù)據(jù)導(dǎo)入庫(kù)以及pandas中使用內(nèi)置函數(shù)讀取數(shù)據(jù)集,及對(duì)數(shù)據(jù)集的基本信息統(tǒng)計(jì),排序和相加等。
Task02:數(shù)據(jù)清洗及特征處理(2天)
本章節(jié)內(nèi)容:數(shù)據(jù)分析的流程性學(xué)習(xí),主要是包括了數(shù)據(jù)清洗以及數(shù)據(jù)的特征處理,數(shù)據(jù)重構(gòu)以及數(shù)據(jù)可視化
#加載所需庫(kù)
import numpy as np
import pandas as pd
#加載數(shù)據(jù)集train.csv
df = pd.read_csv('train.csv')
df.head(3)數(shù)據(jù)清洗 :數(shù)據(jù)中有缺失值,有一些異常點(diǎn)等,需要經(jīng)過一定的處理才能繼續(xù)做后面的分析或建模,所以拿到數(shù)據(jù)的第一步是進(jìn)行數(shù)據(jù)清洗。
第二章第一節(jié)
#缺失值觀察與處理
#任務(wù)一:缺失值 觀察
#(1) 請(qǐng)查看每個(gè)特征缺失值個(gè)數(shù)
#(2) 請(qǐng)查看Age, Cabin, Embarked列的數(shù)據(jù)
#方法一,使用info
df.info()
#方法二,isnull是否是缺失值
df.isnull().sum()
#查看age等數(shù)據(jù)
df[['Age','Cabin','Embarked']].head(3)
#任務(wù) 二:對(duì)缺失值進(jìn)行處理
#(1)處理缺失值一般有幾種思路
#1.對(duì)于缺失值的一般思路有兩種,一種是當(dāng)缺失值個(gè)數(shù)只是占一小部分時(shí),將缺失部分直接刪除。第二種是對(duì)缺失值進(jìn)行填充。填充方法可以是全局常量填充、統(tǒng)計(jì)數(shù)字填充、插值法、KNN填充等。
#(2) 請(qǐng)嘗試對(duì)Age列的數(shù)據(jù)的缺失值進(jìn)行處理,嘗試使用填充的方法,使用.fillna函數(shù)
#data.isnull().sum()
#(3) 請(qǐng)嘗試使用不同的方法直接對(duì)整張表的缺失值進(jìn)行處理
#查找缺失值的三種方法
df[df['Age']==None]=0
df.head(3)
df[df['Age'].isnull()] = 0 # 還好
df.head(3)
df[df['Age'] == np.nan] = 0
df.head()
#【思考】檢索空缺值用np.nan,None以及.isnull()哪個(gè)更好,這是為什么?如果其中某個(gè)方式無法找到缺失值,原因又是為什么?
#【回答】數(shù)值列讀取數(shù)據(jù)后,空缺值的數(shù)據(jù)類型為float64所以用None一般索引不到,比較的時(shí)候最好用np.nan
df.dropna().head(3)
df.fillna(0).head(3)
#【思考】dropna和fillna有哪些參數(shù),分別如何使用呢?
"""
dropna函數(shù)的參數(shù):
axis: 默認(rèn)axis=0。0為按行刪除,1為按列刪除
how: 默認(rèn) ‘a(chǎn)ny’。 ‘a(chǎn)ny’指帶缺失值的所有行/列;'all’指清除一整行/列都是缺失值的行/列
thresh: int,保留含有int個(gè)非nan值的行
subset: 刪除特定列中包含缺失值的行或列
inplace: 默認(rèn)False,即篩選后的數(shù)據(jù)存為副本,True表示直接在原數(shù)據(jù)上更改
fillna函數(shù)的參數(shù):
inplace參數(shù)的取值:True、False
True:直接修改原對(duì)象
False:創(chuàng)建一個(gè)副本,修改副本,原對(duì)象不變(缺省默認(rèn))
method參數(shù)的取值 : {‘pad’, ‘ffill’,‘backfill’, ‘bfill’, None}, default None
pad/ffill:用前一個(gè)非缺失值去填充該缺失值
backfill/bfill:用下一個(gè)非缺失值填充該缺失值
None:指定一個(gè)值去替換缺失值(缺省默認(rèn)這種方式)
limit參數(shù):限制填充個(gè)數(shù)
axis參數(shù):修改填充方向
"""
#重復(fù)值觀察與處理
#任務(wù)一:查看數(shù)據(jù)中的重復(fù)值
df[df.duplicated()]
#任務(wù)二:對(duì)重復(fù)值進(jìn)行處理
#(1)重復(fù)值有哪些處理方式呢?提取出來或刪除
#(2)處理我們數(shù)據(jù)的重復(fù)值,使用.drop_duplicates()函數(shù)
df = df.drop_duplicates()
df.head()
#任務(wù)三:將前面清洗的數(shù)據(jù)保存csv
df.to_csv('test_clear.csv')
#特征觀察與處理
'''
特征大概分為兩大類:
數(shù)值型特征:Survived ,Pclass, Age ,SibSp, Parch, Fare,其中Survived, Pclass為離散型數(shù)值特征,Age,SibSp, Parch, Fare為連續(xù)型數(shù)值特征
文本型特征:Name, Sex, Cabin,Embarked, Ticket,其中Sex, Cabin, Embarked, Ticket為類別型文本特征。
數(shù)值型特征一般可以直接用于模型的訓(xùn)練,但有時(shí)候?yàn)榱四P偷姆€(wěn)定性及魯棒性會(huì)對(duì)連續(xù)變量進(jìn)行離散化。文本型特征往往需要轉(zhuǎn)換成數(shù)值型特征才能用于建模分析。
'''
#任務(wù)一:對(duì)年齡進(jìn)行分箱(離散化)處理
#(1) 分箱操作是什么?
#分箱操作就是對(duì)連續(xù)變量離散化,特征離散化,分箱操作后模型會(huì)更穩(wěn)定,降低了模型過擬合的風(fēng)險(xiǎn)。主要方法有等距分箱法、等頻分箱法。
#(2) 將連續(xù)變量Age平均分箱成5個(gè)年齡段,并分別用類別變量12345表示
df['AgeBand'] = pd.cut(df['Age'], 5,labels = [1,2,3,4,5])
df.head()
df.to_csv('test_ave.csv')
#(3) 將連續(xù)變量Age劃分為(0,5] (5,15] (15,30] (30,50] (50,80]五個(gè)年齡段,并分別用類別變量12345表示
df['AgeBand'] = pd.cut(df['Age'],[0,5,15,30,50,80],labels = [1,2,3,4,5])
df.head(3)
df.to_csv('test_cut.csv')
#(4) 將連續(xù)變量Age按10% 30% 50% 70% 90%五個(gè)年齡段,并用分類變量12345表示
df['AgeBand'] = pd.qcut(df['Age'],[0,0.1,0.3,0.5,0.7,0.9],labels = [1,2,3,4,5])
df.head()
df.to_csv('test_pr.csv')
#(5) 將上面的獲得的數(shù)據(jù)分別進(jìn)行保存,保存為csv格式
#df.to_csv('xx.csv')
#任務(wù)二:對(duì)文本變量進(jìn)行轉(zhuǎn)換
#(1) 查看文本變量名及種類
#方法一: value_counts
df['Sex'].value_counts()
df['Cabin'].value_counts()
df['Embarked'].value_counts()
#方法二: unique
df['Sex'].unique()
df['Sex'].nunique()
#(2) 將文本變量Sex, Cabin ,Embarked用數(shù)值變量12345表示
#方法一: replace
df['Sex_num'] = df['Sex'].replace(['male','female'],[1,2])
df.head()
#方法二: map
df['Sex_num'] = df['Sex'].map({'male': 1, 'female': 2})
df.head()
#方法三: 使用sklearn.preprocessing的LabelEncoder
from sklearn.preprocessing import LabelEncoder
for feat in ['Cabin', 'Ticket']:
lbl = LabelEncoder()
label_dict = dict(zip(df[feat].unique(), range(df[feat].nunique())))
df[feat + "_labelEncode"] = df[feat].map(label_dict)
df[feat + "_labelEncode"] = lbl.fit_transform(df[feat].astype(str))
df.head()
#(3) 將文本變量Sex, Cabin, Embarked用one-hot編碼表示
#方法: OneHotEncoder
for feat in ["Age", "Embarked"]:
# x = pd.get_dummies(df["Age"] // 6)
# x = pd.get_dummies(pd.cut(df['Age'],5))
x = pd.get_dummies(df[feat], prefix=feat)
df = pd.concat([df, x], axis=1)
#df[feat] = pd.get_dummies(df[feat], prefix=feat)
df.head()
#任務(wù)三(附加):從純文本Name特征里提取出Titles的特征(所謂的Titles就是Mr,Miss,Mrs等)
df['Title'] = df.Name.str.extract('([A-Za-z]+)\.', expand=False)
df.head()
# 保存上面的為最終結(jié)論
df.to_csv('test_fin.csv')
Task03:數(shù)據(jù)重構(gòu)(2天)
本章節(jié)做的是數(shù)據(jù)重構(gòu)。
#加載庫(kù)
import numpy as np
import pandas as pd
#加載數(shù)據(jù)集
text = pd.read_csv('/Users/chenrui/Desktop/hands-on-data-analysis-master/第二章項(xiàng)目集合/data/train-left-up.csv')
text.head()第二章第二節(jié)
數(shù)據(jù)重構(gòu)
#數(shù)據(jù)合并
#任務(wù)一:加載data文件夾中所有數(shù)據(jù),觀察與之前原始數(shù)據(jù)相比的關(guān)系
text_left_up = pd.read_csv("data/train-left-up.csv")
text_left_down = pd.read_csv("data/train-left-down.csv")
text_right_up = pd.read_csv("data/train-right-up.csv")
text_right_down = pd.read_csv("data/train-right-down.csv")
text_left_up.head()
text_left_down.head()
text_right_up.head()
text_right_down.head()
#任務(wù)二:使用concat方法,將數(shù)據(jù)train-left-up.csv和train-right-up.csv橫向合并為一張表,并保存這張表為result_up
list_up = [text_left_up,text_right_up] #選擇數(shù)據(jù)
result_up = pd.concat(list_up,axis=1) #賦值
result_up.head()
#任務(wù)三:使用concat方法:將train-left-down和train-right-down橫向合并為一張表,并保存這張表為result_down。然后將上邊的result_up和result_down縱向合并為result
list_down=[text_left_down,text_right_down]
result_down = pd.concat(list_down,axis=1)
result = pd.concat([result_up,result_down])
result.head()
#思考 一次性合并
#任務(wù)四:使用DataFrame自帶的方法join方法和append:完成任務(wù)二和任務(wù)三的任務(wù)
'''
join是對(duì)兩個(gè)表進(jìn)行行索引,列拼接的函數(shù),直接使用df1.join(df2)就可以,
append相當(dāng)于concat函數(shù)在axis=0上進(jìn)行合并
'''
resul_up = text_left_up.join(text_right_up)
result_down = text_left_down.join(text_right_down)
result = result_up.append(result_down)
result.head()
#任務(wù)五:使用Panads的merge方法和DataFrame的append方法:完成任務(wù)二和任務(wù)三的任務(wù)
'''
pandas.merge()函數(shù)參數(shù)說明:
left和right:兩個(gè)不同的DataFrame或Series
how:連接方式,有inner、left、right、outer,默認(rèn)為inner
on:用于連接的列索引名稱,必須同時(shí)存在于左、右兩個(gè)DataFrame中,默認(rèn)是以兩個(gè)DataFrame列名的交集作為連接鍵,若要實(shí)現(xiàn)多鍵連接,‘on’參數(shù)后傳入多鍵列表即可
left_on:左側(cè)DataFrame中用于連接鍵的列名,這個(gè)參數(shù)在左右列名不同但代表的含義相同時(shí)非常有用;
right_on:右側(cè)DataFrame中用于連接鍵的列名
left_index:使用左側(cè)DataFrame中的行索引作為連接鍵( 但是這種情況下最好用JOIN)
right_index:使用右側(cè)DataFrame中的行索引作為連接鍵( 但是這種情況下最好用JOIN)
sort:默認(rèn)為False,將合并的數(shù)據(jù)進(jìn)行排序,設(shè)置為False可以提高性能
suffixes:字符串值組成的元組,用于指定當(dāng)左右DataFrame存在相同列名時(shí)在列名后面附加的后綴名稱,默認(rèn)為(’_x’, ‘_y’)
copy:默認(rèn)為True,總是將數(shù)據(jù)復(fù)制到數(shù)據(jù)結(jié)構(gòu)中,設(shè)置為False可以提高性能
indicator:顯示合并數(shù)據(jù)中數(shù)據(jù)的來源情況
'''
result_up = pd.merge(text_left_up,text_right_up,left_index=True,right_index=True)
result_down = pd.merge(text_left_down,text_right_down,left_index=True,right_index=True)
result = resul_up.append(result_down)
result.head()
#保存數(shù)據(jù)
result.to_csv('result.csv')
#換一種角度看數(shù)據(jù)
#任務(wù)一 :將數(shù)據(jù)變?yōu)镾eries類型
'''
使用stack()函數(shù)將DataFrame數(shù)據(jù)變?yōu)镾eries數(shù)據(jù),stack()又叫做堆疊,將DataFrame數(shù)據(jù)的行索引變?yōu)榱兴饕?。相?dāng)于DataFrame數(shù)據(jù)的每一行作為一個(gè)集合,這一行行中每個(gè)特征對(duì)應(yīng)的表頭作為Series數(shù)據(jù)中的索引,特征值表示為Series數(shù)據(jù)中的值
'''
text = pd.read_csv('result.csv')#讀取 數(shù)據(jù)
text.head()
unit_result=text.stack().head(20)#使用stack函數(shù)
unit_result.head()
unit_result.to_csv('unit_result.csv')#保存數(shù)據(jù)
test = pd.read_csv('unit_result.csv')#讀取 數(shù)據(jù)
test.head()第二章第三節(jié)
數(shù)據(jù)重構(gòu)2
#導(dǎo)入數(shù)據(jù)庫(kù)
import numpy as np
import pandas as pd
#加載數(shù)據(jù)文件:result.csv
text = pd.read_csv('result.csv')#相對(duì)文件
text.head()
#任務(wù)一:學(xué)習(xí)了解GroupBy機(jī)制
'''
分組統(tǒng)計(jì) - groupby功能
① 根據(jù)某些條件將數(shù)據(jù)拆分成組
② 對(duì)每個(gè)組獨(dú)立應(yīng)用函數(shù)
③ 將結(jié)果合并到一個(gè)數(shù)據(jù)結(jié)構(gòu)中
'''
#任務(wù)二:計(jì)算泰坦尼克號(hào)男性與女性的平均票價(jià)
df = text['Fare'].groupby(text['Sex'])
means = df.mean()
means
#任務(wù)三:統(tǒng)計(jì)泰坦尼克號(hào)中男女的存活人數(shù)
survived_sex = text['Survived'].groupby(text['Sex']).sum()
survived_sex.head()
#任務(wù)四:計(jì)算客艙不同等級(jí)的存活人數(shù)
survived_pclass = text['Survived'].groupby(text['Pclass'])
survived_pclass.sum()
#任務(wù)五:統(tǒng)計(jì)在不同等級(jí)的票中的不同年齡的船票花費(fèi)的平均值
text.groupby(['Pclass','Age'])['Fare'].mean().head()
#任務(wù)六:將任務(wù)二和任務(wù)三的數(shù)據(jù)合并,并保存到sex_fare_survived.csv
result = pd.merge(means,survived_sex,on='Sex')
result.to_csv('sex_fare_survived.csv')
#任務(wù)七:得出不同年齡的總的存活人數(shù),然后找出存活人數(shù)最多的年齡段,最后計(jì)算存活人數(shù)最高的存活率(存活人數(shù)/總?cè)藬?shù))
#不同年齡的存活人數(shù)
survived_age = text['Survived'].groupby(text['Age']).sum()
survived_age.head()
#找出最大值的年齡段
survived_age[survived_age.values==survived_age.max()]
#首先計(jì)算總?cè)藬?shù)
_sum = text['Survived'].sum()
print("sum of person:"+str(_sum))
precetn =survived_age.max()/_sum
print("最大存活率:"+str(precetn))
Task04:數(shù)據(jù)可視化(2天)
本章節(jié)主要學(xué)習(xí)數(shù)據(jù)可視化matplotlib庫(kù)。
第二章第四節(jié)
建議參考資料:數(shù)據(jù)分析最有用的25個(gè) Matplotlib圖
#加載庫(kù)numpy、pandas、matplotlib
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
#加載數(shù)據(jù)文件result.csv
text = pd.read_csv('result.csv')
text.head()
#如何讓人一眼 看懂?dāng)?shù)據(jù)
#任務(wù)一跟著書本第九章,了解matplotlib,自己創(chuàng)建一個(gè)數(shù)據(jù)項(xiàng),對(duì)其進(jìn)行基本可視化
'''
matplotlib是python的一個(gè)繪圖庫(kù),調(diào)用matplotlib庫(kù)繪圖一般用pyplot子模塊,其中有兩個(gè)需要注意:figure和axes。figure為所有繪圖操作定義了頂層的類對(duì)象Figure,相當(dāng)于提供了畫板;axes定義了畫板中的每一個(gè)繪圖對(duì)象axes,相當(dāng)于畫板中的每一個(gè)子圖。還有一個(gè)位pylab。
'''
#最基本的可視化圖案有哪些?分別適用于那些場(chǎng)景
'''
繪制圖表,常用圖如下:
plot,折線圖或點(diǎn)圖,實(shí)際是調(diào)用了line模塊下的Line2D圖表接口
scatter,散點(diǎn)圖,常用于表述兩組數(shù)據(jù)間的分布關(guān)系,也可由特殊形式下的plot實(shí)現(xiàn)
bar/barh,條形圖或柱狀圖,常用于表達(dá)一組離散數(shù)據(jù)的大小關(guān)系,比如一年內(nèi)每個(gè)月的銷售額數(shù)據(jù);默認(rèn)豎直條形圖,可選barh繪制水平條形圖
hist,直方圖,形式上與條形圖很像,但表達(dá)意義卻完全不同:直方圖用于統(tǒng)計(jì)一組連續(xù)數(shù)據(jù)的分區(qū)間分布情況,比如有1000個(gè)正態(tài)分布的隨機(jī)抽樣,那么其直方圖應(yīng)該是大致滿足鐘型分布;條形圖主要是適用于一組離散標(biāo)簽下的數(shù)量對(duì)比
pie,餅圖,主要用于表達(dá)構(gòu)成或比例關(guān)系,一般適用于少量對(duì)比
imshow,顯示圖像,根據(jù)像素點(diǎn)數(shù)據(jù)完成繪圖并顯示
'''
#任務(wù)二:可視化展示泰坦尼克號(hào)數(shù)據(jù)集中男女中生存人數(shù)分布情況(用柱狀圖)
sex = text.groupby('Sex')['Survived'].sum()
sex.plot.bar()
plt.title('survived_count')
plt.show()
#思考:計(jì)算出泰坦尼克號(hào)數(shù)據(jù)集中男女中死亡人數(shù),并可視化展示?
all_sum = result_data['Survived'].groupby(result_data['Sex']).count()
survived_sex = survived_sex.sum()
deth_sex = all_sum - survived_sex
deth_sex
#如何和男女生存人數(shù)可視化柱狀圖結(jié)合到一起?
deth_sex.index = deth_sex.index.map({'male':'deth_male','female':'deth_female'})
sex_data = survived_sex.append(deth_sex)
sex_data
#可視化
plt.bar(sex_data.index,sex_data)
plt.show()
#從柱狀圖中可以看出,男性的存活人數(shù)雖然多,但是死亡人數(shù)更多。總體來說男性的死亡率遠(yuǎn)遠(yuǎn)高于女性的死亡率。在由于前面統(tǒng)計(jì)的女性的平均票價(jià)高于男性,可能是女性的船艙位置較好,因此存活率較高。
#任務(wù)四:可視化展示泰坦尼克號(hào)數(shù)據(jù)集中不同票價(jià)的人生存和死亡人數(shù)分布情況。(用折線圖試試)(橫軸是不同票價(jià),縱軸是存活人數(shù))
# 計(jì)算不同票價(jià)中生存與死亡人數(shù) 1表示生存,0表示死亡
fare_sur = text.groupby(['Fare'])['Survived'].value_counts().sort_values(ascending=False)
fare_sur
# 排序后繪折線圖
fig = plt.figure(figsize=(20, 18))
fare_sur.plot(grid=True)
plt.legend()
plt.show()
# 排序前繪折線圖
fare_sur1 = text.groupby(['Fare'])['Survived'].value_counts()
fare_sur1
fig = plt.figure(figsize=(20, 18))
fare_sur1.plot(grid=True)
plt.legend()
plt.show()
#任務(wù)五:可視化展示泰坦尼克號(hào)數(shù)據(jù)集中不同倉(cāng)位等級(jí)的人生存和死亡人員的分布情況。(用柱狀圖)
# 1表示生存,0表示死亡
pclass_sur = text.groupby(['Pclass'])['Survived'].value_counts()
pclass_sur
#seaborn庫(kù)是基于matplotlib庫(kù)的一種更加便捷的繪圖庫(kù)。
import seaborn as sns
sns.countplot(x="Pclass", hue="Survived", data=text)
#思考:看到這個(gè)前面幾個(gè)數(shù)據(jù)可視化,說說你的第一感受和你的總結(jié)
#從可視化數(shù)據(jù)看出客艙等級(jí)越高的存活幾率更大些,同時(shí)男性的死亡率高于女性。
#任務(wù)六:可視化展示泰坦尼克號(hào)數(shù)據(jù)集中不同年齡的人生存與死亡人數(shù)分布情況
#構(gòu)建result_datas數(shù)據(jù)中Survived的FacetGrid()實(shí)例化對(duì)象
facet = sns.FacetGrid(text,hue='Survived',aspect=2)
#使用map函數(shù)進(jìn)行繪圖,使用核密度估計(jì)方法sns.kdeplot,x軸對(duì)象為年齡'Age',使用shade決定是否填充曲線下方面積
facet.map(sns.kdeplot,'Age',shade=True)
#設(shè)置x軸區(qū)間大小
facet.set(xlim=(0,text['Age'].max))
facet.add_legend()
plt.show()
#任務(wù)七:可視化展示泰坦尼克號(hào)數(shù)據(jù)集中不同倉(cāng)位等級(jí)的人年齡分布情況。(用折線圖試試)
text.Age[text.Pclass == 1].plot(kind='kde')
text.Age[text.Pclass == 2].plot(kind='kde')
text.Age[text.Pclass == 3].plot(kind='kde')
plt.xlabel("age")
plt.legend((1,2,3),loc="best")
plt.show()
Task05:數(shù)據(jù)建模及模型評(píng)估(2天)
第三章數(shù)據(jù)建模和模型評(píng)估
使用數(shù)據(jù)進(jìn)行建模,搭建一個(gè)預(yù)測(cè)模型或者其它模型,從模型結(jié)果中分析和評(píng)估模型。
使用泰坦尼克號(hào)的數(shù)據(jù)集,完成泰坦尼克號(hào)存活預(yù)測(cè)這個(gè)任務(wù)。
#加載所需庫(kù)
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from IPython.display import Image
'''
matplotlib.pyplot:Matplotlib是Python的繪圖庫(kù),其中的pyplot包封裝了很多畫圖的函數(shù)。Matplotlib.pyplot包含一系列類似 MATLAB 中繪圖函數(shù)的相關(guān)函數(shù)。
Seaborn是一種基于matplotlib的圖形可視化python libraty。它提供了一種高度交互式界面,便于用戶能夠做出各種有吸引力的統(tǒng)計(jì)圖表。同時(shí)它能高度兼容numpy與pandas數(shù)據(jù)結(jié)構(gòu)以及scipy與statsmodels等統(tǒng)計(jì)模式。
'''
plt.rcParams['font.sans-serif'] = ['SimHei'] # 用來正常顯示中文標(biāo)簽
plt.rcParams['axes.unicode_minus'] = False # 用來正常顯示負(fù)號(hào)
plt.rcParams['figure.figsize'] = (10, 6) # 設(shè)置輸出圖片大小
# 讀取原數(shù)據(jù)數(shù)集
train = pd.read_csv('train.csv')
#讀取清洗過的數(shù)據(jù)集
data = pd.read_csv('clear_data.csv')
'''
模型搭建:
處理完前面的數(shù)據(jù)我們就得到建模數(shù)據(jù),下一步是選擇合適模型
在進(jìn)行模型選擇之前我們需要先知道數(shù)據(jù)集最終是進(jìn)行監(jiān)督學(xué)習(xí)還是無監(jiān)督學(xué)習(xí)
模型的選擇一方面是通過我們的任務(wù)來決定的。
除了根據(jù)我們?nèi)蝿?wù)來選擇模型外,還可以根據(jù)數(shù)據(jù)樣本量以及特征的稀疏性來決定
剛開始我們總是先嘗試使用一個(gè)基本的模型來作為其baseline,進(jìn)而再訓(xùn)練其他模型做對(duì)比,最終選擇泛化能力或性能比較好的模型
'''
sklearn模型算法選擇路徑圖
#使用一個(gè)機(jī)器學(xué)習(xí)最常用的一個(gè)庫(kù)(sklearn)來完成我們的模型的搭建
#任務(wù)一:劃分訓(xùn)練集和測(cè)試集
'''
將數(shù)據(jù)集分為自變量和因變量
按比例切割訓(xùn)練集和測(cè)試集(一般測(cè)試集的比例有30%、25%、20%、15%和10%)
使用分層抽樣
設(shè)置隨機(jī)種子以便結(jié)果能復(fù)現(xiàn)
'''
from sklearn.model_selection import train_test_split
# 一般先取出X和y后再切割,有些情況會(huì)使用到未切割的,這時(shí)候X和y就可以用,x是清洗好的數(shù)據(jù),y是我們要預(yù)測(cè)的存活數(shù)據(jù)'Survived'
X = data
y = train['Survived']
# 對(duì)數(shù)據(jù)集進(jìn)行切割
X_train, X_test, y_train, y_test = train_test_split(X, y, stratify=y, random_state=0)
# 查看數(shù)據(jù)形狀
X_train.shape, X_test.shape
#任務(wù)二:模型建立
'''
創(chuàng)建基于線性模型的分類模型(邏輯回歸)
創(chuàng)建基于樹的分類模型(決策樹、隨機(jī)森林)
分別使用這些模型進(jìn)行訓(xùn)練,分別的到訓(xùn)練集和測(cè)試集的得分
查看模型的參數(shù),并更改參數(shù)值,觀察模型變化
'''
from sklearn.linear_model import LogisticRegression
from sklearn.ensemble import RandomForestClassifier
# 默認(rèn)參數(shù)邏輯回歸模型
lr = LogisticRegression()
lr.fit(X_train, y_train)
# 查看訓(xùn)練集和測(cè)試集score值
print("Training set score: {:.2f}".format(lr.score(X_train, y_train)))
print("Testing set score: {:.2f}".format(lr.score(X_test, y_test)))
# 調(diào)整參數(shù)后的邏輯回歸模型
lr2 = LogisticRegression(C=100)
lr2.fit(X_train, y_train)
print("Training set score: {:.2f}".format(lr2.score(X_train, y_train)))
print("Testing set score: {:.2f}".format(lr2.score(X_test, y_test)))
# 默認(rèn)參數(shù)的隨機(jī)森林分類模型
rfc = RandomForestClassifier()
rfc.fit(X_train, y_train)
print("Training set score: {:.2f}".format(rfc.score(X_train, y_train)))
print("Testing set score: {:.2f}".format(rfc.score(X_test, y_test)))
# 調(diào)整參數(shù)后的隨機(jī)森林分類模型
rfc2 = RandomForestClassifier(n_estimators=100, max_depth=5)
rfc2.fit(X_train, y_train)
print("Training set score: {:.2f}".format(rfc2.score(X_train, y_train)))
print("Testing set score: {:.2f}".format(rfc2.score(X_test, y_test)))
#任務(wù)三:輸出模型預(yù)測(cè)結(jié)果
'''
輸出模型預(yù)測(cè)分類標(biāo)簽
輸出不同分類標(biāo)簽的預(yù)測(cè)概率
'''
# 預(yù)測(cè)標(biāo)簽
pred = lr.predict(X_train)
# 看到0和1的數(shù)組
pred[:10]
# 預(yù)測(cè)標(biāo)簽概率
pred_proba = lr.predict_proba(X_train)
pred_proba[:10]
#模型搭建和評(píng)估-評(píng)估模型好不好用
'''
模型評(píng)估是為了知道模型的泛化能力。
交叉驗(yàn)證(cross-validation)是一種評(píng)估泛化性能的統(tǒng)計(jì)學(xué)方法,它比單次劃分訓(xùn)練集和測(cè)試集的方法更加穩(wěn)定、全面。
在交叉驗(yàn)證中,數(shù)據(jù)被多次劃分,并且需要訓(xùn)練多個(gè)模型。
最常用的交叉驗(yàn)證是 k 折交叉驗(yàn)證(k-fold cross-validation),其中 k 是由用戶指定的數(shù)字,通常取 5 或 10。
準(zhǔn)確率(precision)度量的是被預(yù)測(cè)為正例的樣本中有多少是真正的正例
召回率(recall)度量的是正類樣本中有多少被預(yù)測(cè)為正類
f-分?jǐn)?shù)是準(zhǔn)確率與召回率的調(diào)和平均
'''
#加載庫(kù)
import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
from IPython.display import Image
from sklearn.linear_model import LogisticRegression
from sklearn.ensemble import RandomForestClassifier
plt.rcParams['font.sans-serif'] = ['SimHei'] # 用來正常顯示中文標(biāo)簽
plt.rcParams['axes.unicode_minus'] = False # 用來正常顯示負(fù)號(hào)
plt.rcParams['figure.figsize'] = (10, 6) # 設(shè)置輸出圖片大小
#加載數(shù)據(jù),切分測(cè)試集和訓(xùn)練集
from sklearn.model_selection import train_test_split
# 一般先取出X和y后再切割,有些情況會(huì)使用到未切割的,這時(shí)候X和y就可以用,x是清洗好的數(shù)據(jù),y是我們要預(yù)測(cè)的存活數(shù)據(jù)'Survived'
data = pd.read_csv('clear_data.csv')
train = pd.read_csv('train.csv')
X = data
y = train['Survived']
# 對(duì)數(shù)據(jù)集進(jìn)行切割
X_train, X_test, y_train, y_test = train_test_split(X, y, stratify=y, random_state=0)
# 默認(rèn)參數(shù)邏輯回歸模型
lr = LogisticRegression()
lr.fit(X_train, y_train)
#任務(wù)一:交叉驗(yàn)證
'''
用10折交叉驗(yàn)證來評(píng)估之前的邏輯回歸模型
計(jì)算交叉驗(yàn)證精度的平均值
'''
#交叉驗(yàn)證在sklearn中的模塊為sklearn.model_selection
from sklearn.model_selection import cross_val_score
lr = LogisticRegression(C=100)
scores = cross_val_score(lr, X_train, y_train, cv=10)
# k折交叉驗(yàn)證分?jǐn)?shù)
scores
#平均交叉驗(yàn)證
print("Average cross-validation score: {:.2f}".format(scores.mean()))
'''
思考:k折越多的情況下會(huì)帶來什么樣的影響?
一般而言,k折越多,評(píng)估結(jié)果的穩(wěn)定性和保真性越高,不過整個(gè)計(jì)算復(fù)雜度越高。一種特殊的情況是k=m,m為數(shù)據(jù)集樣本個(gè)數(shù),這種特例稱為留一法,結(jié)果往往比較準(zhǔn)確
'''
#任務(wù)二:混淆矩陣
'''
計(jì)算二分類問題的混淆矩陣
計(jì)算精確率、召回率以及f-分?jǐn)?shù)
問題:什么是二分類問題的混淆矩陣,理解這個(gè)概念,知道它主要是運(yùn)算到什么任務(wù)中的
答:二分類問題的混淆矩陣是一個(gè)2維方陣,它主要用于評(píng)估二分類問題的好壞,它主要運(yùn)用于二分類任務(wù)中。實(shí)際上,多分類問題依然可以轉(zhuǎn)換為二分類問題進(jìn)行處理。
'''
from sklearn.metrics import confusion_matrix
from sklearn.metrics import classification_report
# 訓(xùn)練模型
lr = LogisticRegression(C=100)
lr.fit(X_train, y_train)
# 模型預(yù)測(cè)結(jié)果
pred = lr.predict(X_train)
# 混淆矩陣
print(confusion_matrix(y_train, pred))
# 精確率、召回率以及f1-score
print(classification_report(y_train, pred))
#任務(wù)三:ROC曲線
#繪制ROC曲線
'''
什么是ROC曲線,ROC曲線的存在是為了解決什么問題
ROC的全稱是Receiver Operating Characteristic Curve,中文名字叫“受試者工作特征曲線”,其主要的分析方法就是畫這條特征曲線,ROC曲線的存在主要用于衡量模型的泛化性能,即分類效果的好壞。
'''
#ROC曲線在sklearn中的模塊為sklearn.metrics
#ROC曲線下面所包圍的面積越大越好
from sklearn.metrics import roc_curve
fpr, tpr, thresholds = roc_curve(y_test, lr.decision_function(X_test))
plt.plot(fpr, tpr, label="ROC Curve")
plt.xlabel("FPR")
plt.ylabel("TPR (recall)")
# 找到最接近于0的閾值
close_zero = np.argmin(np.abs(thresholds))
plt.plot(fpr[close_zero], tpr[close_zero], 'o', markersize=10, label="threshold zero", fillstyle="none", c='k', mew=2)
plt.legend(loc=4)
'''
思考:對(duì)于多分類問題如何繪制ROC曲線?
經(jīng)典的ROC曲線適用于對(duì)二分類問題進(jìn)行模型評(píng)估,通常將它推廣到多分類問題的方式有兩種:對(duì)于每種類別,分別計(jì)算其將所有樣本點(diǎn)的預(yù)測(cè)概率作為閾值所得到的TPR和FPR值(是這種類別為正,其他類別為負(fù)),最后將每個(gè)取定的閾值下,對(duì)應(yīng)所有類別的TPR值和FPR值分別求平均,得到最終對(duì)應(yīng)這個(gè)閾值的TPR和FPR值。
首先,對(duì)于一個(gè)測(cè)試樣本:1)標(biāo)簽只由0和1組成,1的位置表明了它的類別(可對(duì)應(yīng)二分類問題中的“正”),0就表示其他類別(“負(fù)”);2)要是分類器對(duì)該測(cè)試樣本分類正確,則該樣本標(biāo)簽中1對(duì)應(yīng)的位置在概率矩陣P中的值是大于0對(duì)應(yīng)的位置的概率值的。
參考鏈接https://blog.csdn.net/qq_30992103/article/details/99730059
'''本期內(nèi)容主要學(xué)習(xí)了使用Python中的一些庫(kù),尤其是Pandas和numpy來進(jìn)行數(shù)據(jù)分析,清洗數(shù)據(jù),特征值選取,數(shù)據(jù)可視化,數(shù)據(jù)建模和評(píng)估等操作,能從中學(xué)習(xí)到處理數(shù)據(jù)的工作流程過程,在后期還需要加強(qiáng)對(duì)代碼的練習(xí)和舉一反三過程,很多代碼很通用,可以用來處理很多數(shù)據(jù)集,值得多次練習(xí)和學(xué)習(xí)。
謝謝大家觀看,如有幫助,來個(gè)喜歡或者關(guān)注吧!
博客網(wǎng)址:https://7988888.xyz/
知乎網(wǎng)址:https://www.zhihu.com/people/braintechnology
知識(shí)星球 : https://t.zsxq.com/aeimaqv
本文內(nèi)容參考以上網(wǎng)址。以上內(nèi)容僅供學(xué)習(xí)使用,不作其它用途,如有侵權(quán),請(qǐng)留言聯(lián)系,作刪除處理!
有任何疑問及建議,掃描以下公眾號(hào)二維碼添加交流:
