Python 数据分析

Python 数据分析

1 Python 中的数据分析

  • 数据分析:把隐藏在一些看似杂乱无章的数据背后的信息提炼出来,总结出所研究对象的内在规律
  • 数据分析三剑客Numpy,Pandas,Matplotlib

2 NumPy

NumPy(Numerical Python) 是 Python 语言的一个扩展程序库,支持大量的维度数组与矩阵运算,此外也针对数组运算提供大量的数学函数库。

2.1 ndarray创建多维数组

  • ndarray为多维数组。

    # 创建一维数据
    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
    
    • numpy默认ndarray的所有元素的类型是相同的
    • 如果传进来的列表中包含不同的类型,则会统一为优先级高的类型,优先级:str > float > int
  • 使用np的routines函数创建

    # 等差数列
    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的属性

np.random.seed(10)
random_arr = np.random.randint(0,100,size=(4,5))
# ndim:维度
random_arr.ndim
输出:
2
# shape:形状(各维度的长度)
random_arr.shape
输出:
(4, 5)

img_arr.shape
输出:
(626, 413, 3)



# size:总长度
random_arr.size
输出:
20

# dtype:元素类型
random_arr.dtype
输出:
dtype('int32')

2.3 ndarray 的基本操作

2.3.1 索引

  • 一维与列表完全一致,多维同理

    arr = 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]])
    

2.3.2 切片

arr
输出:
array([[10, 16, 65, 29],
       [90, 94, 30,  9],
       [74,  1, 41, 37]])

# 获取二维数组前两行
arr[0:2]
输出:
array([[10, 16, 65, 29],
       [90, 94, 30,  9]])

# 获取二维数组前两列
# 逗号左边为第一个维度,右边为第二个维度
arr[:,0:2]
输出:
array([[10, 16],
       [90, 94],
       [74,  1]])

# 获取二维数组前两行和前两列数据
arr[0:2,0:2]
输出:
array([[50, 52],
       [10, 10]])

# 将数据反转,例如[1,2,3]---->[3,2,1],"::"代表整行
# 行反转
arr[::-1]
输出:
array([[74,  1, 41, 37],
       [90, 94, 30,  9],
       [10, 16, 65, 29]])

# 列反转
arr[:,::-1]
输出:
array([[29, 65, 16, 10],
       [ 9, 30, 94, 90],
       [37, 41,  1, 74]])

# 行列反转
arr[::-1,::-1]
输出:
array([[37, 41,  1, 74],
       [ 9, 30, 94, 90],
       [29, 65, 16, 10]])

# 同理可将图片进行反转
# 图片三维分别表示:img_arr(行,列,颜色)
plt.imshow(img_arr[:,::-1,:])

# 对图片进行裁剪
plt.imshow(img_arr[50:450,100:300,:])

2.3.3 变形

  • 使用arr.reshape()函数,注意参数是一个tuple
arr
输出:
array([[10, 16, 65, 29],
       [90, 94, 30,  9],
       [74,  1, 41, 37]])

# 将多维数组变形成一维数组
arr.reshape((1,12))
输出:
array([[10, 16, 65, 29, 90, 94, 30,  9, 74,  1, 41, 37]])

arr.reshape((12,1))
输出:
array([[10],
       [16],
       [65],
       [29],
       [90],
       [94],
       [30],
       [ 9],
       [74],
       [ 1],
       [41],
       [37]])

将一维数组变为二维数组
arr.reshape((-1,3))
输出:
array([[10, 16, 65],
       [29, 90, 94],
       [30,  9, 74],
       [ 1, 41, 37]])

2.3.4 级联

arr
输出:
array([[10, 16, 65, 29],
       [90, 94, 30,  9],
       [74,  1, 41, 37]])

# 一维,二维,多维数组的级联
# axis=0表示列,axis=1表示行
np.concatenate((arr,arr),axis=1)
输出:
array([[10, 16, 65, 29, 10, 16, 65, 29],
       [90, 94, 30,  9, 90, 94, 30,  9],
       [74,  1, 41, 37, 74,  1, 41, 37]])

# 合并照片
img_arr = plt.imread('./cat.jpg')
plt.imshow(img_arr)
arr_3 = np.concatenate([img_arr,img_arr,img_arr],axis=1)
arr_9 = np.concatenate((arr_3,arr_3,arr_3),axis=0)
plt.imshow(arr_9)
  • 级联需要注意的点:
    • 级联的参数是列表:一定要加中括号或小括号
    • 维度必须相同
    • 形状相符:在维度保持一致的前提下,如果进行横向(axis=1)级联,必须保证进行级联的数组行数保持一致。如果进行纵向(axis=0)级联,必须保证进行级联的数组列数保持一致。

