Pyhon机器学习实践指南-第一章

# # -*- coding:utf-8 -*-

import os
import pandas as pd
import requests

"""
先下载iris.data数据集,并写入path目录。实际上下载的是.csv文件,但是通过pandas操作,给
文件添加了一列标题。读出来的结果类似Excel,pandas其实就是操作的行和列,数据列Series,表格DataFrame.
"""
PATH = "D:/Python-lianxi"
r = requests.get('https://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data')
with open(PATH + 'iris.data','w') as f :
    f.write(r.text)
os.chdir(PATH)
df = pd.read_csv(PATH + 'iris.data',names=['sepal length','sepal width','petal length','petal width','class'])
# print(df.head())  #打印出iris数据

"""
下面看下pandas的操作
"""
# print(df['sepal length'])  #通过列名,从数据框中选择某一列。如果想只看其中某几个数据,可以使用切片。
# print(df.ix[:3,:2])  #使用.ix标注和Python列表切片的预防,能够选择该数据框中的一小片。
#下面使用列表迭代器选择width的所有列
# print(df.ix[:3,[x for x in df.columns if 'width' in x]])

"""
以上是基于其在数据框中的位置,选择数据分片。下面使用根据某些特定条件,来选择数据的一个子集。
"""
# print(df['class'].unique())
# print(df[df['class']== 'Iris-virginica'])   #查看分类是Iris-virginica的数据
# print(df.count())  #统计总有多少行数据
# print(df[df['class'] == 'Iris-virginica'].count())   #统计分类为Iris-virginica的数据

"""
以上打印的数据来看,在左侧的索引保留了原始行号。可以将这些数据保存为一个新的数据框并且重置索引。
"""
# virginica = df[df['class'] == 'Iris-virginica'].reset_index(drop= True)
# print(virginica)

"""
也可以通过在某一列上放置条件来选择数据
"""
# print(df[(df['class'] == 'Iris-virginica')&(df['petal width']>2.2)])  #只选择分类为Iris-virginica并花瓣宽度大于2.2的数据

# print(df.describe())  #使用describe方法,收集各相关列的描述性统计信息,类别列不算
# print(df.describe(percentiles=[.20,.40,.80,.90,.95]))   #自定义百分比数据

"""
检查各特征是否有相关性,用.corr方法,一般情况系数为正的,表示相关性强一点,负的相关性弱
"""

# print(df.corr())  #可以查看每个行-列对中的Pearson系数,可以查看秩相关系数
# print(df.corr(method="spearman"))
# print(df.corr(method="kendall"))

"""
以上代码是学习如果选择数据框的某一部分数据,并且从数据中获取汇总统计信息。
但是只看这些数字并不能直观的看出结论,这个是个可视化就登场啦!
"""
import matplotlib.pyplot as plt
plt.style.use('ggplot')
import numpy as np

#下面开始生产第一个图
# fig,ax = plt.subplots(figsize=(6,4))  #创建宽度为6和高度为4 的插图
# ax.hist(df['petal width'],color='black')  #调用.hist并传人数据,绘制直方图,柱子颜色为黑色
# ax.set_ylabel('Count',fontsize=12)  #分别在X轴,Y轴上放置标签,最后一行设置标题。还设置了字体大小
# ax.set_xlabel('Width',fontsize=12)
# plt.title('Iris Petal Width',fontsize=14,y=1.01)
# plt.show()

#也可以为每一列生成一个直方图
# fig, ax = plt.subplots(2,2, figsize=(6,4))
#
# ax[0][0].hist(df['petal width'], color='black');
# ax[0][0].set_ylabel('Count', fontsize=12)
# ax[0][0].set_xlabel('Width', fontsize=12)
# ax[0][0].set_title('Iris Petal Width', fontsize=14, y=1.01)
#
# ax[0][1].hist(df['petal length'], color='black');
# ax[0][1].set_ylabel('Count', fontsize=12)
# ax[0][1].set_xlabel('Lenth', fontsize=12)
# ax[0][1].set_title('Iris Petal Lenth', fontsize=14, y=1.01)
#
# ax[1][0].hist(df['sepal width'], color='black');
# ax[1][0].set_ylabel('Count', fontsize=12)
# ax[1][0].set_xlabel('Width', fontsize=12)
# ax[1][0].set_title('Iris Sepal Width', fontsize=14, y=1.01)
#
# ax[1][1].hist(df['sepal length'], color='black');
# ax[1][1].set_ylabel('Count', fontsize=12)
# ax[1][1].set_xlabel('Length', fontsize=12)
# ax[1][1].set_title('Iris Sepal Length', fontsize=14, y=1.01)
#
# plt.tight_layout()  #该方法可以自动调整子插图,排版更好看一点
# plt.show()

#也可以使用散点图
# fig,ax = plt.subplots(figsize=(6,6))
# ax.scatter(df['petal width'],df['petal length'],color='green')
# ax.set_xlabel('Petal Width')
# ax.set_ylabel('Petal Length')
# ax.set_title('Petal Scatterplot')
# plt.show()

# 也可以添加多个子插图,检查每个方面的数据情况
# fig,ax = plt.subplots(figsize=(6,6))
# ax.plot(df['petal length'],color='blue')
# ax.set_xlabel('Specimen Number')
# ax.set_ylabel('Petal Length')
# ax.set_title('Petal Length plot')
# plt.show()
#以上线图,可以清楚的看出每个类别存在鲜明的长度差别-样本数据集在每个类别拥有50个排序的样例,
#得出花瓣长度很可能是用与区分类别的有用特征

"""
条形图
"""
# fig ,ax = plt.subplots(figsize=(6,6))
# bar_width = 0.6
# labels = [x for x in df.columns if 'length' in x or 'width' in x ]
# ver_y = [df[df['class']=='Iris-versicolor'][x].mean() for x in labels]
# vir_y = [df[df['class'] =='Iris-virginica'][x].mean() for x in labels]
# set_y = [df[df['class']=='Iris-setosa'][x].mean() for x in labels]
# x = np.arange(len(labels))
# ax.bar(x,vir_y,bar_width,bottom=set_y,color='darkgrey')
# ax.bar(x,set_y,bar_width,bottom=ver_y,color='red')
# ax.bar(x,ver_y,bar_width,color='black')
# ax.set_xticks(x + (bar_width/2))
# ax.set_xticklabels(labels,rotation=-70,fontsize=12)
# ax.set_title('Mean Feature Measurement By Class',y=1.01)
# ax.legend(['Virginica','Setosa','Versicolor'])
# plt.show()
"""
为了生成条形图,将x和y 的值传递给bar方法。
"""

"""
接下来进行可视化展示。Seabor库
"""
import matplotlib.pyplot as plt
import seaborn as sns
sns.pairplot(df,hue="class")
# plt.show()   #由于seaborn是建立在matplotlib上的,可以直接使用show函数

# fig ,ax = plt.subplots(2,2,figsize=(7,7))
# sns.set(style='white',palette='muted')
# sns.violinplot(x=df['class'],y=df['sepal length'],ax=ax[0,0])
# sns.violinplot(x=df['class'],y=df['sepal width'],ax=ax[0,1])
# sns.violinplot(x=df['class'],y=df['petal length'],ax=ax[1,0])
# sns.violinplot(x=df['class'],y=df['petal width'],ax=ax[1,1])
# fig.suptitle('Violin Plots',fontsize=16,y=1.03)
# for i in ax.flat:
#     plt.setp(i.get_xticklabels(),rotation=-90)
# fig.tight_layout()
# plt.show()


# 上图展示了特征的分布情况。类别irissetosa的花瓣长度高度聚集在1-2厘米,类别iris-virginica分散
# 在4-7厘米之间。

"""
以上主要是检查数据的展示,下面就要开始操作和处理数据了。
"""
#首先看下map,map方法适用序列数据
#下面展示将鸢尾花分类类型替换,原来的分类名称太长了,不方便
# df['class'] = df['class'].map({'Iris-setosa':'SET','Iris-virginica':'VIR','Iris-versicolor':'VER'})
# print(df)  #可以看到类型都替换成新的名称
"""
上面的操作,将现有的class列的每个值都运行了map方法,由于每个值都能在Python的字典 中找到,
呗添加到被返回的序列。
"""

#下面展示apply的方法,apply也是可以操作数据框的方法。根据花瓣宽度创建新的列,之前看到花瓣宽度平均值是1.3
#现在创建新列宽花瓣,包含一个基于petal width列的二进制值,如果花瓣宽度等于或宽于中值,编码为1,小鱼中值,
#编码为0.下面用apply来实现。
# df['wide petal'] = df['petal width'].apply(lambda v:1 if v>=1.3 else 0)
# print(df)

#基于petal area创建一个新的特征
# df['petal area'] = df.apply(lambda  r:r['petal length']*r['petal width'],axis=1)
#在整个数据框中调用apply,axis=1表示调用函数,axis=0表示该函数对列进行操作。以上操作,每列都被顺序的处理,
#petal length 和petalwidth相乘,得到petal area
# print(df)

#applymap
# df.applymap(lambda v:np.log(v) if isinstance(v,float) else v)

# print(df)

#groupby
# df.groupby('class').mean()
# df.groupby('class').describe()
# df.groupby('petal width')['class'].unique().to_frame()
df.groupby('class')['petal width'].agg({'detal':lambda x :x.max()-x.min(),'max':np.max,'min':np.min})

# print(df)

"""
建模和评估
"""
#先看下花萼宽度和长度的关系
fig,ax = plt.subplots(figsize=(7,7))
ax.scatter(df['sepal width'][:50],df['sepal length'][:50])
ax.set_ylabel('Sepal Length')
ax.set_xlabel('Sepal Width')
ax.set_title('Setosa Sepal Width vs.Sepal Length',fontsize=14,y=1.02)
# plt.show()

"""
由上图看出,似乎有一个正向的线性关系,随着花萼的宽度增加,花萼的长度也会增加。
接下来实验一下线性回归模型,预估这种关系的强度。
"""
import statsmodels.api as sm
y = df['sepal length'][:50]
x = df['sepal width'][:50]
X = sm.add_constant(x)
results = sm.OLS(y,X).fit()
# print(results.summary())
"""
执行结果是 简单的回归模型结果。线性回归模型格式为Y=B0+B1X,其中B0为截距,B1是回归系数,
sepal length=2.6447+0.6909*sepal width.根据结果可以看到R2值尾58,还可以接受。P值就不太正常了。
"""

#下面用结果对象来绘制回归线
fig,ax = plt.subplots(figsize=(7,7))
ax.plot(x,results.fittedvalues,label ='regression line')
ax.scatter(x,y,label='data point',color='r')
ax.set_ylabel('Sepal Length')
ax.set_xlabel('Sepal Width')
ax.set_title('Setosa Sepal Width vs.Sepal Length',fontsize=14,y=1.02)
ax.legend(loc=2)
# plt.show()

"""
scikit-learn库包含分类、回归、聚类、降维、模型选择和预处理,是非常全的库。
下面使用iris数据建立一个分类器,然后学习如何使用scikit-learn评估得到的模型。
"""
"""
用scikit-learn打造机器学习模型的第一步,是要理解数据应如何构造。
独立变量该是数字型的n*m纬的矩阵x、一个因变量y和n*1维的向量。该y向量应该可以是连续的数字,也可以是离散的数字,
还可以是离散的字符串类型。然后将这些向量传递到指定分类器的.fit()方法。
"""
"""
以下的代码,先建立、训练一个分类器,在iris数据集上具有95%的准确度。
逐一分析下上面的代码。代码前两行,做了几个导入操作,读入sklearn包。
导入随机森林分类器,导入将数据分成训练组合测试组模块。
模块train_test_split还会打乱数据的先后顺序。原有数据顺序可能含有误导实际预测的信息。
clf = RandomForestClassifier(max_depth=5,n_estimators=10)这句实现分类器,选择一个使用10个决策树
的森林,而每棵树最多允许五层的判断深度。这么设置避免过拟合。
接下来创建X矩阵和y向量。初始的iris数据框包含四个特征:花瓣宽度和长度,花萼的长度和宽度。
这些特征被选中并成为独立特征矩阵X。最后一列iris类别的名称,就成为因变量y。
"""
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import train_test_split
# clf = RandomForestClassifier(max_depth=5,n_estimators=10)
# X = df.ix[:,:4]
# y = df.ix[:,4]
"""
X_train,X_test, y_train, y_test =cross_validation.train_test_split(train_data,train_target,
test_size=0.4, random_state=0)
train_data:所要划分的样本特征集
train_target:所要划分的样本结果
test_size:样本占比,如果是整数的话就是样本的数量
random_state:是随机数的种子。
随机数种子:其实就是该组随机数的编号,在需要重复试验的时候,保证得到一组一样的随机数。
比如你每次都填1,其他参数一样的情况下你得到的随机数组是一样的。但填0或不填,每次都会不一样。
"""
# X_train,X_test,y_train,y_test = train_test_split(X,y,test_size=0.3)
# clf.fit(X_train,y_train)
# y_pred = clf.predict(X_test)
# rf = pd.DataFrame(list(zip(y_pred,y_test)),columns=['predicted','actual'])
# rf['correct'] = rf.apply(lambda r: 1 if r['predicted']==r['actual'] else 0 ,axis=1)
# print(rf)
# print(rf['correct'].sum()/rf['correct'].count())   #0.955555555556

"""
接下来使用训练数据拟合模型。一点模型训练完毕,再通过测试数据集来调用分类器的预测方法。
测试数据是分类器没有处理过的数据。预测的返回结果是预估标签的列表。
然后创建对应实际标签与预估标签的数据框。
最终,加和正确的预测次数,并除以样例的总数,从而看出预测的准确率。
"""
#下面看看哪些特征提供最佳的辨别力。
# f_importances = clf.feature_importances_
# f_names = df.columns[:4]
# f_std = np.std([tree.feature_importances_ for tree in clf.estimators_],axis=0)
# zz = zip(f_importances,f_names,f_std)
# zzs = sorted(zz,key=lambda s:x[0],reverse = True)
# imps = [x[0] for x in zzs]
# labels = [x[1] for x in zzs]
# errs = [x[2] for x in zzs ]
# plt.bar(range(len(f_importances)),imps,color='r',yerr=errs,align="center")
# plt.xticks(range(len(f_importances)),labels)
# plt.show()
"""
由上图可以看出,花瓣的长度和宽度比较有区分力。
这些数字从哪里呢?随机森林有一个名为f_importances_的方法,返回特征在决策树中划分叶子结点的相对能力,
如果一个特征能够将分组一致性地、干净拆分成不同的类别,它就具有较高的特征重要性。
这个数字的总和将始终为1.
"""
#下面看看SVM分类器的结果
from sklearn.multiclass import OneVsRestClassifier
from sklearn.svm import SVC
from sklearn.model_selection import train_test_split

clf=OneVsRestClassifier(SVC(kernel='linear'))
X = df.ix[:,:4]
y = np.array(df.ix[:,4]).astype(str) #SVM不能像随机森林分类器一样,交标签解释为N木偶用的字符串
X_train,X_test,y_train,y_test = train_test_split(X,y,test_size=0.3)
clf.fit(X_train,y_train)
y_pred=clf.predict(X_test)
rf= pd.DataFrame(list(zip(y_pred,y_test)),columns=['predicted','actual'])
rf['correct']=rf.apply(lambda r:1 if r['predicted']==r['actual'] else 0,axis=1)
print(rf)
print(rf['correct'].sum()/rf['correct'].count())

以上就是Python机器学习实践指南第一章的内容,介绍了数据科学/机器学习的工作流程。

猜你喜欢

转载自blog.csdn.net/wuxiaosi808/article/details/86582737