可视化日记:使用Matplotlib进行一个简单绘图(直方图)

目录

一、导包

二、读取数据

三、画图:

关于hist():

1、hist() 方法的主要参数:

2、hist() 方法的返回值:

四、结果:

五、错误检查:由于数据分布不均匀产生的图像显示问题

六、调整:

(一)调整组距:

(二)自定义图像

我想要达成的目标:

1、将柱子调整,每组柱子添加边框,并将柱子的颜色设置成为绿色:

2、调整横坐标数据,添加标签

问题:Matplotlib绘图无法显示中文字体

解决:通过 plt.rcParams[ ] 方法修改 matplotlib 的配置文件,即 .rc 文件

3、在每组 bin 上添加数据,并将这个视图的 title 改为:“会员消费区间分布”

七、代码


        文章记录一次使用 Matplotlib 进行数据可视化操作过程,包括遇到的问题,汇总的代码在文章结尾

一、导包

        将可能用到的包导入

import pandas as pd
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt

二、读取数据

data= pd.read_excel(r'C:\Users\yysc\Desktop\tools\近一年会员消费金额.xlsx')
s1=data['消费金额']
print(data)
print(s1)

 data:

                      ID    消费金额
0       2303261145034650   150.2
1        112101100036969  1062.8
2       2305132129519544   146.3
3       2111271415175978     5.7
4        110100800021813  2036.6
...                  ...     ...
288842  2205221256421604    26.1
288843  2112251336015595   176.4
288844         200020204  1455.5
288845   108100100112899   399.4
288846         100028938   522.5

s1:

[288847 rows x 2 columns]
0          150.2
1         1062.8
2          146.3
3            5.7
4         2036.6
           ...  
288842      26.1
288843     176.4
288844    1455.5
288845     399.4
288846     522.5
Name: 消费金额, Length: 288847, dtype: float64

三、画图:

        数据是连续型的数据,并没有被分组,我使用条形图,画出一个不同区间的频率直方图,s1的作用是所需要的取数据列

fig,ax=plt.subplots()
n, bins, patches = ax.hist(s1,50,density=True) # density=True纵坐标可以显示概率密度
# print(n,bins,patches)
plt.show()

关于hist():

        在这里,只创建了一个Axes,即ax,对其使用 hist() 方法进行绘图,该方法只需要传入x,不用传入y

1、hist() 方法的主要参数:
  • x:使用的数据序列。
  • bins:可选,它包含整数,序列或字符串,是将横坐标分成了几个区间
  • range:可选,是 bins 的上下限。
  • density:可选,bool值,为TRUE时显示概率密度
  • ...等其他参数可参考官方文档:matplotlib.pyplot.hist — Matplotlib 3.7.2 documentation
2、hist() 方法的返回值:

        hist() 方法会有3个返回值

  • n:bins的值,每个bin里面元素数量;
  • bins:返回每个bin的区间范围;
  • patches:如这里的<BarContainer object of 50 artists> 

(最后一点不咋明白,但总之 patches 可以是 Container 和多边形列表两种,Container 大概意思就是是一个类,然后包含符合 Artists 范围内的一些概念,如在 bar plots中 的 bars;多边形列表就比如一个包括这个直方图的50个柱子的列表,如有误解望指教改正)

可参考官方文档以及:【matplotlib】可视化之路——Patch类详解_matplotlib patch_小猪猪家的大猪猪的博客-CSDN博客

四、结果:

五、错误检查:由于数据分布不均匀产生的图像显示问题

        可以看出,结果很奇怪,先使用 ticklabel_format() 关闭科学计数法,再放大看看y轴的实际值:

ax.ticklabel_format(useOffset=False, style='plain')    # 关闭科学计数法
n, bins, patches = ax.hist(s1,50)    # 去掉density=TRUE,竖轴就是频数
plt.show()

        这里显示,由0左右到20000这个区间的的数据有25万条以上,考虑是数据分布不均匀的问题,上面说到n可以返回每个 bin 里面元素的数量,输出一下:

print(n)

         由上可知,在其他 bins 里面,存在1个或者2个数据,这与28万相比起来实在是太少了,所以在图像里面几乎显示不出来,看起来就只有一根柱子,放大多次之后可以看见其他区间其实还是有高度的:

         在此将第一个区间之外的视作异常值,去掉,只筛选2000以内的数据

s1=data[data['消费金额']<=2000]['消费金额']

         再进行绘制:

 (这下合理多了)

六、调整:

(一)调整组距:

        在统计学里确定组距和组数的方法:

组数:用极差/组距,或参考 Sturges 公式:n=1+3.33lgN (N为样本量)

组距:组距 =(最大值-最小值)/组数

        数值为负的可能是退单情况,我选择金额在 0-2000 之间的数据进行绘制,分为20组(这个数据就是根据经验公式计算出来的,过程中竟然惊讶地发现很多区间的端点刚好是整百!!!

s1=data.loc[(data['消费金额']<=2000) & (data['消费金额']>0),['消费金额']]
# 对比:
# s1=data[data.loc[(data['消费金额']<=2000) & (data['消费金额']>0),['消费金额']]]
# 这种会报错,要求里面是表达式,而data.loc[(data['消费金额']<=2000) & (data['消费金额']>0),['消费金额']]输出的是个object

fig,ax=plt.subplots()
n, bins, patches = ax.hist(s1,20,density=True) # density=True纵坐标可以显示概率密度
ax.ticklabel_format(useOffset=False, style='plain')
print(n,bins)
plt.show()

         此时图像就基本完成了,

        

(二)自定义图像

        因为 matplotlib 的功能实在过于强大,甚至可以自定义一套属于自己的绘图风格,所以在了解其一些基本概念后决定从实际需求出发来熟悉这个库

  • 我想要达成的目标:

1、将柱子调整,每组柱子添加边框,并将柱子的颜色设置成为绿色:

        edgecolor = "black":在hist方法中设置 edgecolor 参数即可设置边框的颜色了        

        color="lime":该参数控制直方图柱子的颜色,具体选择移步:Python Matplotlib绘图的color参数可选内容_matplotlib color_爱学习的小杠精的博客-CSDN博客(很不错,强推!)

n, bins, patches = ax.hist(s1,20,density=True, edgecolor = "black",color="lime") # density=True纵坐标可以显示概率密度

2、调整横坐标数据,添加标签
  • 使用 plt.xticks(ticks, labels) 修改横坐标

主要参数:

        ticks:标签显示的位置的列表,传入空列表将清空轴上标签

        labels:所给出标签位置上标记的记号,可以是人名,月份等,必须有 ticks 参数才能传入该参数

plt.xticks(range(0,2001,100))

效果如下:

  •  使用 plt.xlable()/plt.ylable() 修改坐标轴名字:
plt.xlabel('消费金额')
plt.ylabel('占比')

        得到: 

        介似嘛,中文并没有显示出来?

问题:Matplotlib绘图无法显示中文字体
解决:通过 plt.rcParams[ ] 方法修改 matplotlib 的配置文件,即 .rc 文件
plt.rcParams['font.sans-serif'] = 'SimHei'   # 使图形中的中文正常编码显示

        .rc 配置文件记录着绘图的风格,可以通过修改这自信文件形成一个属于自己的绘图风格,这里 rcParams 后必须跟 [ ] 不可以使用()号(不是很理解,大概是因为这是配置文件里的一个类似固定属性的东西?)

3、在每组 bin 上添加数据,并将这个视图的 title 改为:“会员消费区间分布”
  • 通过 text() 方法添加每组数据的标签:

plt.text(x, y, s, fontsize, verticalalignment,horizontalalignment,rotation , kwargs)

主要参数:
        x,y:标签添加的位置,注释文本内容所在位置的横/纵坐标,默认是根据坐标轴的数据来度量的,是绝对值,也就是说图中点所在位置的对应的值
        s:标签的符号,字符串格式,比如你想加个“我爱python”,更多的是你标注跟数据有关的主体。
        fontsize:加标签字体大小,取整数。
        verticalalignment:垂直对齐方式 ,可选 ‘center’ ,‘top’ , ‘bottom’,‘baseline’ 等
        horizontalalignment:水平对齐方式 ,可以填 ‘center’ , ‘right’ ,‘left’ 等
        rotation:标签的旋转角度,以逆时针计算,取整
        family :设置字体
        style: 设置字体的风格
        weight:设置字体的粗细
        bbox:给字体添加框, 如 bbox=dict(facecolor=‘red’, alpha=0.5) 等。
        string:注释文本内容

        此处纵坐标 y 可以由 n 确定,横坐标 x 可以根据 bins 来确定,n 和 bins 都是数组,代表着什么前面已经了解过了,我现在只需要利用其下表,再写一个循环语句即可在每组 bins 上一个个标注数据了

print(type(bins),len(bins),bins[0],bins[20])

<class 'numpy.ndarray'> 21 6.66133814775094e-16 2000.0
for a in range(len(bins)-1):
    ax.text(bins[a],n[a]+0.0001,'{}%'.format(round(n[a]*10000,3)))

         注意:

        range() 内的数字不要超过 bins 的长度,否则报错

        纵坐标的设置要适当,若写为 n[a]+0.1 会距离柱子很远(因为纵坐标数值很小!),后面用格式化字符串传递我想要显示的内容

        频率直方图中,纵轴表示频率除以组距的值(即单位距离的频率),每个矩形的高代表频率和组距的商,所以我们如果要显示其频率,则要乘以组间距100,按百分号显示,再乘以100。

        关于这个统计小知识可以看看直方图的纵坐标为什么有时候是频率/组距? - 知乎

  •  通过 title() 方法添加每组数据的标签:
plt.title('会员消费区间分布')

        此时效果: 

        虽然不完美(可能纵坐标还需要再调整),但基本完成了,就先画到这里吧 !!

七、代码

import pandas as pd
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
from matplotlib.ticker import FuncFormatter

plt.rcParams['font.sans-serif'] = 'SimHei'   # 使图形中的中文正常编码显示

data= pd.read_excel(r'C:\Users\yysc\Desktop\tools\近一年会员消费金额.xlsx')
s1=data.loc[(data['消费金额']<=2000) & (data['消费金额']>0),['消费金额']]

fig,ax=plt.subplots()
n, bins, patches = ax.hist(s1,20, density=True,edgecolor = "black",color="lime") 
# density=True纵坐标可以显示概率密度

plt.xticks(range(0,2001,100))

ax.ticklabel_format(useOffset=False, style='plain')    # 关掉科学计数法

for a in range(len(bins)-1):
    ax.text(bins[a],n[a]+0.0001,'{}%'.format(round(n[a]*10000,3)))

plt.xlabel('消费金额')
plt.ylabel('占比')
plt.title('会员消费区间分布')

plt.show()

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

带带琪宝

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值