总字符数: 25.54K

代码: 17.89K, 文本: 3.33K

预计阅读时间: 1.54 小时

Matplotlib

matplotlib基本要点

基本使用

1
2
3
4
5
6
7
8
9
from matplotlib import pyplot as plt#导入pyplot
x = range(2,26,2)
#数据在x轴的位置,是一个可迭代对象
y =[15,13,14.5,17,20,25,26,26,24,22,18,15]
#数据在y轴的位置,是一个可迭代对象
#x轴和y轴的数据一起组成了所有要绘制出的坐标
分别是(2,15),(4,13),(6,14.5),(8,17)...
plt.plot(x,y)#传入x和y,通过plot绘制出折线图
plt.show()#在执行程序的时候展示图形

图片大小

1
2
3
4
5
6
7
8
9
plt.figure(figsize=(20,8),dpi=80)
#figure图形图标的意思,在这里指的就是我们画的图
#通过实例化一个fgure并且传递参数,能够在后台自动使用该fgure实例
#在图像模糊的时候可以传入dpi参数,让图片更加清晰
x = range(2,26,2)
y =[15,13,14.5,17,20,25,26,26,24,22,18,15]plt.plot(x,y)
plt.savefig("./sig_size.png ")#保存图片
#可以保存为svg这种矢量图格式,放大不会有锯齿
plt.show()

x/y轴刻度

1
2
3
# 标签竖着显示
plt.xticks(rotation=300)#x轴刻度rotation:旋转的度数
plt.yticks()#y轴刻度

中文显示

1
2
3
# 设置matplotlib正常显示中文和负号
plt.rcParams['font.sans-serif'] = ['SimHei'] # 用黑体显示中文
plt.rcParams['axes.unicode_minus'] = False # 正常显示负号

描述信息

1
2
3
plt.xlabel('x轴描述信息')
plt.ylabel('y轴描述信息')
plt.title('标题')

图形网格

1
plt.grid(alpha=0.4)#绘制网格,alpha:透明度

图例

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
#散点图
from matplotlib import pyplot as plt
from matplotlib import font_manager
# 设置matplotlib正常显示中文和负号
plt.rcParams['font.sans-serif'] = ['SimHei'] # 用黑体显示中文
plt.rcParams['axes.unicode_minus'] = False # 正常显示负号

y_3=[11,17,16,11,12,11,12,6,6,7,8,9,12,15,14,17,18,21,16,17,20,14,15,15,15,19,21,22,22,22,23]#3月份
y_10=[26,26,28,19,21,17,16,19,18,20,20,19,22,23,17,20,21,20,22,15,11,15,5,13,17,10,11,13,12,13,6]#10月份
x_3 =range(1,32)
x_10=range(51,82)
#设置图形大小
plt.figure(figsize=(20,8),dpi=80)
#使用scatter绘制散点图
plt.scatter(x_3,y_3,label='3月份')
plt.scatter(x_10,y_10,label='10月份')
#调整X轴的刻度
_x = list(x_3)+list(x_10)
_xtick_labels=['3月{}日'.format(i) for i in x_3]
_xtick_labels+=['10月{}日'.format(i-50) for i in x_10]
plt.xticks(_x[::3],_xtick_labels[::3],rotation=45)#[::3]步长为3,rotation倾斜角度
#添加图例
plt.legend(loc=2)
#添加描述信息
plt.xlabel('时间')
plt.ylabel('温度')
plt.title('标题')
#展示
plt.show()

自定义绘制图形风格

1
plt.plot(x,y,color='r',linestyle='--',linewidth=5,alpha=0.5)#color线条颜色,linestyle线条风格,linewidth线条粗细,alpha透明度
颜色字符 描述 风格字符 描述
r 红色 - 实线
g 绿色 -- 虚线
b 蓝色 -. 点划线
c 青色 : 点线
m 洋红色 '' 无线条
y 黄色
k 黑色
#00ff00 16进制颜色值
0.8 灰度值字符串

折线图

动手

假设大家在30岁的时候,根据自己的实际情况,统计出来了你和你同桌各自从11岁到30岁每年交的女(男)朋友的数量如列表a和b,请在一个图中绘制出该数据的折线图,以便比较自己和同桌20年间的差异,同时分析每年交女(男)朋友的数量走势

1
2
3
4
5
a = [1,0,1,1,2,4,3,2,3,4,4,5,6,5,4,3,3,1,1,1]
b =[1,0,3,1,2,2,3,3,2,1,2,1,1,1,1,1,1,1,1,1]
要求:
y轴表示个数
x轴表示岁数,比如11岁,12岁等

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
y_1 = [1,0,1,1,2,4,3,2,3,4,4,5,6,5,4,3,3,1,1,1]
y_2 =[1,0,3,1,2,2,3,3,2,1,2,1,1,1,1,1,1,1,1,1]
x=range(11,31)
#设置图形大小
plt.figure(figsize=(20,8),dpi=80)
#设置X轴刻度
xtick_labels=['{}岁'.format(i) for i in x]
plt.xticks(x,xtick_labels)
plt.yticks(range(0,9))
#绘制网格
plt.grid(alpha=0.4)
plt.plot(x,y_1,label='自己')
plt.plot(x,y_2,label='同桌')
#添加图例
plt.legend()
#展示
plt.show()