2.4 ndarray的聚合操作

arr
输出:
array([[10, 16, 65, 29],
       [90, 94, 30,  9],
       [74,  1, 41, 37]])

# 求arr中所有元素之和
arr.sum(axis=None)
输出:
496
# 求arr中每列之合
arr.sum(axis=0)
输出:
array([174, 111, 136,  75])
# 求arr中每行之合
输出:
array([120, 223, 153])

# 最大最小值
arr.max(axis=None)
输出:
94
# 打印arr中每列的最大值:np.max/ np.min
arr.max(axis=0)
输出:
array([90, 94, 65, 37])
# 打印arr中每行的最大值
arr.max(axis=1)
输出:
array([65, 94, 74])

# 打印arr中的平均值
arr.mean(axis=None)
输出:
41.3
# 打印arr中的每列平均值
arr.mean(axis=0)
输出:
array([58, 37, 45.33333333, 25])
# 打印arr中的每行平均值
arr.mean(axis=1)
输出:
array([30, 55.75, 38.25])

2.5 ndarray的排序

np.sort()ndarray.sort()都可以,但有区别:

  • np.sort()不改变输入
  • ndarray.sort()本地处理,不占用空间,但改变输入
arr
输出:
array([[10, 16, 65, 29],
       [90, 94, 30,  9],
       [74,  1, 41, 37]])

# 对arr每列排序
np.sort(arr,axis=0)
输出:
array([[10,  1, 30,  9],
       [74, 16, 41, 29],
       [90, 94, 65, 37]])
arr
输出:
array([[10, 16, 65, 29],
       [90, 94, 30,  9],
       [74,  1, 41, 37]])

# 对arr每列排序
arr.sort(axis=0)
arr
输出:
array([[10,  1, 30,  9],
       [74, 16, 41, 29],
       [90, 94, 65, 37]])

# 对arr每行排序
arr.sort(axis=0)
arr
输出:
array([[ 1,  9, 10, 30],
       [16, 29, 41, 74],
       [37, 65, 90, 94]])

3 Pandas

3.1 Series

Pandas Series 类似表格中的一个列(column),类似于一维数组,可以保存任何数据类型。

pandas.Series( data, index, dtype, name, copy)
  • data:一组数据(ndarray 类型)。
  • index:数据索引标签,如果不指定,默认从 0 开始。
  • dtype:数据类型,默认会自己判断。
  • name:设置名称。
  • copy:拷贝数据,默认为 False。

3.1.1 Series创建

# 使用列表创建Series
Series(data=[1,2,3])
输出:
0    1
1    2
2    3
dtype: int64
索引:0,1,2
数据:1,2,3
数据类型:int64

# 指定索引值,显示索引
Series(data=[1,2,3],index = ["x", "y", "z"])
输出:
x    1
y    2
z    3
dtype: int64

# 使用 key/value 对象,类似字典来创建 Series:
Series(data={'x':1,'y':2,'z':3})
输出:
x    1
y    2
z    3
dtype: int64

# 若只需字典中的一部分数据,只需要指定需要数据的索引即可
Series(data={'x':1,'y':2,'z':3}, index = ['x','z'])
输出:
x    1
z    3
dtype: int64

# 设置 Series 名称参数
Series(data={'x':1,'y':2,'z':3}, index = ['x','z'],name = 'Series_Name')
输出:
x    1
z    3
Name: Series_Name, dtype: int64

3.1.2 Series的索引和切片

  1. 使用中括号取单个索引(此时返回的是元素类型),或者中括号里一个列表取多个索引(此时返回的是一个Series类型)。

  2. 显式索引:

    - 使用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
    
  3. 隐式索引:

    - 使用整数作为索引值,
    - 使用.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
    

3.1.3 Series的基本概念

s = Series([1,2,3,3,2,4])

# 使用s.head(),tail()分别查看前n个和后n个值
s.head(2)
输出:
0    1
1    2
dtype: int64

# 对Series元素进行去重
s.unique()
输出:
array([1, 2, 3, 4], dtype=int64)


3.1.4 Series之间的运算与筛选出空值

# 在运算中自动对齐不同索引的数据,当索引没有对应的值时,可能出现缺失数据显示NaN(not a number)的情况

# 使得两个Series进行相加
s1 = Series([1,2,3],index=['a','b','c'])
s2 = Series([1,2,3],index=['a','d','c'])
s = s1 + s2
s
输出:
a    2.0
b    NaN
c    6.0
d    NaN
dtype: float64

