Matplotlib用法2
一、matplotlib柱状图
* 柱状图是一种用矩形柱来表示数据分类的图表
* 柱状图可以垂直绘制,也可以水平绘制
* 它的高度与其所表示的数值成正比关系
* 柱状图显示了不同类别之间的比较关系,图表的水平轴X指定被比较的类别,垂直轴Y则表示具体的类别值
柱状图的绘制:
matplotlib.pyplot.bar(x,height,width:float=0.8,bottom=None,*,align:str=‘center’,data=None,**kwargs)
- x表示x坐标,数据类型为float类型,一般为np.arange()生成的固定步长列表
- height表示柱状图的高度,也就是y坐标值,数据类型为float类型,一般为一个列表,包含生成柱状图的所有y值
- width表示柱状图的宽度,取值在0~1之间,默认值为0.8
- bottom表示柱状图的起始位置,也就是y轴的起始坐标,默认值为None
- align表示柱状图的中心位置,‘center’、‘lege’边缘,默认值为‘center’
- color 表示柱状图的颜色,默认为蓝色。可以设置多个颜色值
- facecolor : 柱状图的颜色,设置单个颜色值时的使用方式和color参数一样,但是facecolor不能设置多个颜色值
- alpha表示透明度,取值在0~1之间,默认值为1
- label标签,设置后需要调用plt.legend()生成
- edgecolor边框颜色(ec)
- linewidth 边框宽度,浮点数或类数组,默认为None(lw)
- tick_label :柱子的刻度标签,字符串或字符串列表,默认值为None
- linestyle :线条样式(ls)
1.1 基本柱状图绘制
import matplotlib.pyplot as plt
# x轴数据
x = range(5)
# y轴数据
data = [5,20,15,25,10]
# 设置图形标题
plt.title('基本柱状图')
# 绘制网格
plt.grid(ls='--',alpha=0.2,color='r') # alpha表示透明度,alpha参数的值越小,就越透明,当alpha=0时完全透明
# 设置字体
plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来设置字体样式以正常显示
plt.rcParams['axes.unicode_minus'] = False
# bar绘制图形,x表示x坐标,data表示柱状图的高度
plt.bar(x,data)
运行结果:
- 在绘图时设置柱状图的bottom参数:
# bar绘制图形,x表示x坐标,data表示柱状图的高度
# bottom参数表示柱状图的起始位置,也就是y轴的起始坐标,默认值为None
plt.bar(x,data,bottom=[10,20,5,0,10])
运行结果:
- 设置柱状图的颜色
- 使用facecolor——只能设置单个颜色值
- 使用color——可以设置多个颜色值
# bar绘制图形,x表示x坐标,data表示柱状图的高度
# facecolor参数设置柱状图的颜色,只能设置单个颜色值
plt.bar(x,data,facecolor='yellow')
运行结果:
# bar绘制图形,x表示x坐标,data表示柱状图的高度
# color参数设置柱状图的颜色,可以设置多个颜色值
plt.bar(x,data,color=['r','g','b','y'])
运行结果:
- 描边——相关的关键字参数为:
- edgecolor或ec
- linestyle 或 ls
- linewidth 或 lw
import matplotlib.pyplot as plt
# y轴数据
data = [5,20,15,25,10]
plt.title('设置边缘线条样式')
# 设置字体,正常显示中文
plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来设置字体样式以正常显示
plt.rcParams['axes.unicode_minus'] = False
plt.bar(range(len(data)),data,ec='r',ls='--',lw=2)
运行结果:
- 设置tick label
柱子的刻度标签,字符串或者字符串列表
import matplotlib.pyplot as plt
# x轴数据
x = range(5)
# y轴数据
data = [5,20,15,25,10]
# 设置柱子的刻度标签
labels = ['Tom','Dick','Harry','Slim','Jim']
plt.title('设置柱子的刻度标签')
# 设置字体,正常显示中文
plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来设置字体样式以正常显示
plt.rcParams['axes.unicode_minus'] = False
plt.bar(labels,data)
运行结果:
1.2 同位置多柱状图
同一x轴位置绘制多个柱状图,主要通过调整柱状图的宽度和每个柱状图x轴的起始位置。
分析:
- 本实例需要对x轴进行计算,因此需要将x轴转为数值
- 确定同一x轴中,每个柱状图x轴的起始位置
- 需要设置图形的宽度
- 图形2的起始位置=图形2起始位置+图形宽度
- 图形3的起始位置=图形3起始位置+2倍图形宽度
- 需要给每个柱状图循环显示文本内容
- 显示图例
- 在同一个图中绘制多个柱状图(没有设置位置)
import matplotlib.pyplot as plt
import numpy as np
# 设置基本属性
# 国家
countries = ['挪威','德国','中国','美国','瑞典']
# 金牌个数
gold_medal = [16,12,9,8,5]
# 银牌个数
silver_medal = [8,10,4,10,5]
# 铜牌个数
bronze_medal = [13,5,2,7,5]
# 设置字体,正常显示中文
plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来设置字体样式以正常显示
plt.rcParams['axes.unicode_minus'] = False
plt.bar(countries,gold_medal,color='gold',width=0.2) # 通过color设置柱状图的颜色,通过width参数设置柱状图的宽度
plt.bar(countries,silver_medal,color='silver',width=0.2)
plt.bar(countries,bronze_medal,color='c',width=0.2)
运行结果:
- 绘制同位置多柱状图
import matplotlib.pyplot as plt
import numpy as np
# 设置基本属性
# 国家
countries = ['挪威','德国','中国','美国','瑞典']
# 金牌个数
golden_medal = [16,12,9,8,5]
# 银牌个数
silver_medal = [8,10,4,10,5]
# 铜牌个数
bronze_medal = [13,5,2,7,5]
# 1.将x轴转换为数值
x = np.arange(len(countries))
print(x)
# 2.设置图形的宽度(柱形图每条柱子的宽度)
width = 0.2
# ===========确定x的起始位置======================
# 金牌起始位置
golden_x = x
# 银牌的起始位置
silver_x = x + width
# 铜牌的起始位置
bronze_x = x + 2 * width
# 设置字体,正常显示中文
plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来设置字体样式以正常显示
plt.rcParams['axes.unicode_minus'] = False
# =========分别绘制图形=====================
# 绘制金牌图形
plt.bar(golden_x,golden_medal,width=width,color='gold',label='金牌')
# 绘制银牌图形
plt.bar(silver_x,silver_medal,width=width,color='silver',label='银牌')
# 绘制铜牌图形
plt.bar(bronze_x,bronze_medal,width=width,color='brown',label='铜牌')
plt.legend() # 显示图例
# ==========将坐标变回来==========================
# 注意将x轴标签的位置居中
plt.xticks(x+width,labels=countries)
# ----------------------显示高度文本-------------------------
for i in range(len(countries)):
# 金牌的文本设置
# plt.text()中前两两个参数表示绘制文字的x坐标和y坐标,第2个参数表示要添加的文字,va参数表示垂直位置,ha表示水平位置
plt.text(golden_x[i],golden_medal[i],golden_medal[i],va='bottom',ha='center')
# 银牌的文本设置
plt.text(silver_x[i],silver_medal[i],silver_medal[i],va='bottom',ha='center')
# 铜牌的文本设置
plt.text(bronze_x[i],bronze_medal[i],bronze_medal[i],va='bottom',ha='center')
plt.show()
运行结果:
1.3 堆叠柱状图绘制
所谓堆叠柱状图就是将不同数组别的柱状图堆叠在一起,堆叠后的柱状图高度显示了两者相加的结果值。
分析:
- 金牌榜的起始高度为:铜牌数据+银牌数据
- 银牌榜的起始高度为:铜牌数据
- 铜牌榜的其实高度为:0
- 起始位置的数据相加需要使用numpy的相关知识
- 需要确定柱状图的位置
- 显示图例
import matplotlib.pyplot as plt
import numpy as np
# 设置基本属性
# 国家
countries = ['挪威','德国','中国','美国','瑞典']
# 金牌个数
golden_medal = [16,12,9,8,5]
# 银牌个数
silver_medal = [8,10,4,10,5]
# 铜牌个数
bronze_medal = [13,5,2,7,5]
# 设置图形的宽度(柱形图每条柱子的宽度)
width = 0.3
# ===========确定y的起始高度======================
# 将列表转换为numpy数组,再用numpy数组的性质进行两数组相加
# 铜牌的起始高度
bronze_y = np.array(bronze_medal)
# 银牌榜的起始高度
silver_y = bronze_y + np.array(silver_medal)
# 金牌榜的起始高度
golden_y = silver_y + np.array(gold_medal)
# 每个国家总的奖牌数
medal_sum = golden_y
# 设置字体,正常显示中文
plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来设置字体样式以正常显示
plt.rcParams['axes.unicode_minus'] = False
# =========分别绘制图形=====================
# 绘制金牌图形
plt.bar(countries,golden_y,width=width,color='gold',label='金牌')
# 绘制银牌图形
plt.bar(countries,silver_y,width=width,color='silver',label='银牌')
# 绘制铜牌图形
plt.bar(countries,bronze_y,width=width,color='brown',label='铜牌')
plt.legend() # 显示图例
# # ----------------------显示高度文本-------------------------
for i in range(len(countries)):
# 奖牌总数的文本设置
# plt.text()中前两两个参数表示绘制文字的x坐标和y坐标,第2个参数表示要添加的文字,va参数表示垂直位置,ha表示水平位置
plt.text(countries[i],medal_sum[i],medal_sum[i],va='bottom',ha='center')
plt.show()
或者使用plt.bar()函数中的bottom参数设置柱子的起始高度:
import matplotlib.pyplot as plt
import numpy as np
# 设置基本属性
# 国家
countries = ['挪威','德国','中国','美国','瑞典']
# 金牌个数
golden_medal = [16,12,9,8,5]
# 银牌个数
silver_medal = [8,10,4,10,5]
# 铜牌个数
bronze_medal = [13,5,2,7,5]
# 设置图形的宽度(柱形图每条柱子的宽度)
width = 0.3
# 设置字体,正常显示中文
plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来设置字体样式以正常显示
plt.rcParams['axes.unicode_minus'] = False
# =========分别绘制图形=====================
# 通过bar()函数的bottom参数设置柱子的起始高度
# 绘制铜牌图形
plt.bar(countries,bronze_medal,width=width,color='brown',label='铜牌') # 铜牌柱子的起始高度为0,是bottom参数的默认值
# 绘制银牌图形
plt.bar(countries,silver_medal,width=width,color='silver',label='银牌',bottom = bronze_medal)
# 绘制金牌图形
plt.bar(countries,golden_medal,width=width,color='gold',label='金牌',bottom = np.array(bronze_medal) + np.array(silver_medal))
plt.legend() # 显示图例
# # ----------------------显示高度文本-------------------------
nums = []
for i in range(len(countries)):
medal_sum = bronze_medal[i] + silver_medal[i] + gold_medal[i]
nums.append(medal_sum)
# 奖牌总数的文本设置
# plt.text()中前两两个参数表示绘制文字的x坐标和y坐标,第2个参数表示要添加的文字,va参数表示垂直位置,ha表示水平位置
plt.text(countries[i],medal_sum,medal_sum,va='bottom',ha='center')
print(nums)
plt.show()
运行结果:
1.4 水平柱状图
调用matplotlib的barh()函数可以生成水平柱状图
barh()函数的用法与bar()函数的用法基本一样,只是在调用barh()函数时使用y参数传入Y轴数据,使用width参数传入代表条柱宽度的数据。
plt.barh(y,width,height=0.8,left=None,*,align=‘center’,**kwargs)
import matplotlib.pyplot as plt
import numpy as np
# 设置字体,正常显示中文
plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来设置字体样式以正常显示
plt.rcParams['axes.unicode_minus'] = False # 中文负号
# 设置分辨率为100
plt.rcParams['figure.dpi'] = 100
# 设置画布的大小
plt.rcParams['figure.figsize'] = (5,3)
# 国家
countries = ['挪威','德国','中国','美国','瑞典']
# 金牌个数
golden_medal = [16,12,9,8,5]
# # 银牌个数
# silver_medal = [8,10,4,10,5]
# # 铜牌个数
# bronze_medal = [13,5,2,7,5]
# y轴为国家,宽度为奖牌数
plt.barh(countries,width=golden_medal)
plt.show()
运行结果:
实例:三天中3部电影的票房变化
movie = [‘新蝙蝠侠’,‘狙击手’,‘奇迹笨小孩’]
real_day1 = [4053,2548,1543]
real_day2 = [7840,4013,2421]
real_day3 = [8080,3673,1342]
分析:
-
1.确定图形距离左侧的位置
-
2.设置同一高度
-
3.绘制图形设置left参数
-
4.标注数据——plt.text()
- horizontalalignment控制文本的x位置参数表示文本边界框的左边、中间或者右边——ha
- verticalalignment控制文本的y位置参数,表示文本边界框的底部、中心或者顶部——va
-
绘制水平堆叠柱状图
代码如下:
import matplotlib.pyplot as plt
import numpy as np
movie = ['新蝙蝠侠','狙击手','奇迹笨小孩']
real_day1 = [4053,2548,1543] # 第一天
real_day2 = [7840,4013,2421] # 第二天
real_day3 = [8080,3673,1342] # 第三天
# ========================确定左侧距离=============================
left_day1 = 0
left_day2 = np.array(real_day1) # 第二天距离左侧的距离为第一天的数值
left_day3 = left_day2 + np.array(real_day2) # 第三天距离左侧的距离为第一天+第二天的数值
# 设置柱子的高度
height = 0.2
# 绘制图形
plt.barh(movie,real_day1,left=left_day1,height=height) # 第一天图形
plt.barh(movie,real_day2,left=left_day2,height=height) # 第二天图形
plt.barh(movie,real_day3,left=left_day3,height=height) # 第三天图形
# 设置数值文本:计算宽度值和y轴为值
sum_data = np.array(real_day1) + np.array(real_day2) + np.array(real_day3)
for i in range(len(movie)):
plt.text(sum_data[i],movie[i],sum_data[i],va='center',ha='left')
plt.xlim(0,sum_data.max()+2000)
运行结果:
- 为每一个堆叠的柱子添加文本数值:
import matplotlib.pyplot as plt
import numpy as np
movie = ['新蝙蝠侠','狙击手','奇迹笨小孩']
real_day1 = [4053,2548,1543] # 第一天
real_day2 = [7840,4013,2421] # 第二天
real_day3 = [8080,3673,1342] # 第三天
# ========================确定左侧距离=============================
left_day1 = np.array([0,0,0],dtype=np.uint8)
left_day2 = np.array(real_day1) # 第二天距离左侧的距离为第一天的数值
left_day3 = left_day2 + np.array(real_day2) # 第三天距离左侧的距离为第一天+第二天的数值
# 设置线条的高度
height = 0.2
# 绘制图形
plt.barh(movie,real_day1,left=left_day1,height=height) # 第一天图形
for i in range(len(movie)):
plt.text(left_day1[i],movie[i],real_day1[i],size=8,va='center',ha='left')
plt.barh(movie,real_day2,left=left_day2,height=height) # 第二天图形
for i in range(len(movie)):
plt.text(left_day2[i],movie[i],real_day2[i],size=8,va='center',ha='left')
plt.barh(movie,real_day3,left=left_day3,height=height) # 第三天图形
for i in range(len(movie)):
plt.text(left_day3[i],movie[i],real_day3[i],size=8,va='center',ha='left')
plt.xlim(0,sum_data.max()+2000)
运行结果:
- 使用for循环进行绘图:
import matplotlib.pyplot as plt
import numpy as np
movie = ['新蝙蝠侠','狙击手','奇迹笨小孩']
real_day1 = [4053,2548,1543] # 第一天
real_day2 = [7840,4013,2421] # 第二天
real_day3 = [8080,3673,1342] # 第三天
real_days = [real_day1,real_day2,real_day3]
# ========================确定左侧距离=============================
left_day1 = np.array([0,0,0],dtype=np.uint8)
left_day2 = np.array(real_day1) # 第二天距离左侧的距离为第一天的数值
left_day3 = left_day2 + np.array(real_day2) # 第三天距离左侧的距离为第一天+第二天的数值
left_days = np.array([left_day1,left_day2,left_day3])
# 设置线条的高度
height = 0.2
# 绘制图形
for j in range(len(movie)):
plt.barh(movie,real_days[j],left=left_days[j],height=height)
for i in range(len(movie)):
plt.text(left_days[j][i],movie[i],real_days[j][i],size=8,va='center',ha='left') # 使用size参数设置字体大小
# plt.barh(movie,real_day1,left=left_day1,height=height) # 第一天图形
# for i in range(len(movie)):
# plt.text(left_day1[i],movie[i],real_day1[i],va='center',ha='left')
# plt.barh(movie,real_day2,left=left_day2,height=height) # 第二天图形
# for i in range(len(movie)):
# plt.text(left_day2[i],movie[i],real_day2[i],va='center',ha='left')
# plt.barh(movie,real_day3,left=left_day3,height=height) # 第三天图形
# for i in range(len(movie)):
# plt.text(left_day3[i],movie[i],real_day3[i],va='center',ha='left')
# 设置数值文本(总数量):计算宽度值和y轴为值
sum_data = np.array(real_day1) + np.array(real_day2) + np.array(real_day3)
for i in range(len(movie)):
plt.text(sum_data[i],movie[i],sum_data[i],size=8,va='center',ha='left') # 使用size参数设置字体大小
plt.xlim(0,sum_data.max()+2000)
运行结果:
- 绘制同位置多柱状图
import matplotlib.pyplot as plt
import numpy as np
movie = ['新蝙蝠侠','狙击手','奇迹笨小孩']
real_day1 = [4053,2548,1543] # 第一天
real_day2 = [7840,4013,2421] # 第二天
real_day3 = [8080,3673,1342] # 第三天
real_days = [real_day1,real_day2,real_day3]
# 设置字体,正常显示中文
plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来设置字体样式以正常显示
plt.rcParams['axes.unicode_minus'] = False
#-------1.将y轴转换为数值型------------------------------
movie_y = np.arange(len(movie))
# ------2.设置同图形的高度-------------------------------
height = 0.2
# ------3.计算每个图形高度的起始位置----------------------
height_day1 = movie_y
height_day2 = height_day1 + height
height_day3 = height_day2 + height
height_days = [height_day1,height_day2,height_day3]
# ------4.绘制图形--------------------------------------
for i in range(len(movie)):
plt.barh(height_days[i],real_days[i],height=height)
# 给每一个柱子添加文本数值
for j in range(len(real_day1)):
# 第一参数表示文本的x轴坐标,第二个参数表示文本的y轴坐标,第三个参数表示文本数值
plt.text(real_days[i][j],height_days[i][j],real_days[i][j],size=8,ha='left',va='center')
#-------5.替换y轴并将将y轴标签居中---------------------
plt.yticks(movie_y + height , labels=movie) # 第一个参数用来设置y轴上的刻度值,label用来设置对应刻度值的标签
运行结果:
绘图发现,右边文本数值超出边框,有两个方法可以解决:1、去掉右边和上侧的spines;2、使用xlim设置x轴的显示范围。
# 1、去掉右边和上侧的spines
ax = plt.gca()
ax.spines['right'].set_color('none')
ax.spines['top'].set_color('none')
运行结果:
# 2、使用xlim设置x轴的显示范围
plt.xlim(0,np.array(real_days).max()+2000)
运行结果:
二、matplotlib直方图
直方图(Histogram),又称为质量分布图,它是条形图的一种,由一系列不等高的纵向线来表示数据分布情况。直方图的横轴表示数据类型,纵轴表示分布情况。
柱状图和直方图的区别在于,直方图用于概率分布,它显示了一组数值序列在给定的数值范围内出现的概率;而柱状图则用于展示各个类别的频数。
柱状图 | 直方图 |
---|---|
柱状图一般用于描述离散型分类数据的对比 | 直方图一般用于描述连续型数据的分布关系 |
每根柱子宽度固定,柱子之间会有间距 | 每根柱子宽度可以不一样,且一般没有间距 |
横轴变量可以任意排序 | 横轴变量有一定顺序规则 |
将统计值的范围分段,即将整个值的范围分为一系列间隔,然后计算每个间隔有多少个值。直方图也可以被归一化以显示“相对频率”。然后,它显示了属于几个类别中每个类别的占比,其高度总和等于1。
plt.hist(x,bins=None,range=None,density=None,weights=None,cumulative=False,bottom=None,histtype=‘bar’,align=‘mid’,orientation=‘vertical’,rwidth=None,log=False,color=None,label=None,stacked=False,normed=None,*,data=None,**kwargs)
参数说明:
- x:绘制直方图所用的数据,必须是一维数组;多维数组可以先进行扁平化(numpy.ravel())再作图;必选参数。
- bins:直方图的柱数,即要分的组数,默认为10。
- weights:与x形状相同的权重数组,将x中的每个元素乘以对应权重值再计数;如果normed或者density取值为True,则会对权重进行归一化处理。这个参数可用于绘制已合并数据的直方图。
- density:bool,可选。如果为“True”,返回元组的第一个元素将会将计数标准化以形成一个概率密度,也就是说,直方图下的面积(或积分)总和为1.这是通过将计数除以数字的数量来实现的。如果叠加也是“True”,那么柱状图被规范化为1。(替代normed)
- bottom:数组、标量值或None;每个柱子底部相对于y=0的位置。如果是标量值,则每个柱子相对于y=0向上/向下的偏移量相同。如果是数组,则根据数组元素取值移动对应的柱子,即直方图上下偏移距离。
- histtype:{‘bar’,‘barstacked’,‘step’,‘stepfilled’};‘bar’是传统的直方图;'barstacked’是堆叠的条形直方图;'step’是未填充的条形直方图;‘stepfilled’是有填充的直方图。当histtype取值为’step’或’stepfilled’,rwidth设置失效,即不能指定柱子之间的间隔,默认连接在一起。
- align:{‘left’,‘mid’,‘right’}。‘left’:柱子的中心位于bins的左边缘;‘mid’:柱子位于bins左右边缘之间;‘right’:柱子的中心位于bins的右边缘。
- color:具体颜色,数组(元素为颜色)或None。
- label:字符串(序列)或None;有多个数据集时,用label参数做标注区分。
- normed:是否将得到的直方图向量归一化,即显示占比,默认为0他,不归一化;不推荐使用,建议改用density参数。
- alpha:透明度。
返回值说明:
- n:数组或数组列表
- 直方图的值
- bins:数组
- 返回各个bin的区间范围
- patches:列表或者嵌套列表,返回的每个bin里面包含的数据是一个list
2.1 绘制一个直方图:
# 使用numpy随机生成200个数据
x_value = np.random.randint(120,180,300)
# 绘制直方图
plt.hist(x_value,bins=20,edgecolor='red')
plt.title('数据统计')
plt.xlabel('身高')
plt.ylabel('比率')
运行结果:
返回值:
num,bins,patches = plt.hist(x_value,bins=20,edgecolor='red')
print('num:',num)
print('bins:',bins)
for patche in patches:
print(patche)
运行结果:
取patches每个数组元素中的元素:
for p in patches:
print(p)
print(p.get_x()) # 取柱子左下角的横坐标
print(p.get_y()) # 取柱子左下角的纵坐标
print(p.get_width()) # 取柱子的宽度
print(p.get_height()) # 取柱子的高度
print(p.get_angle()) # 取柱子的角度
运行结果:
2.2 添加折线直方图
在直方图中,我们也可以添加折线图,辅助我们查看数据变化情况
- 首先通过pyplot.subplot()创建Axes对象
- 通过Axes对象调用hist()方法绘制直方图,返回折线图所需要的x、y数据
import matplotlib.pyplot as plt
x_value = np.random.randint(120,180,300)
# 创建一个画布
fig,ax = plt.subplots()
# 绘制直方图
num,bins_limit,pat = plt.hist(x_value,bins=10,edgecolor='white')
# 注意num返回的个数是10,bins_limit返回的个数是11,需要截取
print(bins_limit[:10])
# 绘制折线图
ax.plot(bins_limit[:10],num,'--',marker='o')
运行结果:
2.3 不等距分组
一般的直方图都是等距的,但有时我们需要得到不等距的直方图,这个时候需要确定分组上下限,并指定histtype='bar’就可以了。
fig,ax = plt.subplots()
x = np.random.normal(100,20,100) # np.random.normal表示标准正态分布,均值=100,标准差=20,随机生成100个值
# 区间是:50-60,60-70,70-90,90-100,100-110,110-140,140-150
bins = [50,60,70,90,100,110,140,150] # 设置区间,区间数-1=直方图柱子数
ax.hist(x,bins,color='g',rwidth=0.9,edgecolor='white')
ax.set_title('不等距分组')
plt.show()
运行结果:
2.4 多类型直方图
我们在使用直方图查看数据的频率时,有时候会查看多种类型数据出现的频率。
这时候我们可以以列表的形式传入多种数据给hist()方法的x数据。
# 指定分组个数
n_bins = 10
fig,ax = plt.subplots(figsize=(8,5))
# 分别生成10000,5000,2000个值
x_multi = [np.random.randn(n) for n in [10000,5000,2000]] # 列表表达式,生成的x_multi是一个三维数组
print(x_multi)
# 实际绘图代码与单类型直方图差异不大,只是增加了一个图例项
# 在 ax.hist函数中先指定图例label名称
ax.hist(x_multi,n_bins,histtype='bar',label=list('ABC'))
ax.set_title('多类型直方图')
ax.legend()
运行结果:
2.5 堆叠直方图
我们有时候会在同样数据范围情况下,对比两组不同对象群组收集的数据差异。
- 直方图属性data:以列表的形式传入两组数据
- 设置直方图stacked:为True时,允许数据覆盖
x_value = np.random.randint(140,180,200)
x2_value = np.random.randint(140,180,200)
plt.hist([x_value,x2_value],bins=10,stacked=True)
运行结果:
三、matplotlib饼状图
饼状图是用来显示一个数据系列,具体来说,饼状图显示一个数据系列中各项目占项目总和的百分比。
Matplotlib提供了一个pie()函数,该函数可以生成数组中数据的饼状图。可以使用x/sum(x)来计算各个扇形区域占饼状图总和的百分比。pie()函数的参数说明如下:
pyplot.pie(x,explode=None,labels=None,colors=None,autopct=None)
- x:数组序列,数组元素对应扇形区域的数量大小
- labels:列表字符串序列,为每个扇形区域备注一个标签名字
- colors:为每个扇形区域设置颜色,默认按照颜色周期自动设置
- autopct:格式化字符串"fmt%pct",使用百分比的格式设置每个扇形区域的标签
- pctdistance:设置百分比标签与圆心的距离
- labeldistance:设置各扇形标签(图例)与圆心的距离
- explode:指定饼状图某些部分的突出显示,即呈现爆炸式
- shadow:是否添加饼状图的阴影效果
绘制饼图:
# 设置大小
plt.rcParams['figure.figsize'] = (5,5)
# 定义饼图的标签
labels = ['娱乐','育儿','饮食','房贷','交通','其他']
# 每个标签所占的数量
x = [200,500,1200,7000,200,900]
# 绘制饼图
# plt.pie(x,labels=labels,colors=['#FFDAB9','#FFE4E1','#00BFFF','#7FFFD4','#FFEC8B','#D8BFD8'],autopct='fmt%pct')
plt.pie(x,labels=labels)
运行结果:
百分比显示
autopct
# 设置大小
plt.rcParams['figure.figsize'] = (5,5)
# 定义饼图的标签
labels = ['娱乐','育儿','饮食','房贷','交通','其他']
# 每个标签所占的数量
x = [200,500,1200,7000,200,900]
# 绘制饼图
plt.pie(x,labels=labels,autopct='%.2f%%') # autopct中字符串的首尾为%,中间的.2f%表示百分比保留小数点后两位
运行结果:
饼状图的分离
explode:指定饼状图某些部分的突出显示
# 设置大小
plt.rcParams['figure.figsize'] = (5,5)
# 定义饼图的标签
labels = ['娱乐','育儿','饮食','房贷','交通','其他']
# 每个标签所占的数量
x = [200,500,1200,7000,200,900]
# 饼图分离
explode = (0.03,0.05,0.06,0.04,0.08,0.01) # explode中的元素就代表饼图的对应部分距离圆心的距离
# 绘制饼图
plt.pie(x,labels=labels,explode=explode)
运行结果:
设置饼状图百分比和文本距离中心的距离
- pctdistance:设置百分比标签与圆心的距离
- labeldistance:设置各扇形标签(图例)与圆心的距离
# 设置大小
plt.rcParams['figure.figsize'] = (5,5)
# 定义饼图的标签
labels = ['娱乐','育儿','饮食','房贷','交通','其他']
# 每个标签所占的数量
x = [200,500,1200,7000,200,900]
# 饼图分离
explode = (0.03,0.05,0.06,0.04,0.08,0.01) # explode中的元素就代表饼图的对应部分距离圆心的距离
# 绘制饼图
plt.pie(x,labels=labels,autopct='%.2f%%',explode=explode,pctdistance=1.2,labeldistance=1.4)
运行结果:
四、matplotlib散点图
散点图scatter,散点图也叫X-Y图,它将所有的数据以点的形式展现在直角坐标系上,以显示变量之间相互的影响程度,点的位置由变量的数值决定。
通过观察散点图上点的分布情况,我们可以推断出变量间的相关性。如果变量之间不存在相互关系,那么在散点图上就会表现为随机分布的离散的点,如果存在某种相关性,那么大部分的数据点就会相对密集并以某种趋势呈现。
数据的相关关系主要分为:正相关(两个变量值同时增长)、负相关(一个变量值增加另一个变量值下降)、不相关、线性相关、指数相关等,表现在散点图上的大致分布如下图所示。那些离点集群较远的点我们称为离群点或者异常点。
matplotlib.pyplot.scatter(x,y,s=None,c=None,marker=None,cmap=None,norm=None,vmin=None,vmax=None,alpha=None,linewidths=None,edgecolors=None,plotnonfinite=False,data=None,**kwargs)
- x,y:散点的坐标
- s:散点的面积
- c:散点的颜色(默认值为蓝色,‘b’)
- marker:散点的样式(默认值为实心圆,‘o’)
- alpha:散点透明度([0,1]之间的数,0表示完全透明,1则表示完全不透明)
- linewidths:散点的边缘线宽
- edgecolors:散点的边缘颜色
- cmap:colormap,默认为None,标量或者是一个colormap的名字,只有c是一个浮点数数组时才使用。
以下实例scatter()函数接收长度相同的数组参数,一个是x轴的值,另一个是y轴的值。
# x轴数据
x = np.array([1,2,3,4,5,6,7,8])
# y轴数据
y = np.array([1,4,7,20,7,15,33,25])
# 绘制散点图
plt.scatter(x,y)
plt.show()
运行结果:
- 设置散点图中点的面积
# x轴数据
x = np.array([1,2,3,4,5,6,7,8])
# y轴数据
y = np.array([1,4,7,20,7,15,33,25])
# 生成一个[0,1)之间的随机浮点数或N维浮点数组作为点的面积
s = (20*np.random.rand(8))**2
# 绘制散点图
plt.scatter(x,y,s)
plt.show()
运行结果:
- 设置散点图的颜色和透明度
颜色方式:
- 1.颜色英文
- 2.字母 ‘r’ ‘g’ ‘b’ 等
- 3.十六进制 #123ab1
# x轴数据
x = np.random.rand(50) # 随机生成一维数组,其中有50个数
# y轴数据
y = np.random.rand(50)
# 生成一个[0,1)之间的随机浮点数或N维浮点数组
s = (10*np.random.rand(50))**2
# 颜色也可以使用一组数字序列
# 设置随机颜色
colors = np.random.rand(50)
# 绘制散点图
plt.scatter(x,y,s,alpha=0.5,c=colors)
plt.show()
运行结果:
- 可以选择不同的颜色条–配合cmap参数
颜色条 colormap
matplotlib模块提供了很多可用的颜色条,颜色条就像一个颜色列表,其中每一种颜色都有一个范围从0-100的值。下面是颜色条的例子:viridis。
# x轴数据
x = np.arange(1,101)
y = np.arange(1,101)
# 颜色随机
colors = np.arange(1,101)
plt.scatter(x,y,c=colors,cmap='viridis')
运行结果:
cmap主要分为以下四大类:
-
1.Sequential colormaps:连续化色图
- 特点:在两种色调之间近似平滑变化,通常是从低饱和度(白色)到高饱和度(例如明亮的蓝色)
- 应用:适用于大多数科学数据,可以直观地看出数据从低到高的变化
- 1) 以中间值有颜色命名(eg:viridis松石绿):[‘viridis’,‘plasma’,‘inferno’,‘magma’,‘cividis’]
- 2)以色系名称命名,由低饱和度到高饱和度过渡
-
2.Diverging colormaps:两端发散的色图
- 特点:具有中间值(通常是浅色),并在高值和低值处平滑变化为两种不同的色调
- 应用:适用于数据的中间值的很大情况(例如0,因此正值和负值分别表示为颜色图的不同颜色)
[‘PiYG’,‘PRGn’,‘BrBG’,‘PuOr’,‘RdGy’,‘RdBu’,‘RdYIBu’,‘RdYIGn’,‘Spectral’,‘coolwarm’,‘bwr’,‘seismic’]
-
3.Qualitative colormap:离散化色图
-
4…Cyclic colormaps:周期图
五、matplotlib保存图片
保存图片 plplot.savefig()
savefig(fname,dpi=None,facecolor=‘w’,edgecolor=‘w’,orientation=‘portrait’,papertype=None,format=None,transparent=False,bbox_inches=None,pad_inches=0.1,frameon=None,metadata=None)
- frame:(字符串或者仿路径或仿文件)如果格式已经设置,这就决定输出的格式并将文件按fname来保存。如果格式没有设置,在fname有扩展名的情况下推断按此保存,没有扩展名将按照默认格式存储为’png’格式,并将适当的扩展名添加在fname后面。文件夹必须存在。
- dpi:分辨率,每英寸的像素点数
- facecolor:图形表面颜色,默认值为‘auto’。如果是‘auto’,使用当前图形的表面颜色;否则,使用设置的颜色
- edgecolor:图形边缘颜色,默认值为‘auto’。如果是‘auto’,使用当前图形的边缘颜色;否则,使用设置的颜色
- format(字符串):文件格式,比如’jpg’、‘png’、‘pdf’、‘svg’、‘gif’等,未设置的行为将会被记录在fname中
- transparent:用于将图片背景设置为透明。图形也会是透明,除非通过关键字参数指定了表面颜色或边缘颜色
# x轴数据
x_axis = [1,4,9,16,25,36,49,64,81,100]
# y轴数据
y_axis = [1,2,3,4,5,6,7,8,9,10]
# 绘制图形
plt.plot(x_axis,y_axis)
# x轴和y轴标签
plt.xlabel('X')
plt.ylabel('Y')
plt.savefig('mytest.png')
plt.show()
运行结果:
注意:savefig()中第一个参数是保存的路径,如果路径中包含未创建的文件夹,需要手动或者使用os模块创建。必须在调用plt.show()之前保存图片,否则将保存的是空白图形。
使用os模块判断文件夹是否存在,不存在则创建文件夹:
import os
import matplotlib.pyplot as plt
# x轴数据
x_axis = [1,4,9,16,25,36,49,64,81,100]
# y轴数据
y_axis = [1,2,3,4,5,6,7,8,9,10]
# 绘制图形
plt.plot(x_axis,y_axis)
# x轴和y轴标签
plt.xlabel('X')
plt.ylabel('Y')
# 使用os目录判断文件夹是否存在:
if not os.path.exists('mypic'):
# 使用os模块创建文件夹
os.mkdir('mypic')
plt.savefig('mypic/mytest.png')
plt.show()
六、箱线图
箱线图(Boxplot)是一种用作显示一组数据分散情况的统计图表。
箱线图,又称为箱型图(boxplot)或盒式图,不同于一般的折线图、柱状图或饼图等图表,其包含一些统计学的均值、分位数、极值
等统计量,该图信息量较大,不仅能够分析不同类别数据平均水平差异,还能揭示数据间的离散程度、异常值、分布差异
等。
在箱线图中,我们从上四分位数到下四分位数绘制一个盒子,然后用一条垂直触须(也称为‘盒须’)穿过盒子的中间。上垂线延伸至上边缘(最大值),下垂先延伸至下边缘(最小值)。
箱线图的应用场景:
- 箱线图由于能显示一组数据的分散情况,常用于品质管理
- 箱线图有利于数据清洗,能快速直到数据分布情况
- 箱线图有助于分析一组数据的偏向,如分析公司员工收入水平
函数的使用:
matplotlib.pyplot.boxplot(x,notch=None,sym=None,vert=None,whis=None,positions=None,widths=None,patch_artist=None,bootstrap=None,usermedians=NOne,conf_intervals=None,meanline=None,showmeans=None,showcaps=None,showbox=None,showfliers=None,boxprops=None,labels=None,3flierprops=None,medianprops=None,meanprops=None,capprops=None,whiskerprops=None,manage_ticks=True,autorange=False,zorder=None,*,data=None)
- x:输入数据,类型为数组或向量序列,必选参数。
- notch:控制箱体中央是否有V型凹槽。当取值为True时,箱体中央有V型凹槽,凹槽表示中位数的置信区间;取值为False时,箱体为矩形。类型为布尔值,默认值为False。是可选参数。
- vert:箱体的方向,当取值为True时,绘制垂直箱体,当取值为False时,绘制水平箱体。类型为布尔值,默认为True。类型为序列,可选参数。
- positions:指定箱体的位置,刻度和极值会自动匹配箱体的位置。类型为类数组结构。可选参数。默认值为range(1,N+1),N为箱线图的个数
- widths:箱体的宽度。类型为浮点数或类数组结构,默认值为0.5或0.15极值间的距离
- labels:每个数据集的标签,默认值为‘None’。类型为序列,可选参数。
- autorange:类型为波尔只,默认值为False,可选参数。当取值为True且数据分布满足上四分位数(75%)和下四分位数(25%)相等
- showmeans:是否显示算术平均值,类型为布尔值。默认值为False,可选参数。
- meanline:均值显示为线还是点,类型为布尔值,默认值为False,可选参数。当取值为True,且showmeans、shownotched参数均为True时,显示为线
- capprops:箱须横杠的样式,类型为字典,默认值为None,可选参数
- boxprops:箱体的样式,类型为字典,默认值为None,可选参数。
- whiskerprops:箱须的样式,类型为字典,默认值为None,可选参数
- flierprops:离群点的样式,类型为字典,默认值为None,可选参数
- medianprops:中位数的样式,类型为字典,默认值为None,可选参数
- meanprops:算术平均值的样式,类型为字典,默认值为None,可选参数
绘制箱线图:
import numpy as np
x = np.random.rand(20)
plt.boxplot(x,showmeans=True,meanline=True)
plt.grid()
plt.show()
运行结果:
七、wordcloud词云图和jieba分词
7.1 wordcloud词云图
词云图,也叫文字云,是对文本中出现频率较高的“关键词”予以视觉化的展现,词云图过滤掉大量的低频低质的文本信息。
WordCloud:
WordCloud是一款python环境下的词云图工具包,同时支持python2和python3,能通过代码的形式把关键词数据转换成直观且有趣的图文模式。
安装方法:pip install wordcloud 或者 conda install -c conda-forge wordcloud
WordCloud( font_path=None,width=400, height=200,margin=2, ranks_only=None,prefer_horizontal=0.9,mask=None, scale=1,color_func=None, max_words=200,min_font_size=4,stopwords=None,random_state=None, background_color=‘black’,max_font_size=None,font_step=1,mode=‘RGB’,relative_scaling=‘auto’,regexp=None,collocations=True,colormap=None,normalize_plurals=True,contour_width=0, contour_color=‘black’,repeat=False,include_numbers=False,min_word_length=0,collocation_threshold=30,)
WordCloud参数说明:
属性 | 数据类型/默认值 | 解析 |
---|---|---|
font_path | string | 字体路径windows:C:/Windows/Fonts / Linux: /usr/share/fonts |
width | int (default=400) | 输出的画布宽度,默认为400像素 |
height | int (default=200) | 输出的画布高度,默认为200像素 |
prefer_horizontal | float (default=0.90) | 词语水平方向排版出现的频率,默认 0.9 所以词语垂直方向排版出现频率为0.1 |
mask | nd-array or None(default=None) | 如果参数为空,则使用二维遮罩绘制词云如果mask非空,设置的宽高值将被忽略遮罩形状被 mask 取代 |
scale | float (default=1) | 按照比例进行放大画布,如设置为1.5,则长和宽都是原来画布的1.5倍 |
min_font_size | int (default=4) | 显示的最小的字体大小 |
font_step | int (default=1) | 字体步长,如果步长大于1,会加快运算但是可能导致结果出现较大的误差 |
max_words | number (default=200) | 要显示的词的最大个数 |
stopwords | set of strings or None | 设置需要屏蔽的词,如果为空,则使用内置的STOPWORDS |
background_color | color value default=”black” | 背景颜色,默认为黑色 |
max_font_size | int or Nonedefault=None | 显示的最大的字体大小 |
mode | string (default=”RGB”) | 当参数为“RGBA”并且background_color不为空时,背景为透明 |
relative_scaling | float (default=.5) | 词频和字体大小的关联性 |
color_func | callable, default=None | 生成新颜色的函数,如果为空,则使用 self.color_func |
regexp | string or None (optional) | 使用正则表达式分隔输入的文本 |
collocations | bool, default=True | 是否包括两个词的搭配 |
colormap | string or matplotlib colormapdefault=”viridis” | 给每个单词随机分配颜色,若指定color_func,则忽略该方法 |
random_state | int or None | 为每个单词返回一个PIL颜色 |
绘制词云图:
from wordcloud import WordCloud
with open('data.txt',encoding='utf-8') as file:
# 数据文件
txt = file.read()
# 如果数据文件中含有中文的话,font_path必须制定字体,否则中文会乱码
# collocations:是否包括两个词的搭配,默认为True,如果为True,会有重复数据
# width 幕布的宽度
# height 幕布的高度
# max_words 要显示的词的最大个数
# generate 读取文本文件
# 实例化词云图对象
wordcloud = WordCloud(font_path='C:/Windows/Fonts/simfang.ttf',collocations=False,background_color='white',width=800,height=600,max_words=50).generate(txt) # simfang.ttf是仿宋字体
# 生成图片
image = wordcloud.to_image()
# 展示图片
image.show()
# 保存文件
wordcloud.to_file('tag.jpg')
运行结果:
7.2 jieba分词
jieba分词:
pip install jieba
jieba分词的特点——支持三种分词模式:
- 精确模式:试图将句子最精确地切开,适合文本分析
- 全模式:把句子中所有的可以成词的词语都扫描出来,速度非常快,但是不能解决歧义
- 搜索引擎模式:在精确模式的基础上,对长词再次切分,提高召回率,适合用于搜索引擎分词。
- 支持繁体分词
- 支持自定义词典
jieba库的三种方法:
- jieba.cut方法接受三个输入参数:需要分词的字符串;cut_all参数用来控制是否采用全模式;HMM参数用来控制是否使用HMM(隐马尔可夫)模型。
- jieba.cut_for_search方法接受两个参数:需要分词的字符串;是否使用HMM模型。该方法适合用于搜索引擎构建倒排序索引的分词,粒度比较细,待分词的字符串可以是unicode或UTF-8字符串、GBK字符串。注意:不建议直接输入GBK字符串,可能无法预料地错误解码成UTF-8。
- jieba.cut以及jieba.cut_for_search返回的结构都是一个可迭代的generator,可以使用for循环来获取分词后得到的每一个词语(unicode),或者用 =jieba.lcut以及jieba.lcut_for_search直接返回list。
使用jieba库进行分词:
import jieba
seg_list = jieba.cut('我来到北京清华大学',cut_all=True)
print('Full Mode'+' '.join(seg_list)) # 全模式
seg_list = jieba.cut('我来到北京清华大学',cut_all=False)
print('Default Mode'+' '.join(seg_list)) # 精确模式
seg_list = jieba.cut('小明硕士毕业于中国科学院计算所,后在日本京都大学深造') # 默认模式
print(' '.join(seg_list)) # 精确模式
seg_list = jieba.cut_for_search('小明硕士毕业于中国科学院计算所,后在日本京都大学深造')
print(' '.join(seg_list)) # 精确模式
运行结果:
实例:先使用jieba库对文本进行分词,再使用WordCloud绘制词云图。
from wordcloud import WordCloud
import jieba
with open('data_zh.txt',encoding='utf-8') as file:
# 数据文件
txt = file.read()
txt_list = jieba.cut(txt,cut_all=False) # 返回的是一个列表对象
# 进行字符串拼接,用空格分隔切割好的词
txt_str = ' '.join(txt_list)
# 如果数据文件中含有中文的话,font_path必须制定字体,否则中文会乱码
# collocations:是否包括两个词的搭配,默认为True,如果为True,会有重复数据
# width 幕布的宽度
# height 幕布的高度
# max_words 要显示的词的最大个数
# generate 读取文本文件
# 实例化词云图对象
wordcloud = WordCloud(font_path='C:/Windows/Fonts/simfang.ttf',collocations=False,background_color='white',width=800,height=600,max_words=50).generate(txt_str) # simfang.ttf是仿宋字体
# 生成图片
image = wordcloud.to_image()
# 展示图片
image.show()
# 保存文件
wordcloud.to_file('tag_zh.jpg')
运行结果:
jieba.analyse的使用:提取关键字
- 第一个参数:待提取关键词的文本
- 第二个参数topK:返回关键词的数量,重要性从高到低排序
- 第三个参数withWeight:是否同时返回每个关键词的权重
- 第四个参数allowPOS=():词性过滤,为空表示不过滤,若提供则返回符合词性要求的关键词,查看:jieba词性表 https://blog.csdn.net/Yellow_python/article/details/83991967
注意:在使用jieba.analyse之前要通过import jieba.analyse 将其导入
使用jieba.analyse提取文本中的关键词
import jieba
import jieba.analyse
text = '不必说碧绿的菜畦,光滑的石井栏,高大的皂荚树,紫红的桑椹;也不必说鸣蝉在树叶里长吟,肥胖的黄蜂伏在菜花上,轻捷的叫天子(云雀)忽然从草间直窜向云霄里去了。单是周围的短短的泥墙根一带,就有无限趣味。油蛉在这里低唱,蟋蟀们在这里弹琴。翻开断砖来,有时会遇见蜈蚣;还有斑蝥,倘若用手指按住它的脊梁,便会拍的一声,从后窍喷出一阵烟雾。何首乌藤和木莲藤缠络着,木莲有莲房一般的果实,何首乌有拥肿的根。有人说,何首乌根是有象人形的,吃了便可以成仙,我于是常常拔它起来,牵连不断地拔起来,也曾因此弄坏了泥墙,却从来没有见过有一块根象人样。如果不怕刺,还可以摘到覆盆子,象小珊瑚珠攒成的小球,又酸又甜,色味都比桑椹要好得远。'
seg_list = jieba.analyse.extract_tags(text,allowPOS=('n')) # 提取文本中的名词
print('analyse extract allowPOS'+str(seg_list)) # 分析提取
运行结果:
使用jieba.analyse提取文本中的关键词并用WordCloud绘制词云图
import jieba
import jieba.analyse
from wordcloud import WordCloud
# text = '不必说碧绿的菜畦,光滑的石井栏,高大的皂荚树,紫红的桑椹;也不必说鸣蝉在树叶里长吟,肥胖的黄蜂伏在菜花上,轻捷的叫天子(云雀)忽然从草间直窜向云霄里去了。单是周围的短短的泥墙根一带,就有无限趣味。油蛉在这里低唱,蟋蟀们在这里弹琴。翻开断砖来,有时会遇见蜈蚣;还有斑蝥,倘若用手指按住它的脊梁,便会拍的一声,从后窍喷出一阵烟雾。何首乌藤和木莲藤缠络着,木莲有莲房一般的果实,何首乌有拥肿的根。有人说,何首乌根是有象人形的,吃了便可以成仙,我于是常常拔它起来,牵连不断地拔起来,也曾因此弄坏了泥墙,却从来没有见过有一块根象人样。如果不怕刺,还可以摘到覆盆子,象小珊瑚珠攒成的小球,又酸又甜,色味都比桑椹要好得远。'
# 读取文本文件
fp = open('data_zh.txt','r',encoding='utf-8')
text = fp.read()
fp.close()
# seg_list = jieba.analyse.extract_tags(text,allowPOS=('n')) # 提取文本中的名词
seg_list = jieba.analyse.extract_tags(text) # 不设定关键词
print('analyse extract allowPOS'+str(seg_list)) # 分析提取
print(len(seg_list))
# 将提取到的关键字列表拼接成字符串
seg_str = ' '.join(seg_list)
print(seg_str)
# 绘制词云图
wordcloud = WordCloud(font_path='C:/Windows/Fonts/simfang.ttf',collocations=False,background_color='white',width=800,height=600,max_words=50).generate(seg_str)
image = wordcloud.to_image()
image.show()
运行结果: