Python数据分析
1 Python 中的数据分析
- 数据分析:把隐藏在一些看似杂乱无章的数据背后的信息提炼出来,总结出所研究对象的内在规律
- 数据分析三剑客:
Numpy,Pandas,Matplotlib
2 NumPy
NumPy(Numerical Python) 是 Python 语言的一个扩展程序库,支持大量的维度数组与矩阵运算,此外也针对数组运算提供大量的数学函数库。
2.1 ndarray创建多维数组
ndarray为多维数组。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22# 创建一维数据
np.array([1,2,3])
# 创建二维数组
np.array([[1,2,3],['a','b','c']])
输出:
array([['1', '2', '3'],
['a', 'b', 'c']], dtype='<U11')
# 使用matplotlib.pyplot获取一个numpy数组,数据来源于一张图片。
# 操作该numpy数据会同步到图片中
import matplotlib.pyplot as plt
img_arr = plt.imread('./cat.jpg')
plt.imshow(img_arr)
plt.imshow(img_arr - 100)
# 打印对象属性
type(img_arr)
输出:
numpy.ndarray
123456789101112131415161718192021numpy
默认ndarray
的所有元素的类型是相同的- 如果传进来的列表中包含不同的类型,则会统一为优先级高的类型,优先级:
str > float > int
使用np的routines函数创建
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18# 等差数列
np.linspace(1,100,num=10)
输出:
array([ 1., 12., 23., 34., 45., 56., 67., 78., 89., 100.])
np.arange(0,10,2)
输出:
array([0, 2, 4, 6, 8])
# 随机因子:表示的是一个无时无刻都在变化的数值,一般指时间。若随机因子不变,输出的结果不变
np.random.seed(10)
np.random.randint(0,100,size=(4,5))
生成0到1的随机数,左闭右开
np.random.seed(3)
np.random.random(size=(3,4))
2.2 ndarray的属性
1 | np.random.seed(10) |
2.3 ndarray 的基本操作
2.3.1 索引
一维与列表完全一致,多维同理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26arr = np.random.randint(1,100,size=(3,4))
arr
# 输出:
array([[10, 16, 65, 29],
[90, 94, 30, 9],
[74, 1, 41, 37]])
# 打印第二行数据
arr[1]
输出:
array([90, 94, 30, 9])
# 修改数据
arr[1] = 10
arr[1]
输出:
array([10, 10, 10, 10])
arr[1] = [90, 94, 30, 9]
arr
输出:
array([[10, 16, 65, 29],
[90, 94, 30, 9],
[74, 1, 41, 37]])
12345678910111213141516171819202122232425
2.3.2 切片
1 | arr |
2.3.3 变形
- 使用
arr.reshape()
函数,注意参数是一个tuple
1 | arr |
2.3.4 级联
1 | arr |
- 级联需要注意的点:
- 级联的参数是列表:一定要加中括号或小括号
- 维度必须相同
- 形状相符:在维度保持一致的前提下,如果进行横向(axis=1)级联,必须保证进行级联的数组行数保持一致。如果进行纵向(axis=0)级联,必须保证进行级联的数组列数保持一致。
2.4 ndarray的聚合操作
1 | arr |
2.5 ndarray的排序
np.sort()
与ndarray.sort()
都可以,但有区别:
np.sort()
不改变输入ndarray.sort()
本地处理,不占用空间,但改变输入
1 | arr |
3 Pandas
3.1 Series
Pandas Series 类似表格中的一个列(column),类似于一维数组,可以保存任何数据类型。
1 | pandas.Series( data, index, dtype, name, copy) |
- data:一组数据(ndarray 类型)。
- index:数据索引标签,如果不指定,默认从 0 开始。
- dtype:数据类型,默认会自己判断。
- name:设置名称。
- copy:拷贝数据,默认为 False。
3.1.1 Series创建
1 | # 使用列表创建Series |
3.1.2 Series的索引和切片
使用中括号取单个索引(此时返回的是元素类型),或者中括号里一个列表取多个索引(此时返回的是一个Series类型)。
显式索引:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33- 使用index中的元素作为索引值
- 使用s.loc[](推荐):注意,loc中括号中放置的一定是显示索引
s = Series([1,2,3],index=['a','b','c'])
s[1]
输出:
2
s[[1,2]]
输出:
b 2
c 3
dtype: int64
s['a']
输出:
1
s.a
输出:
1
s.loc['a']
输出:
1
s.loc[['a','b']]
输出:
a 1
b 2
dtype: int64
1234567891011121314151617181920212223242526272829303132隐式索引:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18- 使用整数作为索引值,
- 使用.iloc[](推荐):iloc中的中括号中必须放置隐式索引
s = Series([1,2,3],index=['a','b','c'])
# 隐式索引为右开区间,最后一个索引不引用
s[1:2]
输出:
b 2
dtype: int64
# 显式索引为右开区间,最后一个索引引用
s['a':'b']
输出:
a 1
b 2
dtype: int64
1234567891011121314151617
3.1.3 Series的基本概念
1 | s = Series([1,2,3,3,2,4]) |
3.1.4 Series之间的运算与筛选出空值
1 | # 在运算中自动对齐不同索引的数据,当索引没有对应的值时,可能出现缺失数据显示NaN(not a number)的情况 |
3.2 DataFrame
DataFrame 是一个表格型的数据结构,它含有一组有序的列,每列可以是不同的值类型(数值、字符串、布尔型值)。DataFrame 既有行索引也有列索引,它可以被看做由 Series 组成的字典(共同用一个索引)。
DataFrame 构造方法如下:
1 | pandas.DataFrame( data, index, columns, dtype, copy) |
- data:一组数据(ndarray、series, map, lists, dict 等类型)。
- index:索引值,或者可以称为行标签。
- columns:列标签,默认为 RangeIndex (0, 1, 2, …, n) 。
- dtype:数据类型。
- copy:拷贝数据,默认为 False。
3.2.1 DataFrame 创建
1 | # 使用列表创建 |
3.2.2 DataFrame 索引
对列进行索引
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27- 通过类似字典的方式 df['q']
df = DataFrame({'张三':[130,140,150],'李四':[100,110,90]},index=['语文','数学','英语'])
df
输出:
张三 李四
语文 130 100
数学 140 110
英语 150 90
# 默认列索引
df['李四']
输出:
语文 100
数学 110
英语 90
Name: 李四, dtype: int64
# 获取前两列
df[['李四','张三']]
输出:
李四 张三
语文 100 130
数学 110 140
英语 90 150
1234567891011121314151617181920212223242526对行进行索引
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19- 使用.loc[]加index来进行行索引
- 使用.iloc[]加整数来进行行索引
- 同样返回一个Series,index为原来的columns
# 使用显示索引
df.loc['语文']
输出:
张三 130
李四 100
Name: 语文, dtype: int64
# 使用隐式索引
df.iloc[0]
输出:
张三 130
李四 100
Name: 语文, dtype: int64
123456789101112131415161718对元素索引的方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21- 使用列索引
- 使用行索引(iloc[3,1] or loc['C','q'])
- 行索引在前,列索引在后
df['李四']['数学']
输出:
110
# 注;下面两个反之,报错
df.loc['语文']['李四']
or df.loc['语文','李四']
输出:
100
df.loc[['语文','英语'],'李四']
输出:
语文 100
英语 90
Name: 李四, dtype: int64
1234567891011121314151617181920
3.2.3 DataFrame 切片
注意,直接用中括号时:
- 索引表示的是列索引
- 切片表示的是行切片
1 | # 索引 |
3.2.4 DataFrame 运算
同Series一样:
- 在运算中自动对齐不同索引的数据
- 如果索引不对应,则补NaN
1 | df = DataFrame({'张三':[130,140,150],'李四':[100,110,90]},index=['语文','数学','英语']) |
3.2.5 DataFrame 拼接
pd.concat()
1
2
3pd.concat(objs,axis=0,join='outer',join_axes=None,ignore_index=False)
12- objs : 这是Series的序列或映射,DataFrame或Panel对象。
- axis : {0,1,…},默认为0。0为行拼接,1为列拼接
- join : {‘inner’,‘outer’},默认为’outer’。如何处理其他轴上的索引。外部为联合,内部为交叉。
- ignore_index : 布尔值,默认为False。如果为True,则不要在串联轴上使用索引值。结果轴将标记为0,…,n-1。
- join_axes : 这是索引对象的列表。用于其他(n-1)轴的特定索引,而不是执行内部/外部设置逻辑。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43df1 = DataFrame(data=np.random.randint(0,100,size=(3,4)))
df2 = DataFrame(data=np.random.randint(0,100,size=(3,3)))
df1
输出:
0 1 2 3
a 8 63 94 29.0
b 97 81 37 84.0
c 84 78 76 11.0
df2
输出:
0 1 2
a 83 17 61
d 94 95 3
c 34 46 84
# 外连接:补NaN(默认模式)
pd.concat((df1,df2))
输出:
0 1 2 3
a 8 63 94 29.0
b 97 81 37 84.0
c 84 78 76 11.0
a 83 17 61 NaN
d 94 95 3 NaN
c 34 46 84 NaN
# 内连接:只连接匹配的项
df1 = DataFrame(data=np.random.randint(0,100,size=(3,4)),index=['a','b','c'])
df2 = DataFrame(data=np.random.randint(0,100,size=(3,3)),index=['a','d','c'])
pd.concat((df1,df2),axis=0,join='inner')
输出:
0 1 2
a 8 63 94
b 97 81 37
c 84 78 76
a 83 17 61
d 94 95 3
c 34 46 84
123456789101112131415161718192021222324252627282930313233343536373839404142pd.merge()
1
2
3
4
5
6pd.merge(left, right, how='inner', on=None, left_on=None, right_on=None,left_index=False, right_index=False, sort=True)
# merge与concat的区别在于,merge需要依据某一共同的列来进行合并
# 使用pd.merge()合并时,会自动根据两者相同名称的那一列,作为key来进行合并。
# 注意: 每一列元素的顺序不要求一致
12345left : 一个DataFrame对象。
right : 另一个DataFrame对象。
on : 列(名)加入上。必须在左右DataFrame对象中都找到。
left_on : 左侧DataFrame中的列用作键。可以是列名,也可以是长度等于DataFrame长度的数组。
right_on : 右侧DataFrame中的列用作键。可以是列名,也可以是长度等于DataFrame长度的数组。
left_index : 如果为True,则使用左侧DataFrame的索引(行标签)作为其连接键。如果DataFrame具有MultiIndex(分层),则级别数必须与右侧DataFrame中的连接键数匹配。
right_index : 相同的使用作为left_index为正确的数据帧。
how : “left”,“right”,“inner”,“内”之一。默认为inner。
合并方法 SQL等效 描述 left LEFT OUTER JOIN 使用左侧对象的key right RIGHT OUTER JOIN 使用正确对象的key outer FULL OUTER JOIN 使用联合key inner INNER JOIN 使用key的交集 sort : 排序的结果数据框中加入字典顺序按键。默认情况下为True,在许多情况下,设置为False将大大提高性能。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160# 一对一匹配合并
df1 = DataFrame({'employee':['Bob','Jake','Lisa'],
'group':['Accounting','Engineering','Engineering'],
})
df2 = DataFrame({'employee':['Lisa','Bob','Jake'],
'hire_date':[2004,2008,2012],
})
df1
输出:
employee group
0 Bob Accounting
1 Jake Engineering
2 Lisa Engineering
df2
输出:
employee hire_date
0 Lisa 2004
1 Bob 2008
2 Jake 2012
pd.merge(df1,df2)
输出:
employee group hire_date
0 Bob Accounting 2008
1 Jake Engineering 2012
2 Lisa Engineering 2004
# 多对一不合并:指左表单行匹配右表多行数据
df3 = DataFrame({
'employee':['Lisa','Jake'],
'group':['Accounting','Engineering'],
'hire_date':[2004,2016]})
df4 = DataFrame({'group':['Accounting','Engineering','Engineering'],
'supervisor':['Carly','Guido','Steve']
})
df3
输出:
employee group hire_date
0 Lisa Accounting 2004
1 Jake Engineering 2016
df4
输出:
group supervisor
0 Accounting Carly
1 Engineering Guido
2 Engineering Steve
pd.merge(df3,df4)
输出:
employee group hire_date supervisor
0 Lisa Accounting 2004 Carly
1 Jake Engineering 2016 Guido
2 Jake Engineering 2016 Steve
# 多对多匹配:指左表多行匹配右表多行数据
df1
输出:
employee group
0 Bob Accounting
1 Jake Engineering
2 Lisa Engineering
df4
输出:
group supervisor
0 Accounting Carly
1 Engineering Guido
2 Engineering Steve
pd.merge(df1,df4)
employee group supervisor
0 Bob Accounting Carly
1 Jake Engineering Guido
2 Jake Engineering Steve
3 Lisa Engineering Guido
4 Lisa Engineering Steve
# key的规范化
df1 = DataFrame({'employee':['Jack',"Summer","Steve"],
'group':['Accounting','Finance','Marketing']})
df2 = DataFrame({'employee':['Jack','Bob',"Jake"],
'hire_date':[2003,2009,2012],
'group':['Accounting','sell','ceo']})
df1
输出:
employee group
0 Jack Accounting
1 Summer Finance
2 Steve Marketing
df2
输出:
employee hire_date group
0 Jack 2003 Accounting
1 Bob 2009 sell
2 Jake 2012 ceo
# 使用key的交集
pd.merge(df1,df2,how='inner')
pd.merge(df1,df2)
输出:
employee group hire_date
0 Jack Accounting 2003
# 联合key
pd.merge(df1,df2,how='outer')
输出:
employee group hire_date
0 Jack Accounting 2003.0
1 Summer Finance NaN
2 Steve Marketing NaN
3 Bob sell 2009.0
4 Jake ceo 2012.0
# 当有多个列名称相同时,需要使用on=来指定哪一个列作为key,配合suffixes指定冲突列名
pd.merge(df1,df2,on='group',how='outer')
输出:
employee_x group employee_y hire_date
0 Jack Accounting Jack 2003.0
1 Summer Finance NaN NaN
2 Steve Marketing NaN NaN
3 NaN sell Bob 2009.0
4 NaN ceo Jake 2012.0
# 当两张表没有可进行连接的列时,可使用left_on和right_on手动指定merge中左右两边的哪一列列作为连接的列
df1 = DataFrame({'employee':['Bobs','Linda','Bill'],
'group':['Accounting','Product','Marketing'],
'hire_date':[1998,2017,2018]})
df2 = DataFrame({'name':['Lisa','Bobs','Bill'],
'hire_dates':[1998,2016,2007]})
df1
输出:
employee group hire_date
0 Bobs Accounting 1998
1 Linda Product 2017
2 Bill Marketing 2018
df2
输出:
name hire_dates
0 Lisa 1998
1 Bobs 2016
2 Bill 2007
pd.merge(df1,df2,left_on='employee',right_on='name',how='outer')
输出:
employee group hire_date name hire_dates
0 Bobs Accounting 1998.0 Bobs 2016.0
1 Linda Product 2017.0 NaN NaN
2 Bill Marketing 2018.0 Bill 2007.0
3 NaN NaN NaN Lisa 1998.0
pd.merge(df1,df2,left_index=True,right_index=True,how='outer')
输出:
employee group hire_date name hire_dates
0 Bobs Accounting 1998 Lisa 1998
1 Linda Product 2017 Bobs 2016
2 Bill Marketing 2018 Bill 2007
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
3.3 使用tushare包获取某股票的历史行情数据。
1 | import tushare as ts |
3.3.1 输出该股票所有收盘比开盘上涨3%以上的日期
1 | df = pd.read_csv('./maotai.csv') |
3.3.2 输出该股票所有开盘比前日收盘跌幅超过2%的日期
1 | (df['open'] - df['close'].shift(1))/df['close'].shift(1) < -0.02 |
3.3.3 实例
- 假如我从2008年1月1日开始,每月第一个交易日买入1手股票,每年最后一个交易日卖出所有股票,到今天为止,我的收益如何?
- 分析:
- 规则:基于开盘价股票的买卖
- 买:一个完整的年需要买12次股票,一次买入100只,一个完整的年需要买入1200只(单价:当天开盘价)
- 卖:一个完整的年需要卖一次股票,一次卖出1200只
- 备注:19年不是一个完整的年,该年只可以买入900只,并且卖不出去
1 | # 数据的重新取样的机制(resample):根据指定好的规则进行指定数据的提取 |
4 数据处理
4.1 处理丢失数据
有两种丢失数据:
None
None
是Python自带的,其类型为python object
。因此,None
不能参与到任何计算中。1
2
3
4
5
6#查看None的数据类型
type(None)
输出:
NoneType
12345NaN
np.nan
是浮点类型,能参与到计算中。但计算的结果总是NaN
。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27type(np.nan)
输出:
float
# 将某些元素设置为NaN
from pandas import DataFrame
import numpy as np
df = DataFrame(data=np.random.randint(0,100,size=(3,4)))
print(df)
df.iloc[0,0]=None
df.iloc[1,1]=np.nan
df.iloc[2,2]=None
df
输出:
0 1 2 3
0 83 7 94 91
1 21 42 84 27
2 55 60 48 92
0 1 2 3
0 NaN 93.0 31.0 47
1 50.0 NaN 38.0 7
2 40.0 89.0 NaN 94
1234567891011121314151617181920212223242526
4.1.1 删除包含空字段的行
1 | DataFrame.dropna(axis=0, how='any', thresh=None, subset=None, inplace=False) |
- axis:默认为 0,表示逢空值剔除整行,如果设置参数 axis=1 表示逢空值去掉整列。
- how:默认为 ‘any’ 如果一行(或一列)里任何一个数据有出现 NA 就去掉整行,如果设置 how=‘all’ 一行(或列)都是 NA 才去掉这整行。
- thresh:设置需要多少非空值的数据才可以保留下来的。
- subset:设置想要检查的列。如果是多个列,可以使用列名的 list 作为参数。
- inplace:如果设置 True,将计算得到的值直接覆盖之前的值并返回 None,修改的是源数据。
4.1.2 检测哪些列中存在空值
1 | # Pandas 把 n/a 和 NA 当作空数据,na 不是空数据,不符合我们要求,我们可以指定空数据类型: |
4.1.3 fillna()
方法来替换空字段
1 | # 使用12345数据替换空字段 |
4.2 清洗重复数据
1 | # 如果对应的数据是重复的,duplicated() 会返回 True,否则返回 False。 |
keep : {'first', 'last', False}
- first : 保留第一个数据,默认
- last : 保留最后一个数据
- False : 丢弃所有数据
4.3 处理数据异常值
- 使用df.std()函数可以求得DataFrame对象每一列的标准差
- 创建一个1000行3列的df 范围(0-1),求其每一列的标准差
- 对df应用筛选条件,去除标准差太大的数据:假设过滤条件为 C列数据大于两倍的C列标准差
1 | df = pd.DataFrame(np.random.random(size=(100,3)),columns=['A','B','C']) |
4.4 数据映射
4.4.1 替换元素:df.replace()
1 | df.replace(to_replace=None, value=None, inplace=False, limit=None, regex=False, method='pad',) |
- to_replace:被替换的值
- value:替换后的值
- inplace:是否要改变原数据,False是不改变,True是改变,默认是False
- limit:控制填充次数
- regex:是否使用正则,False是不使用,True是使用,默认是False
- method:填充方式,pad,ffill,bfill分别是向前、向前、向后填充
- 注意:DataFrame中,无法使用method和limit参数
1 | df = pd.DataFrame(data=np.random.randint(1,100,size=(8,5))) |
4.4.2 元素映射map()
- map():会根据提供的函数对指定序列做映射
- map():可以映射新一列数据
- map():中可以使用lambd表达式
- map():中可以使用方法,可以是自定义的方法
- map():并不是df的方法,而是series的方法
- map():中不能使用sum之类的函数,for循环
- 并不是任何形式的函数都可以作为map的参数。只有当一个函数具有一个参数且有返回值,那么该函数才可以作为map的参数。
1 | # 创建数据表 |
4.4.3 元素映射apply()
- apply和map都可以作为一种基于Series的运算工具,并且apply比map更快
- 输出的是一个映射关系表
1 | df['Score'].apply(true_score) |
4.5 数据采样take()
take()函数接受一个索引列表,用数字表示,使得df根据列表中索引的顺序进行采样
- 可以借助np.random.permutation()函数随机抽样
1 | # 行采样 |
4.6 数据分类处理
4.6.1 数据分组
1 | df = DataFrame({'item':['Apple','Banana','Orange','Banana','Orange','Apple'], |
4.6.2 操作分组后的数据
分组后的成员中可以被进行运算的值会进行运算,不能被运算的值不进行运算
1 | # 默认如果不指定列的话,会计算所有列的平均值,此处指定计算price列 |
4.6.3 高级数据聚合
- 使用groupby分组后,也使用transform和apply提供自定义函数实现更多的运算
- apply:输出为数据值
- transform:输出为数据映射值
- transform和apply都会进行运算,在transform或者apply中传入函数即可
- transform和apply也可以传入一个lambda表达式
1 | df.groupby('item')['price'].sum() |
4.6.4 query()
- 通过query(“查询条件来查找”)
1 | months = {'JAN' : 1, 'FEB' : 2, 'MAR' : 3, 'APR' : 4, 'MAY' : 5, 'JUN' : 6, |
4.7 算法处理分析数据
4.7.1 几个概念
- 人工智能和机器学习之间的关系:
- 机器学习是用来实现人工智能的一种技术手段
- 算法模型
- 概念:特殊的对象。特殊之处就在于该对象内部已经集成或者封装好一个某种方程(还没有求出解的方程)
- 作用:算法模型对象最终求出的解就是该算法模型实现预测或者分类的结果
- 预测
- 分类
- 样本数据:numpy,DataFrame
- 样本数据和算法模型之间的关联:样本数据是需要带入到算法模型对象中对其内部封装的方程进行求解的操作。该过程被称为模型的训练。
- 组成部分:
- 特征数据:自变量(x)
- 目标数据:因变量(y)
- 模型的分类:
- 有监督学习:如果模型需要的样本数据中必须包含特征和目标数据,则该模型归为有监督学习的分类
- 无监督学习:如果模型需要的样本数据只需要有特征数据即可。
- sklearn模块:大概封装了10多种算法模型对象。
- 线性回归算法模型:预测
- KNN算法模型:分类
4.7.2 线性回归
1 | import numpy as np |
score的实现原理:
print('模型预测的温度:',linner.predict(feature)) print('真实温度:',target) 123
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
+ [scikit-learn 线性回归模型的score函数,返回值是决定系数R^2\_春卷同学的博客-CSDN博客](https://blog.csdn.net/Rex_WUST/article/details/82621952)
##### 4.7.3 K-近邻算法(KNN)
1. KNN算法原理:
1. 计算已知类别数据集中的点与当前点之间的距离;
2. 按照距离递增次序排序;
3. 选取与当前点距离最小的k个点;
4. 确定前k个点所在类别的出现频率;
5. 返回前k个点所出现频率最高的类别作为当前点的预测分类。
2. 工作原理:
1. 存在一个样本数据集合,也称作训练样本集,并且样本集中每个数据都存在标签,即我们知道样本集中每一数据与所属分类的对应关系。输人没有标签的新数据后,将新数据的每个特征与样本集中数据对应的特征进行比较,然后算法提取样本集中特征最相似数据(最近邻)的分类标签。
2. 一般来说,我们只选择样本数据集中前K个最相似的数据,这就是K-近邻算法中K的出处
3. 通常\_K是不大于20的整数。最后 ,选择K个最相似数据中出现次数最多的分类,作为新数据的分类\_
3. 实例:KNN手写数字识别
```auto
#特征数据的职位是字符串类型的数据,特征数据在knn中是需要参与运算,必须将字符串类型的特征数据转换为数值型的数据
import numpy as np
import matplotlib .pyplot as plt
from sklearn.neighbors import KNeighborsClassifier
# 样本数据的提取
feature = []
target = []
for i in range(7):#i:0-9表示的是文件夹的名称
for j in range(1,501):#j:1-500表示的是图片的名称的一部分
imgPath = './data/'+str(i)+'/'+str(i)+'_'+str(j)+'.bmp'
img_arr = plt.imread(imgPath)
feature.append(img_arr)
target.append(i)
target = np.array(target)
# feature目前是三维的numpy数组。必须变形成二维的才可以作为特征数据
feature = np.array(feature)
feature.shape
# 变形成二维
feature = feature.reshape(5000,784)
# 进行样本数据的打乱
np.random.seed(10)
np.random.shuffle(feature)
np.random.seed(10)
np.random.shuffle(target)
# 对样本数据进行拆分
# 测试数据
# 训练数据
#训练数据是以train结尾的
x_train = feature[:4950]
y_train = target[:4950]
#测试数据是以test结尾的
x_test = feature[4950:]
y_test = target[4950:]
knn = KNeighborsClassifier(n_neighbors=9)
knn.fit(x_train,y_train)
knn.score(x_test,y_test)
#对模型进行测试
print('真实的结果:',y_test)
print('模型分类的结果:',knn.predict(x_test))
# 保存训练好的模型
from sklearn.externals import joblib
#保存
joblib.dump(knn,'./knn.m')
#读取
knn = joblib.load('./knn.m')
knn
# 将外部图片带入模型进行分类的测试
img_arr = plt.imread('./数字.jpg')
plt.imshow(img_arr)
# 切对应的数据
eight_arr = img_arr[175:240,85:135]
plt.imshow(eight_arr)
# 模型只可以测试类似于测试数据中的特征数据
x_test[4].shape
# 将8对应的图片进行降维(65, 50, 3)降低成(784,)
# 将图片降低为2维
eight_arr = eight_arr.mean(axis=2)
#进行图片像素的等比例压缩
import scipy.ndimage as ndimage
eight_arr = ndimage.zoom(eight_arr,zoom=(28/65,28/50))
eight_arr = eight_arr.reshape(1,784)
# 分类数据
knn.predict(eight_arr)
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
本文转自 https://www.cnblogs.com/f-carey/p/17216794.html,如有侵权,请联系删除。