# 可以使用pd.isnull(),pd.notnull()或s.isnull(),notnull()函数检测缺失数据
s[[0,1]]
输出:
a    2.0
b    NaN
dtype: float64

s[['a','b']]
输出:
a    2.0
b    NaN
dtype: float64

s[[True,False,True,False]]
输出:
a    2.0
c    6.0
dtype: float64

s.isnull()
输出:
a    False
b     True
c    False
d     True
dtype: bool

s.notnull()
输出:
a     True
b    False
c     True
d    False
dtype: bool

# 打印出不为空值的数据
s[s.notnull()]
输出:
a    2.0
c    6.0
dtype: float64

3.2 DataFrame

DataFrame 是一个表格型的数据结构,它含有一组有序的列,每列可以是不同的值类型(数值、字符串、布尔型值)。DataFrame 既有行索引也有列索引,它可以被看做由 Series 组成的字典(共同用一个索引)。

DataFrame 构造方法如下:

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 创建

# 使用列表创建
df = DataFrame(data=[['a',1],['y',2],['z',3]],columns=['k','v'])
df
输出:
	k	v
0	a	1
1	y	2
2	z	3

# 使用ndarray创建DataFrame
np.random.seed(10)
df = DataFrame(data=np.random.randint(0,100,size=(3,4)),index=['a','b','c'],columns=['A','B','C','D'])
df
输出:
	A	B	C	D
a	9	15	64	28
b	89	93	29	8
c	73	0	40	36

# DataFrame以字典的键作为每一【列】的名称,以字典的值(一个数组)作为每一列。
data = {'k':['a', 'b', 'c'], 'v':[1, 2, 3]}
df = pd.DataFrame(data)
df
输出:
	k	v
0	a	1
1	y	2
2	z	3

3.2.2 DataFrame 索引

  1. 对列进行索引

    - 通过类似字典的方式  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
    
  2. 对行进行索引

    - 使用.loc[]加index来进行行索引
    - 使用.iloc[]加整数来进行行索引
    - 同样返回一个Series,index为原来的columns
    
    # 使用显示索引
    df.loc['语文']
    输出:
    张三    130
    李四    100
    Name: 语文, dtype: int64
    
    # 使用隐式索引
    df.iloc[0]
    输出:
    张三    130
    李四    100
    Name: 语文, dtype: int64
    
  3. 对元素索引的方法

    - 使用列索引 
    - 使用行索引(iloc[3,1] or loc['C','q'])
    - 行索引在前,列索引在后
    
    df['李四']['数学']
    输出:
    110
    
    # 注;下面两个反之,报错
    df.loc['语文']['李四']
    or df.loc['语文','李四']
    输出:
    100
    
    df.loc[['语文','英语'],'李四']
    输出:
    语文    100
    英语     90
    Name: 李四, dtype: int64
    

3.2.3 DataFrame 切片

注意,直接用中括号时:

  • 索引表示的是列索引
  • 切片表示的是行切片
# 索引
df[列索引]:取一列
df[[col1,col2]]:取出两列
df.loc[显示的行索引]:取行
df.loc[行,列]:取元素
# 切片
df[index1:index3]:切行
df.loc[col1:col3]:切列

df = DataFrame({'张三':[130,140,150],'李四':[100,110,90]},index=['语文','数学','英语'])
df
输出:
	张三	李四
语文	130	100
数学	140	110
英语	150	90

# 切前两行数据
df[0:2]
输出:
张三	李四
语文	130	100
数学	140	110

# 在loc和iloc中使用切片(切列)
df.iloc[:,0:1]
输出:
	张三
语文	130
数学	140
英语	150

3.2.4 DataFrame 运算

同Series一样:

  • 在运算中自动对齐不同索引的数据
  • 如果索引不对应,则补NaN
df = DataFrame({'张三':[130,140,150],'李四':[100,110,90]},index=['语文','数学','英语'])
df
输出:
	张三	李四
语文	130	100
数学	140	110
英语	150	90

qizhong = df
qimo = df-30
qizhong
输出:
	张三	李四
语文	130	100
数学	140	110
英语	150	90

qimo
输出:
张三	李四
语文	100	70
数学	110	80
英语	120	60

# 求两个DataFrame数据平均值
(qizhong + qimo)/2
输出:
	张三	李四
语文	115.0	85.0
数学	125.0	95.0
英语	135.0	75.0

# 修改张三qizhong数学成绩为120
qizhong['张三']['数学'] = 120
qizhong.loc['数学','张三'] = 120
qizhong
输出:
	张三	李四
语文	130	100
数学	120	110
英语	150	90

qizhong['李四'] -= 50
qizhong
输出:
	张三	李四
语文	130	50
数学	120	60
英语	150	40

3.2.5 DataFrame 拼接

  1. pd.concat()

     pd.concat(objs,axis=0,join='outer',join_axes=None,ignore_index=False)
    
    • 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)轴的特定索引,而不是执行内部/外部设置逻辑。
    df1 = 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
    
    
  2. pd.merge()

    pd.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来进行合并。
    # 注意: 每一列元素的顺序不要求一致
    
    • left : 一个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将大大提高性能。

    # 一对一匹配合并
    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
    

3.3 使用tushare包获取某股票的历史行情数据。

import tushare as ts
ts.set_token('your token here')
pro = ts.pro_api()
df = ts.get_k_data('600519',start='1900-01-01')
df.to_csv('./maotai.csv')

3.3.1 输出该股票所有收盘比开盘上涨3%以上的日期

df = pd.read_csv('./maotai.csv')
df.drop(labels='Unnamed: 0',axis=1,inplace=True)

#验证data列中数据类型,发现为str
type(df['date'][0])
输出:
str
# 将date这一列的数据先转成时间类型然后将其作为原数据的行索引
df = pd.read_csv('./maotai.csv',index_col='date',parse_dates=['date'])
df.drop(labels='Unnamed: 0',axis=1,inplace=True)
df
- labels:一个字符或者数值,加上axis ,表示带label标识的行或者列;如 (labels='A', axis=1) 表示A列
- axis:axis=0表示行,axis=1表示列
- columns:列名
- index:表示dataframe的index, 如index=1, index=a
- inplace:True表示删除某行后原dataframe变化,False不改变原始dataframe

# 输出该股票所有收盘比开盘上涨3%以上的日期
#(收盘-开盘)/开盘 > 0.03
(df['close'] - df['open']) / df['open'] > 0.03
#True:满足需求
#false:不满足
#返回了满足需求的行数据
df.loc[(df['close'] - df['open']) / df['open'] > 0.03]
#获取了满足需求的日期
df.loc[(df['close'] - df['open']) / df['open'] > 0.03].index

#结论:如果获取了一组布尔值,接下来改组布尔值就直接作为元数据的行索引

3.3.2 输出该股票所有开盘比前日收盘跌幅超过2%的日期

(df['open'] - df['close'].shift(1))/df['close'].shift(1) < -0.02
# shift(1) 是将索引列下移一行
# 满足需求的行数据
df.loc[(df['open'] - df['close'].shift(1))/df['close'].shift(1) < -0.02].index

3.3.3 实例

  • 假如我从2008年1月1日开始,每月第一个交易日买入1手股票,每年最后一个交易日卖出所有股票,到今天为止,我的收益如何?
  • 分析:
    • 规则:基于开盘价股票的买卖
    • 买:一个完整的年需要买12次股票,一次买入100只,一个完整的年需要买入1200只(单价:当天开盘价)
    • 卖:一个完整的年需要卖一次股票,一次卖出1200只
    • 备注:19年不是一个完整的年,该年只可以买入900只,并且卖不出去
# 数据的重新取样的机制(resample):根据指定好的规则进行指定数据的提取
# 根据月份提取
df_monthly = df_new.resample('M').first()
df_monthly.head()

# 计算出买股票一共花了多少钱
cost_money = df_monthly['open'].sum()*100
cost_money
输出:
3679128.6999999997

# 计算卖出所有的股票一共进账多少钱
# 根据年份提取
df_yearly = df_new.resample('A').last()
# 去除最后一年
df_yearly = df_yearly[:-1]
recv_money = df_yearly['open'].sum()*1200
recv_money
输出:
3160378.8000000003

# 19年买入了900只股票没有卖出,剩余的股票也计算到总收益
# 剩余股票的单价应该选择使用昨日的收盘价
# 最后一行
last_price = df.iloc[-1]['close']
last_price

cunHuo_price = last_price['close'] * 900

# 计算总收益
cunHuo_price+recv_money-cost_money
输出:
515260.100000001

4 数据处理

4.1 处理丢失数据