散点图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#散点图
from matplotlib import pyplot as plt
from matplotlib import font_manager
# 设置matplotlib正常显示中文和负号
plt.rcParams['font.sans-serif'] = ['SimHei'] # 用黑体显示中文
plt.rcParams['axes.unicode_minus'] = False # 正常显示负号

y_3=[11,17,16,11,12,11,12,6,6,7,8,9,12,15,14,17,18,21,16,17,20,14,15,15,15,19,21,22,22,22,23]#3月份
y_10=[26,26,28,19,21,17,16,19,18,20,20,19,22,23,17,20,21,20,22,15,11,15,5,13,17,10,11,13,12,13,6]#10月份
x_3 =range(1,32)
x_10=range(51,82)
#设置图形大小
plt.figure(figsize=(20,8),dpi=80)
plt.scatter(x_3,y_3)
plt.scatter(x_10,y_10)
#调整X轴的刻度
_x = list(x_3)+list(x_10)
_xtick_labels=['3月{}日'.format(i) for i in x_3]
_xtick_labels+=['10月{}日'.format(i-50) for i in x_10]
plt.xticks(_x[::3],_xtick_labels[::3],rotation=45)
#展示
plt.show()

条形图

1
2
3
4
5
6
7
#绘制条形图
x=["战狼2","速度与激情8","功夫瑜伽","西游伏妖篇","变形金刚5:最后的骑士","摔跤吧!爸爸","加勒比海盗5死无对证" ,"金刚:骷髅岛","极限特工:终极回归","生化危机6:终章", "乘风破浪","神偷奶爸3" ,"智取威虎山","大闹天竺","金刚狼3:殊死一战","蜘矜侠:英雄归来","悟空传","银河护卫队2","情圣","新木乃伊",]
y=[56.01,26.94,17.53,16.49,15.45,12.96,11.8,11.61,11.28,11.12,10.49,10.3,8.75,7.55,7.32,6.99,6.88,6.86,6.58,6.23]#单位:亿
plt.figure(figsize=(20,8),dpi=80)
plt.bar(x,y,width=0.3)
plt.xticks(x,rotation=90)#让文字旋转90度,避免文字重叠
plt.show()
1
2
3
4
5
6
7
8
#绘制横着的条形图
x=["战狼2","速度与激情8","功夫瑜伽","西游伏妖篇","变形金刚5:最后的骑士","摔跤吧!爸爸","加勒比海盗5死无对证" ,"金刚:骷髅岛","极限特工:终极回归","生化危机6:终章", "乘风破浪","神偷奶爸3" ,"智取威虎山","大闹天竺","金刚狼3:殊死一战","蜘矜侠:英雄归来","悟空传","银河护卫队2","情圣","新木乃伊",]
y=[56.01,26.94,17.53,16.49,15.45,12.96,11.8,11.61,11.28,11.12,10.49,10.3,8.75,7.55,7.32,6.99,6.88,6.86,6.58,6.23]#单位:亿
plt.figure(figsize=(20,8),dpi=80)
plt.barh(range(len(x)),y,height=0.3)
plt.yticks(range(len(x)),x)
plt.grid(alpha=0.4)
plt.show()

多条形图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 假设你知道了列表a中电影分别在2017-09-14(b_14),2017-09-15(b_15),2017-09-16(b_16)三天的票房,为了展示列表中电影本身的票房以及同其他电影的数据对比情况,应该如何更加直观的呈现该数据?
x = ["猩球崛起3:终极之战", "敦刻尔克", "蜘蛛侠:英雄归来", "战狼2"]
b_14 = [2358, 399, 2358, 362]
b_15 = [12357, 156, 2045, 168]
b_16 = [15746, 312, 4497, 319]
bar_width = 0.2
x_14 = list(range(len(x)))
x_15 = [i+bar_width for i in x_14]
x_16 = [i+bar_width*2 for i in x_14]
# 设置图形大小
plt.figure(figsize=(20, 8), dpi=80)
plt.bar(range(len(x)),b_14, width=bar_width,label='9月14日')
plt.bar(x_15, b_15, width=bar_width,label='9月15日')
plt.bar(x_16, b_16, width=bar_width,label='9月16日')
#设置图例
plt.legend()
#设置x轴的刻度
plt.xticks(x_15,x)
plt.show()

直方图

把数据分为多少组进行统计???

组数要适当,太少会有较大的统计误差,大多规律不明显

组数:将数据分组,当数据在100个以内时,
按数据多少常分5-12组.
组距:指每个小组的两个端点的距离

1
2
3
4
5
6
7
8
9
10
11
bin_width = 3#设置组距为3
num_bins = int((max (a)-min(a))/bin_width)#分为多少组
plt.hist(a,num_bins)
#传入需要统计的数据,以及组数即可
#plt.hist(a,[min(a)+i*bin_width for i in range(num_bins)])
#可以传入一个列表,长度为组数,值为分组依据,当组距不均匀的时候使用
#plt.hist(a, num_bins,normed=1)
#normed : bool是否绘制频率分布直方图,默认为频数直方图
plt.xticks(list(range(min(a),max(a))[::bin_width],rotation=45)
plt.grid(True,linestyle = "-.",alpha=0.5)
#显示网格,alpha为透明度
1
2
3
4
5
6
7
8
9
10
11
12
13
#直方图
#假设你获取了250部电影的时长(列表a中),希望统计出这些电影时长的分布状态(比如时长为100分钟到120分钟电影的数量,出现的频率)等信息,你应该如何呈现这些数据?
a = [131, 98, 125, 131, 124, 139, 131, 117, 128, 108,135, 138, 131, 102, 107, 114, 119, 128, 121, 142, 127, 130, 124, 101,110, 116, 117, 110, 128, 128, 90, 99, 136, 126, 134, 95, 138, 117, 79, 78,132, 124, 113, 150, 110, 117, 86, 95, 144, 105, 126, 130, 126, 130, 126, 116, 123, 106, 112, 138,123, 86, 101, 99, 136, 123, 117, 119, 105, 137, 123, 128, 125, 104, 109, 134, 125, 127, 105, 120, 107, 129, 116,108, 132, 103, 136, 118, 102, 120, 114, 105, 115, 132, 145, 119, 121, 112, 139, 125, 138, 109, 132, 134, 156, 106,117, 127, 144, 139, 139, 119, 140, 83, 110, 102, 123, 107, 143, 115, 136, 118, 139, 123, 112, 88, 125, 109, 119, 133, 112, 114,122, 109, 106, 123, 116, 131, 127, 115, 118, 112, 135, 115, 146, 137, 116, 103, 144, 83, 123, 79, 110, 101, 100, 154, 136,100, 118, 119, 133, 134, 106, 129, 126, 110, 98, 109, 141, 120, 117, 106, 149, 122, 122, 110, 118, 127, 121, 114, 125, 126,114, 140, 103, 130, 141, 117, 106, 114, 121, 114, 133, 137, 92, 121, 112, 146, 97, 137, 105, 98, 117, 112, 81, 97, 139, 113, 134, 106, 144, 110, 137, 137, 91, 104, 117, 100, 111, 101, 110, 105, 129, 137, 112, 120, 113, 133,112, 83, 94, 146, 133, 101, 131, 116, 111, 84, 137, 115, 122, 106, 144, 109, 123, 116, 111, 111, 133, 150]
plt.figure(figsize=(20,8),dpi=80)
plt.grid()
# 组距(组距最好选可以让max(a)-min(a)整除的)
d = 3
#计算组数
num_bins=(max(a)-min(a))//d
plt.hist(a,num_bins)
#设置x轴的刻度
plt.xticks(range(min(a),max(a)+d,d))#max(a)+d保证可以取到最大值
plt.show()

用条形图绘制直方图

1
2
3
4
5
6
7
8
9
10
11
12
13
#在美国2004年人口普查发现有124 million的人在离家相对较远的地方工作.根据他们从家到上班地点所需要的时间,通过抽样统计(最后一列)出了下表的数据,这些数据能够绘制成直方图么?
interval = [0,5,10,15,20,25,30,35,40,45,60,90]#时间段m
width =[5,5,5,5,5,5,5,5,5,15,30,60]#组距
quantity = [836,2737,3723,3926,3596,1438,3273,642,824,613,215,47]#数据
# 前面的问题中给出的数据都是统计之后的数据,所以为了达到直方图的效果,需要绘制条形图
# 所以:一般来说能够使用plt.hist方法的的是那些没有统计过的数据
plt.figure(figsize=(20,8),dpi=80)
plt.grid()
plt.bar(range(12),quantity,width=1)
#设置x轴的刻度
_x = [i-0.5 for i in range(13)]#让x轴往左移动0.5
plt.xticks(_x,interval+[150])
plt.show()

Numpy

什么是numpy

一个在Python中做科学计算的基础库,重在数值计算,也是大部分PYTHON科学计算库的基础库,多用于在大型、多维数组上执行数值运算

numpy基础

numpy创建数组(矩阵)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#numpy
#创建数组:
import numpy as np
a = np.array ([1,2,3,4,5])
b = np.array (range(1,6))
c = np.arange(1,6)
#上面a,b,c内容相同,注意arange和range的区别
#np.arange的用法: arange([start,] stop[,step,],dtype=None)
#数组的类名:
a =np.array ([1,2,3,4,5])
type(a)
#numpy.ndarray
#数据的类型
a.dtype
#dtype('int32')

numpy中的数据类型

类型 类型代码 说明
int8、uint8 i1、u1 有符号和无符号的8位(1个字节)整型
int16、uint16 i2、u2 有符号和无符号的16位(2个字节)整型
int32、uint32 i4、u4 有符号和无符号的32位(4个字节)整型
int64、uint64 i8、u8 有符号和无符号的64位(8个字节)整型
float16 f2 半精度浮点数
float32 f4或f 标准的单精度浮点数.与C的float兼容
float64 f8或d 标准的双精度浮点数.与C的double和Python的float对象兼容
float128 f16或g 扩展精度浮点数
complex64、complex128 c8、c16 分别用两个32位、64位或128位浮点数表示的
complex256 c32 复数
bool ? 存储True和False值的布尔类型
1
2
3
4
5
6
7
8
9
10
11
#指定创建的数组的数据类型:
a=np.array([1,0,1,0],dtype=np.bool) #或者使用dtype='?'
a
#Out:array([ True, False, True, False])
# 修改数组的数据类型:
# a.astype("i1")#或者使用a.astype(np.int8)
#Out:array([1, 0, 1, 0], dtype=int8)
#修改浮点型的小数位数:
# b
# np.round (b,2)
# 那么问题来了,python中如何保留固定位数的小数?

数组的形状

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
import numpy as np
#查看数组的形状:a.shape
t1=np.arange(12)
t1
#OUT:array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])
t1.shape
#OUT:(12,)
t2=np.array([[1,2,3],[4,5,6]])
t2
#OUT:array([[1, 2, 3],[4, 5, 6]])
t2.shape
#OUT:(2, 3)
t3=np.array([[[1,2,3,],[4,5,6]],[[7,8,9],[10,11,12]]])
t3.shape#OUT:(2, 2, 3)
#修改数组的形状:a.reshape(3,4)
t4=np.arange(12)
t4#OUT:array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])
t4.reshape((3,4))#变成3行4列的数组,3*4=12
# OUT:array([[ 0, 1, 2, 3],[ 4, 5, 6, 7],[ 8, 9, 10, 11]])
t5=np.arange(24).reshape((2,3,4))#2块,3行4列
t5
#OUT:array([[[ 0, 1, 2, 3],
# [ 4, 5, 6, 7],
# [ 8, 9, 10, 11]],
# [[12, 13, 14, 15],
# [16, 17, 18, 19],
# [20, 21, 22, 23]]])
t5 = t5.reshape((4,6))#t5本身不会改变
# OUT:array([[ 0, 1, 2, 3, 4, 5],
# [ 6, 7, 8, 9, 10, 11],
# [12, 13, 14, 15, 16, 17],
# [18, 19, 20, 21, 22, 23]])
# t6.shape[0]*t6.shape[1]#加入不知道t6有多少个但是想把它变成一维的所以用shape[0]*shape[1]
t6=t5.reshape((t5.shape[0]*t5.shape[1],))#shape[0]行数,shape[1]列数或者t5.flatten()
t6
# OUT:array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
# 17, 18, 19, 20, 21, 22, 23])
t5.flatten()
#OUT:array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
# 17, 18, 19, 20, 21, 22, 23])

数组的计算

数组和数的计算

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
t5
# OUT:array([[ 0, 1, 2, 3, 4, 5],
# [ 6, 7, 8, 9, 10, 11],
# [12, 13, 14, 15, 16, 17],
# [18, 19, 20, 21, 22, 23]])
t5+2#所有的值都+2,t5*2,t5-2,
#t5/0#任何数除以零都得零,有些情况下会报Warning,结果是nan,和inf,nan是零除以零的结果(nan(not on number不是一个数字)),inf(infinity,无穷)是零除以一个数字的结果
#OUT:array([[nan, inf, inf, inf, inf, inf],
# [inf, inf, inf, inf, inf, inf],
# [inf, inf, inf, inf, inf, inf],
# [inf, inf, inf, inf, inf, inf]])
# OUT:array([[ 2, 3, 4, 5, 6, 7],
# [ 8, 9, 10, 11, 12, 13],
# [14, 15, 16, 17, 18, 19],
# [20, 21, 22, 23, 24, 25]])

数组和数组的计算

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
t5
#OUT:array([[ 0, 1, 2, 3, 4, 5],
# [ 6, 7, 8, 9, 10, 11],
# [12, 13, 14, 15, 16, 17],
#[18, 19, 20, 21, 22, 23]])
t6=np.arange(100,124).reshape((4,6))
t6
t6+t5#对应位置的数字相+,其他运算也是
t7=np.arange(0,6)
t7
#OUT:array([0, 1, 2, 3, 4, 5])
t5-t7#行形状一样也可以计算
# OUT:array([[ 0, 0, 0, 0, 0, 0],
# [ 6, 6, 6, 6, 6, 6],
# [12, 12, 12, 12, 12, 12],
# [18, 18, 18, 18, 18, 18]])
t8=np.arange(4).reshape((4,1))
t8
# OUT:array([[0],
# [1],
# [2],
# [3]])
t5-t8
# OUT:array([[ 0, 1, 2, 3, 4, 5],
# [ 5, 6, 7, 8, 9, 10],
# [10, 11, 12, 13, 14, 15],
# [15, 16, 17, 18, 19, 20]])
t9=np.arange(10)
t9#OUT:array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
# t5-t9#报错,对应不上

广播原则

如果两个数组的后缘维度 (trailing dimension,即从末尾开始算起的维度)的轴长度相符或其中一方的长度为1,则认为它们是广播兼容的.广播会在缺失和(或)长度为1的维度上进行.

怎么理解呢?

可以把维度指的是shape所对应的数字个数那么问题来了:

  1. shape为(3,3,3)的数组能够和(3,2)的数组进行计算么?
    1. 不可以,形状不一样
  2. shape为(3,3,2)的数组能够和(3,2)的数组进行计算么?
    1. 可以,末尾形状一样(第一块的3行2列和后面的3行2列计算,以此类推)
  3. 有什么好处呢?
    1. 举个例子:每列的数据减去列的平均值的结果

numpy常用方法


numpy常用统计方法

Pandas

什么是pandas

一个开源的Python类库:用于数据分析、数据处理、数据可视化

  • 高性能
  • 容易使用的数据结构
  • 容易使用的数据分析工具

很方便和其他类库一起使用:

  • numpy:用于数学计算
  • scikit-learn:用于机器学习

pandas读取数据

pandas需要先读取表格类型的数据,然后进行分析

数据类型 说明 Pandas读取方式
csv、tsv、txt 用逗号分隔、tab分隔的纯文本文件 pd.read_csv
excel 微软xls或者xlsx文件 pd.read_excel
mysql 关系型数据库表 pd.read_sql
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
# 导入Pandas
import pandas as pd
# 读取纯文本文件
# 读取csv,使用默认的标题行、逗号分隔
fpath="./datas/ml-latest-small/ratings.csv"
# 使用pd.read_csv读取数据
ratings=pd.read_csv(fpath)
# 查看前几行数据
ratings.head()
# 查看数据的形状,返回(行数,列数)
ratings.shape
# 查看列名列表
ratings.columns
#查看索引列
ratings.index
# 查看每列的数据类型
ratings.dtypes
# 读取txt文件,自己指定分隔符、列名
fpath="./datas/crazyant/access_pvuv.txt"
pvuv=pd.read_csv(
fpath,
sep='\t',#列分隔符
header=None,#没有标题行
names=['pdate','pv','uv']#列名
)
pvuv
# 读取excel文件
fpath="./datas/crazyant/access_pvuv.xls"
pvuv=pd.read_excel(fpath)
pvuv
# 读取mysql数据库
import pymysql
conn=pymysql.connect(
host='127.0.0.1',
user='root',
password='123456789',
datase='test',
charset='utf8'
)
mysql_page=pd.read_sql('select * from test',con=conn)
mysql_page

Pandas数据结构

DataFrame:二维数据,整个表格,多行多列

Series:一维数据,一行或一列

  • Series
  • DataFrame
  • 从DataFrame中查询出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
import pandas as pd 
import numpy as np
# 1.Series
# Series是一种类似于数组的对象,它由一组数据(不同数据类型)以及一组与之相关的数据标签(既索引组成)
# 1.1仅有数据列表即可产生最简单的Series
s1= pd.Series([1,'a',5.2,7])
s1#左侧为索引,右侧是数据
#获取索引
s1.index
#获取数据
s1.values
# 1.2 创建一个具有标签索引的Series
s2= pd.Series([1,'a',5.2,7],index=['a','b','c','d'])
s2.index
# 1.3使用python字段创建series
sdata={'a':300,'b':9900,'c':9920,'d':23556,'e':290903}
s3=pd.Series(sdata)
s3
# 1.4 根据标签索引查询数据
# 类似Python的字典dict
s2['a']
type(s2['a'])
s2[['b','a']]
type(s2[['b','a']])

DataFrame

DataFrame是一个表格型的数据结构

  • 每列可以是不同的值类型(数值、字符串、布尔值等)
  • 既有行索引index,也有列索引columns
  • 可以被看作由Series组成的字典

根据多个字典序列创建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
28
29
# 2 DataFrame
# DataFrame是一个表格型的数据结构
# 根据多个字典序列创建dataframe
data={
'state':['AMKKLS','MNNJS','JKSNGSA','JKOMNS','ASSSSV'],
'year':[2000,2001,2002,2003,2004],
'pop':[1.5,1.7,3.6,2.4,2.9]
}
df=pd.DataFrame(data)
df
df.dtypes
df.columns
df.index
# 从dataFrame中查询出Series
# 如果只查询一列、一行,返回的是pd.Series
# 如果查询多行、多列,返回的是pd.DataFrame
df
# 查询一列,结果是一个pd.Series
df['year']
type(df['year'])#pandas.core.series.Series
# 查询多列,结果是一个pd.DataFrame
df[['year','pop']]
type(df[['year','pop']])#pandas.core.frame.DataFrame
# 查询一行,结果是pd.Series
df.loc[1]
type(df.loc[1])#pandas.core.series.Series
# 查询多行,结果是一个pd.DataFrame
df.loc[1:3]
type(df.loc[1:3])#pandas.core.frame.DataFrame

Pandas查询数据的5种方法

按数值、列表、区间、条件、函数五种方法

Pandas查询数据的几种方法

1
2
3
4
5
df.loc方法,根据行、列的标签值查询
df.iloc方法,根据行、列的数字位置查询
df.where方法
df.query方法
.loc既能查询,又能覆盖写入,强烈推荐!

Pandas使用df.loc查询数据的方法

1
2
3
4
5
使用单个label值查询数据
使用值列表批量查询
使用数值区间进行范围查询
使用条件表达式查询
调用函数查询

注意

  • 以上查询方法,既适用于行,也适用于列
  • 注意观察降维dataFrame>Series>值

Pandas如何新增数据列

在进行数据分析时,经常需要按照一定条件创建新的数据列,然后进行进一步分析

  1. 直接赋值
  2. df.apply方法
  3. df.assign方法
  4. 按条件选择分组分别赋值
1
2
3
4
5
import pandas as pd
# 读取csv数据到DataFrame
fpath='./datas/beijing_tianqi/beijing_tianqi_2018.csv'
df=pd.read_csv(fpath)
df.head()

直接赋值的方法

1
2
3
4
5
6
7
8
9
# 实例:清理温度列,变成数字类型
# 替换掉温度的后缀℃
df.loc[:,'bWendu']=df['bWendu'].str.replace('℃','').astype('int32')
df.loc[:,'yWendu']=df['yWendu'].str.replace('℃','').astype('int32')
df.head()
# 实例:计算温差
# 注意:df['bWendu']其实是一个Series,后面的减法返回的是Series
df.loc[:,'wencha']=df['bWendu']-df['yWendu']
df.head()

df.apply方法

沿着df的某个轴应用一个函数.传递给函数的对象是个Series对象,其索引是数据帧的索引(axis=0)或数据帧的列(axis=1)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
实例:添加一列温度类型:
1. 如果最高温度大于33度就说高温
2. 低于-10度是低温
3. 否则是常温
def get_wendu_type(x):
if x['bWendu']>33:
return '高温'
if x['yWendu']<-10:
return '低温'
return '常温'
df.loc[:,'wendu_type']=df.apply(get_wendu_type,axis=1)
df
# 查看温度类型的计数
df['wendu_type'].value_counts()

df.assign方法

给数据帧分配新的列.返回一个新对象,其中包含除了新列之外的所有原始列.

1
2
3
4
5
# 可以同时添加多个新的列
df.assign(
yWendu_huashi = lambda x : x['yWendu']*9/5+32,
bWendu_huashi = lambda x : x['bWendu']*9/5+32
)

按条件选择分组分别赋值

按条件先选择数据,然后对这部分数据赋值新列

实例:高低温差大于10度,则认为温差大

1
2
3
4
5
# 先创建空列(这是第一种创建新列的方法)
df['wencha_type']=''
df.loc[df['bWendu']-df['yWendu']>10,'wencha_type']='温差大'
df.loc[df['bWendu']-df['yWendu']<=10,'wencha_type']='温差正常'
df['wencha_type'].value_counts()

Pandas数据统计函数

  1. 汇总类统计
  2. 唯一去重和按值计数
  3. 相关系数和协方差

汇总类统计

1
2
3
4
5
6
7
8
# 一下子提取所有数字列统计结果
df.describe()
# 查看单个Series的数据
df['bWendu'].mean()
# 最高温
df['bWendu'].max()
# 最低温
df['bWendu'].min()

唯一去重

1
2
3
df['fengxiang'].unique()
df['tianqi'].unique()
df['fengli'].unique()

按值计数

1
2
3
df['fengxiang'].value_counts()
df['tianqi'].value_counts()
df['fengli'].value_counts()

相关系数和协方差

  1. 协方差:衡量同向反向程度,如果协方差为正,说明X,Y同向变化,协方差越大说明同向程度越高;如果协方差为负,说明X,Y反向运动,协方差越小说明反向程度越高.
  2. 相关系数:衡量相似程度,当他们相关系数为1时,说明两个变量变化时的正向相似度最大,当相关系数为-1时,说明两个变量变化的反向相似度最大
1
2
3
4
5
6
7
8
9
# 协方差矩阵
df.cov()
# 相关系数矩阵
df.corr()
# 单独查看空气质量和最高温度的相关系数
df['aqi'].corr(df['bWendu'])
df['aqi'].corr(df['yWendu'])
# 空气质量和温度差的相关系数
df['aqi'].corr(df['bWendu']-df['yWendu'])

Pandas缺失值处理

Pandas使用这些函数处理缺失值

  • isnull和notnull:检测是否是空值,可用于df和series
  • dropna:丢弃、删除缺失值
    • axis:删除行还是列,{0 or  ‘index’,1or ‘columns’},default 0
    • how:如果等于any则任何值都删除,如果等于all则所有值都为空才删除
    • inplace:如果为True则修改当前df,否则返回新的df
  • fillna: 填充空值
    • value:用于填充的值,可以是单个值,或者字典(key是列名,value是值)
    • method:等于ffill使用前一个不为空的值填充forword fill;等于bfill使用后一个不为空的值填充backword fill
    • axis:按行还是列填充,{0 or  ‘index’,1or ‘columns’}
    • inplace:如果为True则修改当前df,否则返回新的df
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
import pandas as pd
fpath=('./datas/student_excel/student_excel.xls')
df = pd.read_excel(fpath,skiprows=2)# skiprows跳过前两行
df
# 检测空值
df.isnull()
df['分数'].isnull()
df['分数'].notnull()
# 筛选没有空分数的所有行
df.loc[df['分数'].notnull(),:]
# 删除掉全是空值的列
df.dropna(axis='columns',how='all',inplace=True)
df
# 删除全是空值的行
df.dropna(axis='index',how='all',inplace=True)
df
# 将分数列为空的填充为0分
df.fillna({'分数':0},inplace=True)
# 等同于
# df.loc[:,'分数']=df['分数'].fillna(0)
# 将姓名的缺失值填充
# 使用前面的有效值填充ffill:forward fill
df.loc[:,'姓名']=df.fillna(method='ffill')
df
# 将清洗好的excel保存
df.to_excel('./datas/student_excel/student_clean_excel.xls',index=False)#index=False不保存索引

Pandas 的Setting WithCopyWarning 报警复现、原因、解决方案

报警复现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import pandas as pd
# 读取csv数据到DataFrame
fpath='./datas/beijing_tianqi/beijing_tianqi_2018.csv'
df=pd.read_csv(fpath)
df.head()
# 直接赋值的方法
# 实例:清理温度列,变成数字类型
# 替换掉温度的后缀℃
df.loc[:,'bWendu']=df['bWendu'].str.replace('℃','').astype('int32')
df.loc[:,'yWendu']=df['yWendu'].str.replace('℃','').astype('int32')
df.head()
# 只选出3月份的数据用于分析
condition = df['ymd'].str.startswith('2018-03')
# 这一步会报错Setting WithCopyWarning
df[condition]['wen_cha']=df['bWendu']-df['yWendu']
df[condition].head()

原因

发出警告的代码 df[condition]['wen_cha']=df['bWendu']-df['yWendu']相当于:df.get(condition).set(wen_cha),第一步骤的get发出了报警

链式操作其实是两个步骤,先get后set,get得到的dataframe可能是view也可能是copy,pandas发出警告

核心要诀:pandas的dataframe的修改写操作,只允许在源dataframe上进行,一步到位

解决方法

  1. 将get+set的两步操作,改成set的一步操作
1
2
df.loc[condition,'wendu_cha']=df['bWendu']-df['yWendu']
df[condition].head()
  1. 如果需要预筛选数据做后续的处理分析,使用copy复制dataframe
1
2
3
4
df_month3=df[condition].copy()
df_month3.head()
df_month3['wen_cha']=df['bWendu']-df['yWendu']
df_month3.head()

注意:pandas不允许筛选子dataframe,再进行修改写入

要么使用.loc实现一个步骤直接修改源dataframe

要么先复制一个子dataframe再执行修改

Pandas数据排序

Series的排序:

Series.sort_values(ascending=True,inplace=False)

参数说明:

  • ascending:默认为True升序排序,为False降序排序
  • inplace:是否修改Series

DataFrame的排序:

DataFrame.sort_values(by,ascending=True,inplace=False)

参数说明:

  • by:字符串或者List<字符串>,单列排序或者多列排序
  • ascending:bool或者List,升序还是降序,如果是list对应by的多列
  • inplace:是否修改原始DataFrame

Series的排序

1
2
3
df['aqi'].sort_values()
df['aqi'].sort_values(ascending=False)
df['tianqi'].sort_values()

DataFrame的排序

  1. 单列排序

    1
    2
    df.sort_values(by='aqi')
    df.sort_values(by='aqi',ascending=False)
  2. 多列排序

    1
    2
    3
    4
    5
    6
    # 按空气质量等级、最高温度排序,默认升序
    df.sort_values(by=['aqiLevel','bWendu'])
    # 两个字段都是降序
    df.sort_values(by=['aqiLevel','bWendu'],ascending=False)
    # 分别指定升序和降序
    df.sort_values(by=['aqiLevel','bWendu'],ascending=[True,False])

pandas字符串处理

Pandas的字符串处理

  1. 使用方法:先获取Series的str属性,然后再属性上调用函数
  2. 只能在字符串列上使用,不能在数字列上使用
  3. Dataframe上没有str属性和处理方法
  4. Series.str并不是Python原生字符串,而是自己的一套方法,不过大部分和原生str很相似

演示内容

1
2
3
4
1. 获取Series的str属性,然后使用各种字符串处理函数
2. 使用str的startswith、contains等bool类Series可以做条件查询
3. 需要多次str处理的链式操作
4. 使用正则表达式处理
1
2
3
4
5
import pandas as pd
# 读取csv数据到DataFrame
fpath='./datas/beijing_tianqi/beijing_tianqi_2018.csv'
df=pd.read_csv(fpath)
df.head()
  1. 获取Series的str属性,使用各种字符串处理函数
1
2
3
4
5
6
df['bWendu'].str
# 字符串替换函数
df['bWendu'].str.replace('℃','')
# 判断是不是数字
df['bWendu'].str.isnumeric()
# df['aqi'].str.len() #不允许在int类型上用str
  1. 使用str的startswith、contains等得到bool的Series可以做条件查询
1
2
3
condition=df['ymd'].str.startswith('2018-03')
condition
df[condition].head()
  1. 需要多次str处理的链式操作
    怎样提取201803这样的数字月份?
  2. 先将日期2018-03-31替换成20180331的形式
  3. 提取月份字符串201803
1
2
3
4
5
 # 每次调用函数,都返回一个新Series
df['ymd'].str.replace('-','')
df['ymd'].str.replace('-','').str.slice(0,6)
# slice就是切片语法,可以直接用
df['ymd'].str.replace('-','').str[0:6]
  1. 使用正则表达式的处理
1
2
3
4
5
6
7
8
9
10
11
12
#添加新列
def get_nianyueri(x):
year, month,day = x["ymd"].split("-")
return f"{year}{month}{day}日"
df["中文日期"]= df.apply(get_nianyueri,axis=1)
df['中文日期']
# 问题:怎么将'2018年12月31日'中的年月日三个中文字符去除?
# 方法1: 链式replace
df['中文日期'].str.replace('年','').str.replace('月','').str.replace('日','')
# Series.str默认就开启了正则表达式模式
# 方法2:正则表达式替换
df['中文日期'].str.replace('[年月日]','')

Pandas的axis参数

  • axis=0或者’index’:
    • 如果是单行操作,就指的是某一行
    • 如果是聚合操作,指的是跨行cross rows
  • axis=1或者’columns’:
    • 如果是单列操作,就指的是某一列
    • 如果是聚合操作,指的是跨列cross columns

按哪个axis,就是这个axis要动起来类似被for遍历,其他的axis保持不动

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import pandas as pd 
import numpy as np
df = pd.DataFrame(
np.arange(12).reshape(3,4),
columns=['A','B','C','D']
)
df
# 1. 单列drop,就是删除某一列
# 代表的就是删除某列
df.drop('A',axis=1)
# 2. 单行drop,就是删除某一行
df.drop(1,axis=0)
# 3. 按axis=0/index执行mean聚合操作
# 反直觉:输出的不是每行的结果,而是每列的结果
df
# axis=0 or axis=index
df.mean(axis=0)
# 4. 按axis=1/columns执行mean聚合操作
df
# axis=1 or axis=columns
df.mean(axis=1)

Pandas的索引index

Pandas的索引index的用途

把数据存储与普通的column列也能用于数据查询,那使用index有什么好处?

index的用途总结:

  1. 更方便的数据查询
  2. 使用index可以获得性能提升
  3. 自动的数据对齐功能
  4. 更多更强大的数据结构支持

Pandas的索引index的用途

1
2
3
4
5
6
7
8
9
10
11
12
13
import pandas as pd 
df = pd.read_csv('./datas/ml-latest-small/ratings.csv')
df.head()
df.count()
# 1. 使用index查询数据
# drop=false,让索引列还保持在column
df.set_index('userId',inplace=True,drop=False)# set_index修改索引
df.head()
df.index
# 使用index的查询方法
df.loc[500].head(5)
# 使用column的condition查询方法
df.loc[df['userId']==500].head()

使用index会提升查询性能

  1. 如果index是唯一的,Pandas会使用哈希表优化,查询性能O(1)
  2. 如果index不是唯一的,但是有序,Pandas会使用二分查找法,查询性能为O(logN)
  3. 如果index是完全随机的,那么每次查询都要扫描全表,查询性能为O(N)

实验1:完全随机的顺序查询

1
2
3
4
5
6
7
8
from sklearn.utils import shuffle
df_shuffle=shuffle(df)
df_shuffle.head()
# 索引是否是递增的
df_shuffle.index.is_monotonic_increasing
df_shuffle.index.is_unique
# 计时,查询id==500数据性能
%timeit df_shuffle.loc[500]

实验2:将index排序后的查询

1
2
3
4
5
6
df_sorted = df_shuffle.sort_index()
df_sorted.head()
# 索引是否是递增的
df_sorted.index.is_monotonic_increasing
df_sorted.index.is_unique
%timeit df_sorted.loc[500]

使用index能自动对其数据

包括series和dataframe

1
2
3
4
5
s1=pd.Series([1,2,3],index=list('abc'))
s1
s2=pd.Series([2,3,4],index=list('bcd'))
s2
s1+s2

使用index更多更强大的数据结构支持

很多强大的索引数据结构

  1. Caregoricalindex,基于分类数据的index,提升性能
  2. Multiindex,多维索引,用于groupby多维聚合后结果等
  3. Datetimeindex,时间类型索引,强大的日期和时间的方法支持

Pandas的Merge语法

pandas怎样实现DataFrame的Merge

pandas的Merge,相当于Sql的Join,将不同的表key关联到一个表

merge的语法:

pd.merge(left,right,how='inner',on=None,left_on=None,right_on=None,left_index=False,right_index=False,sort=True,suffixes=('_x','_y'),copy=True,indicator=False,validate=None)
  • left,right:要merge的dataframe或者有name的Series
  • how: join类型,’left’, ‘right’ , ‘outer’, ‘inner’
  • on: join的key,left和right都需要有这个key
  • left_on: left的df或者series的key
  • right_on: right的df或者seires的key
  • left_index,right_index:使用index而不是普通的column做join
  • suffixes:两个元素的后缀,如果列有重名,自动添加后缀,默认是(‘_X’,’_Y’)

本次实验提纲

  1. 电影数据集的join实例
  2. 理解merge时一对一、一对多、多对多的数量对齐关系
  3. 理解left join、right join、inner join、 outer join、的区别
  4. 如果出现非Key的字段重名怎么办