有两种丢失数据:

  1. None

    None是Python自带的,其类型为python object。因此,None不能参与到任何计算中。

    #查看None的数据类型
    type(None)
    输出:
    NoneType
    
  2. NaN

    np.nan是浮点类型,能参与到计算中。但计算的结果总是NaN

    type(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
    
    

4.1.1 删除包含空字段的行

DataFrame.dropna(axis=0, how='any', thresh=None, subset=None, inplace=False)

# 示例
df.dropna(axis=0,how='any',inplace=False)

# 移除指定列(col01)有空值的行
df.dropna(axis=0,subset=['col01'] ,how='any',inplace=False)

  • axis:默认为 0,表示逢空值剔除整行,如果设置参数 axis=1 表示逢空值去掉整列。
  • how:默认为 'any' 如果一行(或一列)里任何一个数据有出现 NA 就去掉整行,如果设置 how='all' 一行(或列)都是 NA 才去掉这整行。
  • thresh:设置需要多少非空值的数据才可以保留下来的。
  • subset:设置想要检查的列。如果是多个列,可以使用列名的 list 作为参数。
  • inplace:如果设置 True,将计算得到的值直接覆盖之前的值并返回 None,修改的是源数据。

4.1.2 检测哪些列中存在空值

# Pandas 把 n/a 和 NA 当作空数据,na 不是空数据,不符合我们要求,我们可以指定空数据类型:
missing_values = ["n/a", "na", "--"]
df = pd.read_csv('property-data.csv', na_values = missing_values)

# 判断列中是否存在空值,axis=1时判断行
df.isnull().any(axis=0)
any() :一行(或一列)里任何一个数据有出现 NA 就去掉整行
all(): 一行(或列)都是 NA 才去掉这整行。

4.1.3 fillna() 方法来替换空字段

# 使用12345数据替换空字段
df.fillna(12345, inplace = True)

# 指定某列替换空字段,如使用 12345 替换 PID 为空数据:
df['PID'].fillna(12345, inplace = True)

# 
# 数据清洗:填充空值
df.fillna(method='ffill',axis=0,inplace=True)
df.fillna(method='bfill',axis=0,inplace=True)
# method:指定一个值去替换缺失值(缺省默认这种方式)
# 'ffill':用前一个非缺失值去填充该缺失值
# 'bfill':用后一个非缺失值去填充该缺失值
# axis:默认为0,表示行填充,axis=1表示列填充。

4.2 清洗重复数据

# 如果对应的数据是重复的,duplicated() 会返回 True,否则返回 False。
df.duplicated()
# 删除重复数据
df.drop_duplicates(subset = None,keep = 'first',inplace = False,ignore_index = False,)
  • keep : {'first', 'last', False}
    • first : 保留第一个数据,默认
    • last : 保留最后一个数据
    • False : 丢弃所有数据

4.3 处理数据异常值

  • 使用df.std()函数可以求得DataFrame对象每一列的标准差
  • 创建一个1000行3列的df 范围(0-1),求其每一列的标准差
  • 对df应用筛选条件,去除标准差太大的数据:假设过滤条件为 C列数据大于两倍的C列标准差
df = pd.DataFrame(np.random.random(size=(100,3)),columns=['A','B','C'])
std_twice = df['C'].std()*2
std_twice_index = df.loc[df['C']>std_twice].index
df.drop(labels=std_twice_index,axis=0,inplace=True)

4.4 数据映射

4.4.1 替换元素:df.replace()

df.replace(to_replace=None, value=None, inplace=False, limit=None, regex=False, method='pad',)
# 单值替换
    普通替换: 替换所有符合要求的元素:to_replace=15,value='e'
    按列指定单值替换: to_replace={列标签:替换值} value='value'
# 多值替换
    列表替换: to_replace=[] value=[]
    字典替换(推荐) to_replace={to_replace:value,to_replace:value}
  • to_replace:被替换的值
  • value:替换后的值
  • inplace:是否要改变原数据,False是不改变,True是改变,默认是False
  • limit:控制填充次数
  • regex:是否使用正则,False是不使用,True是使用,默认是False
  • method:填充方式,pad,ffill,bfill分别是向前、向前、向后填充
  • 注意:DataFrame中,无法使用method和limit参数
df = pd.DataFrame(data=np.random.randint(1,100,size=(8,5)))
df
输出:
	0	1	2	3
0	91	22	61	58
1	80	52	86	10
2	57	85	21	90

#  替换单值
df.replace(to_replace=10,value='ten',inplace=True)
df.replace(to_replace=80,value='ten',inplace=True)
输出:
	0	1	2	3
0	91	22	61	58
1	ten	52	86	ten
2	57	85	21	90

# 只替换第一列的数据
df.replace(to_replace={0:'ten'},value='one0')
输出:
	0	1	2	3
0	91	22	61	58
1	one0	52	86	ten
2	57	85	21	90

# 替换多值:列表
df.replace(to_replace=['ten',91],value=['one0','nineOne'])
输出:
	0	1	2	3
0	nineOne	22	61	58
1	10	52	86	10
2	57	85	21	90

# 替换多值:字典
df.replace(to_replace={'ten':'One0',91:'nine1'})
输出:
	0	1	2	3
0	nine1	22	61	58
1	One0	52	86	One0
2	57	85	21	90

4.4.2 元素映射map()

  • map():会根据提供的函数对指定序列做映射
  • map():可以映射新一列数据
  • map():中可以使用lambd表达式
  • map():中可以使用方法,可以是自定义的方法
  • map():并不是df的方法,而是series的方法
  • map():中不能使用sum之类的函数,for循环
  • 并不是任何形式的函数都可以作为map的参数。只有当一个函数具有一个参数且有返回值,那么该函数才可以作为map的参数。
# 创建数据表
dic = {
    'name':['张三','李四','王五'],
    'Score':[130,140,150],
}
df = pd.DataFrame(data=dic)
df
输出:

	name	Score
0	张三	130
1	李四	140
2	王五	150

# 映射关系表
dic = {
    '张三':'san',
    '李四':'si',
    '王五':'wu'
}
df['nick_name'] = df['name'].map(dic)
df
	name	Score	nick_name
0	张三	130	san
1	李四	140	si
2	王五	150	wu

# 将map当做一种运算工具,至于执行何种运算,是由map函数的参数决定的,(参数:lambda,函数)
def true_score(s):
    return s*0.75

df['true_score'] = df['Score'].map(true_score)
df
输出:
	name	Score	nick_name	true_score
0	张三	130	san	97.5
1	李四	140	si	105.0
2	王五	150	wu	112.5

4.4.3 元素映射apply()

  • apply和map都可以作为一种基于Series的运算工具,并且apply比map更快
  • 输出的是一个映射关系表
df['Score'].apply(true_score)
输出:
0     97.5
1    105.0
2    112.5
Name: Score, dtype: float64

4.5 数据采样take()

take()函数接受一个索引列表,用数字表示,使得df根据列表中索引的顺序进行采样

  • 可以借助np.random.permutation()函数随机抽样
# 行采样
df.take([1,0,2])
输出:
	A	B	C
1	0.021581	0.400854	0.986081
0	0.158678	0.888694	0.498163
2	0.974851	0.925864	0.147149

# 列采样
df.take([1,0,2],axis=1).head(2)
输出:
	B	A	C
0	0.888694	0.158678	0.498163
1	0.400854	0.021581	0.986081

# 随机抽样
# 随机列展示,再随机抽样10个数据
df.take(np.random.permutation(3),axis=1).take(np.random.permutation(10),axis=0)

4.6 数据分类处理

4.6.1 数据分组

df = DataFrame({'item':['Apple','Banana','Orange','Banana','Orange','Apple'],
                'price':[4,3,3,2.5,4,2],
               'color':['red','yellow','yellow','green','green','green'],
               'weight':[12,20,50,30,20,44]})
df
输出:
	item	price	color	weight
0	Apple	4.0	red	12
1	Banana	3.0	yellow	20
2	Orange	3.0	yellow	50
3	Banana	2.5	green	30
4	Orange	4.0	green	20
5	Apple	2.0	green	44

# 使用groupby实现分组
# 使用groups查看分组情况
df.groupby('item',axis=0)
df.groupby('item',axis=0).groups
输出:
{'Apple': [0, 5], 'Banana': [1, 3], 'Orange': [2, 4]}

4.6.2 操作分组后的数据

分组后的成员中可以被进行运算的值会进行运算,不能被运算的值不进行运算

# 默认如果不指定列的话,会计算所有列的平均值,此处指定计算price列
# 以item中的项目分组计算每个项目价格的平均值
s = df.groupby('item').mean()['price']
s.to_dict()
df['mean_price'] = df['item'].map(s.to_dict())
输出:
	item	price	color	weight	mean_price
0	Apple	4.0	red	12	3.00
1	Banana	3.0	yellow	20	2.75
2	Orange	3.0	yellow	50	3.50
3	Banana	2.5	green	30	2.75
4	Orange	4.0	green	20	3.50
5	Apple	2.0	green	44	3.00

# 以color中的项目分组计算每个颜色价格的平均值
s = df.groupby('color',axis=0).mean()['price'].to_dict()
df['color_mean_price'] = df['color'].map(s)

	item	price	color	weight	mean_price	color_mean_price
0	Apple	4.0	red	12	3.00	4.000000
1	Banana	3.0	yellow	20	2.75	3.000000
2	Orange	3.0	yellow	50	3.50	3.000000
3	Banana	2.5	green	30	2.75	2.833333
4	Orange	4.0	green	20	3.50	2.833333
5	Apple	2.0	green	44	3.00	2.833333

4.6.3 高级数据聚合

  • 使用groupby分组后,也使用transform和apply提供自定义函数实现更多的运算
  • apply:输出为数据值
  • transform:输出为数据映射值
  • transform和apply都会进行运算,在transform或者apply中传入函数即可
  • transform和apply也可以传入一个lambda表达式
df.groupby('item')['price'].sum()
近似于
df.groupby('item')['price'].apply(sum)
输出:
item
Apple     6.0
Banana    5.5
Orange    7.0
Name: price, dtype: float64

# 自定义处理函数
def myFun(s):# 必须要有一个参数
    sum = 0
    for i in s:
        sum +=i
    return sum/len(s)

df.groupby(by='item')['price'].apply(myFun)
输出:
0    3.00
1    2.75
2    3.50
3    2.75
4    3.50
5    3.00
Name: price, dtype: float64

df.groupby(by='item')['price'].transform(myFun)
输出:
0    3.00
1    2.75
2    3.50
3    2.75
4    3.50
5    3.00
Name: price, dtype: float64

4.6.4 query()

  • 通过query("查询条件来查找")
months = {'JAN' : 1, 'FEB' : 2, 'MAR' : 3, 'APR' : 4, 'MAY' : 5, 'JUN' : 6,
          'JUL' : 7, 'AUG' : 8, 'SEP' : 9, 'OCT': 10, 'NOV': 11, 'DEC' : 12}
of_interest = ['Obama, Barack', 'Romney, Mitt', 'Santorum, Rick', 
               'Paul, Ron', 'Gingrich, Newt']
parties = {
  'Bachmann, Michelle': 'Republican',
  'Romney, Mitt': 'Republican',
  'Obama, Barack': 'Democrat',
  "Roemer, Charles E. 'Buddy' III": 'Reform',
  'Pawlenty, Timothy': 'Republican',
  'Johnson, Gary Earl': 'Libertarian',
  'Paul, Ron': 'Republican',
  'Santorum, Rick': 'Republican',
  'Cain, Herman': 'Republican',
  'Gingrich, Newt': 'Republican',
  'McCotter, Thaddeus G': 'Republican',
  'Huntsman, Jon': 'Republican',
  'Perry, Rick': 'Republican'           
 }

#读取数据
df = pd.read_csv('./usa_election.txt')
df.head(2)
输出:
     cmte_id    cand_id             cand_nm        contbr_nm contbr_city  \
0  C00410118  P20002978  Bachmann, Michelle  HARVEY, WILLIAM      MOBILE   
1  C00410118  P20002978  Bachmann, Michelle  HARVEY, WILLIAM      MOBILE   

  contbr_st   contbr_zip contbr_employer contbr_occupation  contb_receipt_amt  \
0        AL  366010290.0         RETIRED           RETIRED              250.0   
1        AL  366010290.0         RETIRED           RETIRED               50.0   

  contb_receipt_dt receipt_desc memo_cd memo_text form_tp  file_num  
0        20-JUN-11          NaN     NaN       NaN   SA17A    736166  
1        23-JUN-11          NaN     NaN       NaN   SA17A    736166  

#新建一列各个候选人所在党派party
df['party'] = df['cand_nm'].map(parties)
df.head(2)

#查看colums:party这一列中有哪些元素
df['party'].unique()

#统计party列中各个元素出现次数
df['party'].value_counts()

#查看各个党派收到的政治献金总数
df.groupby('party')['contb_receipt_amt'].sum()

#每天每个党派收到政治现金的总数
df.groupby(['contb_receipt_dt','party'])['contb_receipt_amt'].sum()


# 将表中日期格式转换为'yyyy-mm-dd'
def new_date(s):
    day,month,year=s.split('-')
    month=months[month]
    return '20'+year+'-'+str(month)+'-'+day
df['contb_receipt_dt']=df['contb_receipt_dt'].map(new_date)
df.head(2)

# 查看老兵(捐献者职业)DISABLED VETERAN主要支持谁(给谁捐钱最多)
df['contbr_occupation'] == 'DISABLED VETERAN'
disabled_veteran = df.loc[df['contbr_occupation'] == 'DISABLED VETERAN']
disabled_veteran.groupby('cand_nm')['contb_receipt_amt'].sum()

#候选人的捐赠者中,捐赠金额最大的人的职业以及捐献额
df['contb_receipt_amt'].max()
df.query('contb_receipt_amt == 1944042.43')[['contbr_occupation','contb_receipt_amt']]

4.7 算法处理分析数据

4.7.1 几个概念

  • 人工智能和机器学习之间的关系:
    • 机器学习是用来实现人工智能的一种技术手段
  • 算法模型
    • 概念:特殊的对象。特殊之处就在于该对象内部已经集成或者封装好一个某种方程(还没有求出解的方程)
    • 作用:算法模型对象最终求出的解就是该算法模型实现预测或者分类的结果
      • 预测
      • 分类
  • 样本数据:numpy,DataFrame
    • 样本数据和算法模型之间的关联:样本数据是需要带入到算法模型对象中对其内部封装的方程进行求解的操作。该过程被称为模型的训练。
    • 组成部分:
      • 特征数据:自变量(x)
      • 目标数据:因变量(y)
  • 模型的分类:
    • 有监督学习:如果模型需要的样本数据中必须包含特征和目标数据,则该模型归为有监督学习的分类
    • 无监督学习:如果模型需要的样本数据只需要有特征数据即可。
  • sklearn模块:大概封装了10多种算法模型对象。
    • 线性回归算法模型:预测
    • KNN算法模型:分类

4.7.2 线性回归

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from pylab import mpl
from sklearn.linear_model import LinearRegression


mpl.rcParams['font.sans-serif'] = ['FangSong'] # 指定默认字体
mpl.rcParams['axes.unicode_minus'] = False # 解决保存图像是负号'-'显示为方块的问题

# 整合数据
ferrara1 = pd.read_csv('./ferrara_150715.csv')
ferrara2 = pd.read_csv('./ferrara_250715.csv')
ferrara3 = pd.read_csv('./ferrara_270615.csv')
ferrara=pd.concat([ferrara1,ferrara1,ferrara1],ignore_index=True)
...
faenza3 = pd.read_csv('./faenza_270615.csv')
faenza = pd.concat([faenza1,faenza2,faenza3],ignore_index=True)

# 去除无用的列
city_list = [ferrara,torino,mantova,milano,ravenna,asti,bologna,piacenza,cesena,faenza]
for city in city_list:
    city.drop(labels='Unnamed: 0',axis=1,inplace=True)

# 显示最高温度于离海远近的关系
max_temp=[]
city_dist = []
for city in city_list:
    temp = city['temp'].max()
    max_temp.append(temp)
    dist =  city['dist'].max()
    city_dist.append(dist)
city_dist

# 绘制散点图
plt.scatter(city_dist,max_temp)
plt.xlabel('距离')
plt.ylabel('温度')
plt.title('城市最高温度和离海远近之间的关系')

#对当前的数据建立一个算法模型,然后可以让模型实现预测的功能(根据距离预测最高温度)。
# y = kx + b线性方程,该方程还没有求出解
# 如果方程中的k和b是已知的,则该方程就有解
# 建立线性回归算法模型对象
linner = LinearRegression()

#样本数据的封装/提取
feature = np.array(city_dist)
feature = feature.reshape(-1, 1)
target = np.array(max_temp)

#对模型进行训练
linner.fit(feature,target)  #X:二维形式的特征数据,y:目标数据

# (标量) 系数b
linner.intercept_

# (数组)斜率
linner.coef_

# 对预测结果计算出的决定系数R^2
# 决定系数反应了y的波动有多少百分比能被x的波动所描述,即表征依变数Y的变异中有多少百分比,可由控制的自变数X来解释。
# 意义:拟合优度越大,说明x对y的解释程度越高。自变量对因变量的解释程度越高,自变量引起的变动占总变动的百分比高。观察点在回归直线附近越密集。
linner.score(feature,target)

# 绘制回归曲线
x = np.linspace(0,350,100).reshape(-1,1)
y = linner.predict(x)
plt.scatter(city_dist,max_temp)
plt.scatter(x,y)
plt.xlabel('距离')
plt.ylabel('温度')
plt.title('海滨城市最高温度和离海远近之间的关系')

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. 欧几里得距离(Euclidean Distance): 欧氏距离是最常见的距离度量,衡量的是多维空间中各个点之间的绝对距离。公式如下:

    image-20230314223128357

  4. 实例:KNN手写数字识别

    #特征数据的职位是字符串类型的数据,特征数据在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)
    
posted @ 2023-03-14 22:51  f_carey  阅读(2553)  评论(0编辑  收藏  举报