@

一、数据可视化概述

1、什么是数据可视化

在计算机视觉领域,数据可视化是对数据的一种形象直观的解释,实现从不同维度观察数据,从而得到更有价值的信息。

  • 抽象的、复杂的、不易理解的数据

  • 图形、图像、符号、颜色、纹理等

  • 具备较高的识别效率

  • 数据本身所包含的有用信息

2、为什么要进行数据可视化

  1. 我们利用视觉获取的信息量,远远比别的感官要多得多

  2. 数据可视化能够帮助我们对数据有更加全面的认识

  3. 数据可视化能够在小空间中展示大规模数据

3、案例展示

1)电影台词含义可视化

img

2)南丁格尔图

img

3)文字和可视化对比效果

img

4、数据可视化的作用

  1. 记录信息
    • img
    • img
  1. 分析推理
    • img
    • img
  1. 信息传播与协同
    • img
    • img

5、数据可视化分类

1)科学可视化

面向科学和工程领域,如何以几何、拓扑和形状特征来呈现数据中蕴含的规律

颜色映射

img

轮廓法

将数值等于某一指定指定阈值的点连接起来的可视化方法

img

2)信息可视化

是结构化、非几何的数据如何从大规模高维复杂数据中提取出有用信息

地理信息

  • 空间数据:地理信息数据
    img

时变数据

  • 时变数据可视化采用多视角、数据比较等方法体现数据随时间变化的趋势和规律
    img

层次数据

img

网络数据

  • 不具备层次结构,结构更加复杂自由
    img

DBSCAN
算法将数据点分为三类:
核心 点:在半径 Eps 内含有超过 MinPts 数目的 点
边界点:在半径 Eps 内点的数量小于 MinPts ,但是落在核心点的邻域 内
噪音点:既不是核心点也不是边界点的点

img

6、数据可视化发展历史与未来

1)数据可视化发展史

  1. 17世纪之前:图表萌芽
    • 几何图表和地图
    • 展示重要信息
  1. 1600-1699年:物理测量
    • 时间、距离、空间
    • 测量理论与设备的完善
  1. 1700-1799年:图形符号
    • 等值线
    • 轮廓线
    • 折线图
    • 柱状图
    • 饼状图
  1. 1800-1900年:数据图形
    • 柱状图
    • 饼图
    • 直方图
    • 折线图
  1. 1900-1949年:现代启蒙
    • 广泛应用于政府、商业和科学
    • 提供新的洞察和发现机会
    • 多维数据可视化和心理学介入
  1. 1950-1974年:多维信息的可视编码
    • 《图形符号学》,构成图形的基本要素和图形设计的框架
  1. 1975-1974年:多维统计图形
    • 网络、层次、数据库、文本等非结构化与高维数据
    • 信息可视化发展成一门学科
  1. 1987-2004年:交互可视化
    • 实时数据可视化系统
  1. 2004年至今:可视分析学
    • 数据分析至关重要
    • 辅助用户挖掘出有用信息,做出决策

2)数据可视化的未来

  1. 数据可视化面临的挑战
    • 数据规模大
    • 数据质量问题
    • 数据快速动态变化
    • 分析能力不足
    • 多来源数据的类型和结构各异
  1. 数据可视化发展方向
    • 可视化技术与数据挖掘有着紧密的联系
    • 可视化技术与人机交互有着紧密的联系

二、数据可视化理论

1、视觉感知

1)视觉感知和视觉认知

  1. 视觉感知和视觉认知
    • 视觉感知
      • 人类大脑的最主要功能之一
      • 人眼对客观事物的第一映象
      • 在我们的生活中起着至关重要的作用
    • 视觉感知是指客观事物通过人的视觉器官在人脑中形成的直接反映
      • 视觉低级
        • 与物体性质相关:深度、形状、边界、表面材质等
      • 视觉高级
        • 对物体的识别和分类
        • 一种基本的认知能力
      • 对所观察到的客观事物更深入的理解和解释
      • 会受到记忆、理解、判断、推理等因素的影
  1. 格式塔原则(完图法则)
    • 基本准则
      • 描述了人在视觉上如何感知对象,是图形和用户界面你设计的基本准则
    • 视觉感知
      • 将视觉感知内容理解为常规的、简单的、相连的、对称的或有序的结构
    • 简单提炼法则
      • 是格式塔原则最基本的呢法则
    • 整体
      • 将事务理解为一个整体,而不是将事务理解为组成该事务所有部分的集合
    • 接近原则
      • 通常,人在进行视觉感知时会把距离上相互靠近的元素视作一个整体
      • 元素之间的距离越近,被视作组合的概率越大
    • 相似原则
      • 相似原则关注的是元素内部特征的差异性,比如:纹理、颜色、形状、大小等特征
      • 人们的视觉感知常常会把具有明显共同特征的元素当成一个整体或归为一类
    • 闭合原则
      • 是指人们常常会尽可能地在心理上把一个不连贯的图形补充完整,使之连贯,或者说倾向于从视觉上封闭那些开放或未完成的轮廓
    • 连续原则
    • 基本思想
      • 视觉形象是作为一个统一的整体最先被认知的,而后才是从各个部分开始认知
    • 数据可视化时将数据映射为图形元素,生成包含原始信息的视觉图像的过程

2)颜色理论

  1. 三基色
    img
    • 三基色
    • 相加混色
    • 相加二次色
    • 补色
    • 中间色
  1. 色彩三要素
    img
    • 色相
    • 明度
    • 饱和度
  1. 色彩与心理
    img
    • 冷色
    • 暖色

3)可视化编码

  1. 数据可视化的制作过程实质上是数据到视觉元素的编码过程

  2. 可视化将数据以一定的编码原则映射为直观、易于理解和记忆的可视化元素

  3. 为了能有效、正确地引导用户对数据的理解和分析,设计者在数据的可视化过程中必须遵循科学的可视化编码原则

  4. 设计者要研究人的视觉感知、不同的可视化元素的展示效果,以及如何合理使用不同的视觉通道表达数据所传达的重要信息,避免给用户造成视觉错觉,以达到良好的数据可视化效果。

  • 可视化编码
    描述数据与可视化结果的映射关系,把可视化看做成一组符号的组合,这些图形符号中携带了被编码的信息,从这些符号中读取相应的信息时,就称之为解码

    • 标记
      • 是一组几何图形元素:如点、线、面、体等
    • 视觉通道
      • 用于控制标记的视觉特征,常用的视觉通道有标记的颜色、位置、尺寸、形状、方向、色相、明度、饱和度、纹理等

2、大数据技术

1)数据采集与预处理

  1. 数据来源
    • 人所产生的数据
    • 机器、设备和物体的数据
    • 行业、科研实验数据
  1. 数据采集方法
    • 系统日志
      • 网站点击率、网页浏览痕迹等
    • 网页数据
      • 推文、评论、新闻信息等
    • 其他数据
      • 隐私数据、医疗、科学等
  1. 数据预处理

2)大数据存储与管理

  1. 数据类型
    结构化数据
    • 保存在数据库中
      • 关系型数据库、非关系型数据库

      非结构化数据

    • 文本、图片、音频、视频文件等
      • 分布式文件系统

      半结构化数据

    • xml文件、json文件、计算机日志信息等
      • 用自定义的结构来存储数据
  1. 数据存储方式
    分布式文件系统
    • 90%的大数据都是非结构化数据
    • 分布式文件系统把一个文件分割成很多小的数据块,分布地存储到多个计算机节点上
    • 为了保证系统的容错性和可靠性,分布式文件系统采用多副本方式对数据块进行冗余存储
      • 多副本容错技术
        img

关系型数据库

    • 保存小规模结构化数据

非关系型数据库

    • 灵活的可扩展性
    • 分布式特性与云存储紧密融合
    • 保存大规模数据
    • 开源,成本低

半结构化数据

    • 保存自定义结构的数据

云存储

    • 海量存储,弹性伸缩,无缝扩展
      • 增加存储节点,数据自动重组
      • 减少存储节点,数据自动恢复
    • 高并发读写性能,摆脱单台设备能力束缚
    • 高可靠性,系统业务不中断
    • 同意访问入口,多用户并行访问
    • 高可用性,由及时维护变为定期维护

3)大数据分析与挖掘

大数据处理的数据类型

  1. 静态数据

  2. 动态数据

大数据计算框架

  1. 批处理
    • 静态数据
    • 高延迟
    • 历史数据
  1. 流式处理
    • 动态数据
    • 低延迟
    • 实时性要求高
  1. 交互式查询
    • 低延迟
    • 历史数据
  1. MapReduce
    • 对静态数据做批处理计算
  1. Spark
    • 对动态数据做流式处理
    • 交互式查询

数据挖掘

4)大数据可视化

  • img

3、数据可视化基本图表

  1. 柱状图
    • 柱状对比图
    • 堆叠柱形图
    • 瀑布图
  1. 条形图
    • 双向条形图
    • 多维度双向条形图
    • 子弹图
  1. 折线图
    • 折线对比图
    • 面积图
    • 堆叠面积图
  1. 饼图
    • 环形图
    • 嵌套环形图
    • 南丁格尔玫瑰图
  1. 直方图

  2. 散点图

  3. 气泡图

  4. 雷达图

  5. 地图

  6. 热力图

  7. 箱线图

  8. 矩形树图

4、数据可视化工具

数据可视化工具特性

  • 实时性

    • 数据可视化工具必须适应大数据时代数据量的爆炸式增长需求
    • 必须快速搜集和分析数据,并对数据信息进行实时更新
  • 更丰富的展现

    • 数据可视化工具需要具备更丰富的展现方式
    • 能充分满足数据展现的多维度要求
  • 简单操作

    • 数据可视化工具满足快速发展,易于操作的特性
    • 能满足互联网时代信息多变的特点
  • 多种数据集成支持方式

    • 数据的来源不仅仅局限于数据库
    • 数据可视化工具将支持团队协作数据、数据仓库、文本等多种方式、并能够通过互联网进行展现

大数据可视化工具

  • 入门级工具

    • Excel是日常数据分析工作中最常用的工具,简单易用,用户不需要复杂的学习就可以轻松使用Excel提供的各种图表功能,尤其是制作折线图、饼状图、柱状图、散点图等各种统计图表时,Excel是普通用户的首选工具
    • 信息图表是信息、数据知识等的视觉化表达,它利用了人们对于文字信息更容易理解的特点,更高效、直观、清晰地传递信息,在计算机科学、数学以及统计学领域有着广泛的应用
    • 地图工具在数据可视化中较为常见,他在展示数据基于空间或地理上有着很强的表现力,可以直观地展现各分析指标的分布、区域等特征
    • R、D3、Python
  • 信息图表工具

    • google chart API:谷歌图表API
    • Tableau:视觉创建和仪表板设计
  • 地图工具

    • Google Fushion Tables:云计算的雏形
      • Google Fushion Tables让一般使用者也可以轻松制作出专业的统计地图,该工具可以让数据表呈现为图表、图形和地图,从而帮助发现一些隐藏在数据背后的模式和趋势
    • Modest Maps:交互地图库
      • Modest Maps是一个小型、可扩展、交互式的免费库,提供了一套查看卫星地图的API,只有10KB大小,是目前最小的可用地图库,特也是一个开源项目,有强大的社区支持,是在网站中整合地图应用的理想选择
    • Leaflet:互动地图
      • Leaflet是一个小型化的地图框架,通过小型化和轻量化来满足移动网页的需要
  • 高级分析工具

    • R是一个自由、免费、源代码开放的软件,它是一个用于统计计算和统计制图的优秀工具,使用难度较高,通常用于大数据集的统计与分析
    • Python具有丰富和强大的绘图库
      • Seabron
      • Matplotlib
      • Pyecharts
      • Ggplot
    • D3是用来做web页面可视化的组件,比较难入门,需要有HTML和JavaScript基础才行,对JavaScript的DOM(文档对象模型)要求也有点高

三、Numpy库

1、数组、Numpy

1)数组

  • 一维的数据称为向量

    • 集合
      • 集合中的元素不要求是相同的类型
    • 元组
      • 元组中的元素也不要求是相同的类型
    • 列表
      • 列表中的元素可以是不同的类型
    • 一维数组
      • 数据会将输入的数据转换为一致的数据类型
      • 数组计算的速度较其他类型都快
  • 二维的数据称为矩阵

    • 矩阵
    • 多组一维数据组合就是二维数据
    • 数据库表格和Excel表格是最常见的二维数据
    • 嵌套的列表
    • 二维数组
    • DataFrame表格形式
  • 三维或者更高维的数据,可用数组来表示

    • 3维数据使用三层嵌套列表
    • 三维数组
  • 数组也可以表示一维数据、二维数据、对应的就是一维数组、二维数组

    • 大数据的开发流程一般包括:数据收集、数据存储、数据分析和数据可视化
    • 结果数据一般都是结构化的二维数据、在对其进行数据可视化展现

2)Numpy

  • 具有一个强大的N维数组对象ndarray

  • 广播函数功能

  • 具有线性代数、博立叶变换、随机数生成等功能

  • 是Scipy、Pandas等数据处理或科学计算库的基础

  • 能够整合C/C++/Fortran的代码

Numpy使用array()提供数组的类型ndarray、Numpy的ndarray类型与python内置的list类型比较

  • 数组对象是一维数据更像单个数据,可以不使用for循环进行元素遍历计算

  • Numpy一堆数据对象做了优化,计算速度更快,效率更高

  • 科学计算中,一维数组中的元素类型往往相同

  • 数组对象采用相同的数据类型,有助于节省运算和存储空间

# 用列表存储数据,并计算这组数据的平方
a = [1,2,3,4]
c = []
for i in a:
    c.append(i**2)
print(c)

# 用ndarray类型来存储,计算显然更加加单
# ndarray具有广播功能
import numpy as np
a = np.array([1,2,3,4])
a**2

img

# Python原生数据类型与numpy数组性能对比
def add(n):
    a = []
    b = []
    c = []
    for i in range(n):
        a.append(i ** 2)
        b.append(i + 3)
        c.append(a[i] + b[i])
    return c

def np_add(n):
    a = np.arange(n) ** 2
    b = np.arange(n) + 3
    c = a + b
    return c

N = 1000000
# 比较性能,使用“魔法函数” timeit
%timeit add(N)
%timeit np_add(N)
# 使用numpy运行时间是使用列表的70分之一

img

2、ndarray的创建和操作

ndarray是一个多维数组对象,由两部分构成

  • 实际的数据

  • 描述这些数据的元数据,即数据维度和数据类型等

同构

  • 所有元素的类型一般都是相同的
a = np.array([[1,'a', 3], [4,'v', 6]])
print(type(a))
a

img

1)ndarray的基本属性

ndarray对象的属性

一对象名称.属性名称()

array([['1', 'a', '3'],
       ['4', 'v', '6']], dtype='<U11')
属性 含义 结果 案例
a.shape 数据维度 (2, 3) 2行3列的二维数组
a.size 元素个数 6 6个元素
a.ndim 数组的维度 2 2维数组
a.dtype 元素的数据类型 dtype(‘int32’) dtype(‘int32’)
a.itemsize 每个元素的大小 以字节为单位 4 int32为四个字节

2)ndarray的元素类型

创建ndarray数组时可指定元素的数据类型

所支持的数据类型包括整数、浮点数、复数、布尔值、字符串或是普通的Python对象(object)

np.array([[1, 2, 3], [4, 5, 6]], dtype = np.float32)

img

array_01 = np.array([[1, 2, 3], [4, 5, 6]])
array_01.dtype

img

数据类型 类型说明 说明
int_ 默认整形
intc 等价于long的整形
int8 i1 字节整形,1个字节,范围: [-128, 127]
int16 i2 整形,2个字节,范围:[-32768, 32767]
int32 i3 整形,4个字节,范围:[-2^31, 2^31 - 1]
int64 i4 整形,8个字节,范围:[-2^63, 2^63 - 1]
uint8 u1 无符号整形,1个字节,范围:[0, 255]
uint16 u2 无符号整形,2个字节,范围:[0, 65535]
uint32 u3 无符号整形,1个字节,范围:[0, 2^32 - 1]
uint64 u4 无符号整形,1个字节,范围:[0, 2^64 - 1]
bool_ 以一个字节形成存储的布尔值(True或是False)
float_ float64简写形式
float16 f2 半精度浮点型(2字节): 1符号位 + 5位指数 + 10位的小数部分
float32 f4或f 单精度浮点型(4字节): 1符号位 + 8位指数 + 23位小数部分
float64 f8或d 双精度浮点型(8字节): 1符号位 + 11位指数 + 52位的小数部分
complex_ c16 complex128的简写形式
complex64 c8 复数,由两个32位的浮点数来表示
complex128 c16 复数,由两个64位的浮点数来表示
object O Python对象类型
String_ S 固定长度的字符串类型(每个字符1个字节),比如: 要创建一个长度为8的字符串,应使用S8
Unicode_ U 固定长度的unicode类型的字符串(每个字符占用字节数由平台决定),长度定义类似String_类型

Python内建数据类型仅支持整数、浮点数和复数3种类型

对元素类型进行精确定义,有助于Numpy合理使用存储空间并优化性能。

在科学计算和数据分析领域设计数据类型较多,对存储和性能都有较高要求,并可以应对较大的数据应用场景。

非同质的ndarray对象

  • 非同质ndarray元素为对象类型

  • ndarray数组可以由非同质对象构成

  • 非同质的ndarray对象的元素长度不同

  • 非同质ndarray对象无法有效发挥NumPy优势,应该尽量避免使用

3)ndarray的创建

使用Python的列表、元组等类型创建ndarray数组
# 从列表创建
np.array([[1, 2, 3], [4, 5, 6]], dtype = np.float32)

img

# 从元组创建
np.array([(1, 2), (2, 3)])

img

# 从列表和元组创建
np.array([[1, 2, 3, 4], (4, 5, 6, 7)])

img

到这里可以看出来,不管是什么方式创建,最后都会转化成列表类型

使用Numpy中的函数创建ndarray数组

# 类似range()函数,返回ndarray类型,元素从0到n - 1
np.arange(5)

img

# 根据shape生成一个全1数组,shape是元组类型
np.ones((3, 4))

img

# 根据shape生成一个全0数组,shape是元组类型
np.zeros((2, 3 ,4))

img

# 根据shape生成一个数组,每个元素都是val
np.full((2, 3), 99)

img

# 创建一个正方的n*n单位矩阵,对角线为1,其余为0
np.eye(5)

img

# 根据已有数组,生成一个维度相同的新数组
print('array_01:\n', array_01)
# 根据数组array_01的形状生成一个全1数组
print('np.ones_like:\n', np.ones_like(array_01))
# 根据数组array_01的形状生成一个全0数组
print('np.zeros_like:\n', np.zeros_like(array_01))
# 根据数组array_01的形状生成一个数组,每个元素值都是val
print('np.full_like:\n', np.full_like(array_01, 99))

img

# 根据起止数据等间距地填充数据,形成数组
np.linspace(1, 10, 10)

img

4)ndarray的变换

  • 维度变换

    • # 创建一个新的数组
      a = np.linspace(1, 12, 12, dtype=np.int32)
      # ndarray数组的维度变换
      # 不改变数组元素,返回一个shape形状的数组,原数组a不变
      b = a.reshape(3, 4)
      print('a:\n', a)
      print('b:\n', b)
      

      img

    • # 改变数组的shape,且修改原数据
      a.resize(3, 4)
      a
      

      img

    • # 将数组n个维度中两个维度进行调换
      a.swapaxes(1, 0)
      

      img

    • # 把数组的维度降低,返回折叠后的一维数组,原数组不变
      a.flatten()
      

      img

  • 元素类型变换

    • # 创建一个新的数组
      b = np.linspace(1, 9, 9)
      b.resize(3, 3)
      print('b:\n', b)
      print('b.dtype:\n', b.dtype)
      d = b.astype(np.int16)
      print('d:\n', d)
      

      img

  • 数组转换为列表

    • print('b:\n', b)
      # 转换为list类型
      b.tolist()
      

      img

5)ndarray的操作

索引:获取数组中特定位置的元素

维度用,切开 不用,表示一个维度一直用行,先从行开始 :后面不包括

c = np.linspace(1, 24, 24, dtype=np.int)
c.resize(2, 3, 4)
print('c:\n', c)
print('c[0]:\n', c[0])
print('c[0][0]:\n', c[0][0])
# 多维数组索引方式一
print('c[0][0][0]:\n', c[0][0][0])
# 多维数组索引方式二
print('c[0, 0, 0]:\n', c[0, 0, 0])

img

切片:获取数组元素子集

# 切片获取元素子集
print('c:\n', c)
print('c[0][1:3][1:3]:\n', c[0][1:3][1:3])
print('c[0, 1:3, 1:3]:\n', c[0, 1:3, 1:3])
# 获取步长跳跃切片
print('c[0, 1, ::2]:\n', c[0, 1, ::2])#双冒号表示步长

img

3、ndarray数组的运算

1)ndarray与标量运算

  • 乘法

    # 乘法
    a = np.arange(1, 10).reshape(3, 3)
    b = [1, 2, 4]
    print('a:\n', a)
    print('a*10:\n', a*10)
    print('b*3:\n', b*3)
    

    img

  • 平方

    # 平方
    a**2
    

    img

  • 减法

    # 减法
    a - 9
    

    img

  • 逻辑运算、比较大小、过滤元素

    # 数组的重要特性,过滤值
    print('a > 5:\n', a > 5)
    # 使用多条条件过滤,注意运算优先级
    print('a[(a > 5) & (a < 8)]:\n', a[(a > 5) & (a < 8)])
    

    img

2)数组元素运算函数

函数名称 函数功能
np.abs(b) 计算各元素的绝对值
np.sqrt(b) 计算各元素的平方根
np.square(b) 计算各元素的平方
np.log(b)、np.log10(b)、np.log2(b) 计算数组各元素的自然对数、10底对数和2底对数
np.ceil© 计算数组各元素的ceiling值,向上取整
np.floor© 计算数组各元素的floor值,向下取整
np.rint© 计算数组各元素的四舍五入值
np.modf© 将数组个元素的小树和整数部分以两个独立数组形式返回
np.cos© 三角函数

3)数组间的运算

维度相同的数组

  • 加:a + b

  • 减:a - b

  • 乘:a * b

  • 除:a / b

  • 逻辑运算:a > b

4)Numpy统计函数

数组内的所有元素进行统计,通常是返回一个数值

  • np.sum()求和

    # 求每列的和
    print('np.sum(a, axis=0):\n', np.sum(a, axis=0))
    # 求每行的和
    print('np.sum(a, axis=1):\n', np.sum(a, axis=1))
    # 求所有元素的和
    print('np.sum(a):\n', np.sum(a))
    

    img

函数名称 函数功能
np.min(a) 求取最小值
np.max(a) 求取最大值
np.median(a) 计算中间值
np.average(a) 计算加权平均值
np.mean(a) 计算算术平均值
np.std(a) 计算标准差
np.var(a) 计算方差

四、Pandas库

1、Pandas数据结构Series对象

1)创建Series对象

Series保存的是一维带索引的数组

数组中的元素可以是任何数据类型,整数,字符串,浮点数,Python对象等

  • data,一维数组

    • Numpy的ndarray对象
    • 字典、列表等
    • 一个数值,比如数字5
  • Index,每个元素的索引

    • Series一维数组的每个元素都带有索引
    • 如果不传入index参数,会自动为每个元素生产索引
# 导入pandas和numpy
import pandas as pd
import numpy as np
data = np.arange(1, 10)
index = np.arange(11, 20)
s = pd.Series(data, index=index)
s

img

  • 从Numpy的ndarray对象创建Series对象

    • 如果传入的data是一个ndarray对象,索引index必须和data要有一样的长度
    • 如果没有传入索引index,将会自动创建一个从0开始的索引
    • 传入index索引

      s = pd.Series(np.random.rand(5), index=['a', 'b', 'c','d', 'e'])
      
    • 不传入index索引,自动创建索引
s = pd.Series(np.random.rand(5))

  • 用字典创建Series对象

    • 如果不传入索引

      index

      参数,字典的key将会成为索引

    d = {'a': 1, 'b': 3, 'c': 5}
    pd.Series(d)

  
- - 如果传入的data是dict类型,并且同时传入了索引index,则将按照传入的索引值来创建Series对象

- - 如果传入的索引

    index

    与传入的数据

    data

    不匹配,则将以索引为准。

pd.Series(d, index=['a', 'b', 'c', 'd', 'e'])
```
  • 用列表创建Series对象

    • 如果不传入索引,则会自动创建索引

      pd.Series([x for x in range(1, 5)])
      
    • 如果传入索引,索引的长度必须与

      data

      的长度相同

      pd.Series([x for x in range(1, 5)], list('abcd'))
      
    • 如果索引的长度与data的长度不同,程序会报错

2)操作Series对象

  • 数字索引

  • index

    索引

    s = pd.Series(np.random.rand(3), index=['a', 'b', 'c'])
    print("s[0]:\n", s[0])
    print("s['b']:\n", s['b'])
    

    img

判断索引是否在索引列表中

  • In

  • 直接访问一个不存在的索引会报KeyError错误

  • get函数

    • 索引存在,则返回对应值
    • 索引不在,无返回值
    • 指定索引不存在的的返回值
print("'a' in s: \n", 'a' in s)
print("'f' in s: \n", 'f' in s)
try:
    print("s['f']: \n", s['f'])
except KeyError:
    print(KeyError)
print("s.get('b'): \n", s.get('b'))
print("s.get('f'):\n", s.get('f'))
print("s.get('f', 'f不在索引列表中'):\n", s.get('f', 'f不在索引列表中'))

img

切片

  • 分号分隔,截取部分子集

    print("s[:3]:\n{}".format(s[:3]))
    print("s[:'c']:\n{}".format(s[:'c']))
    print("s[1:3]:\n{}".format(s[1:3]))
    print("s[[1,2]]:\n{}".format(s[[1,2]]))
    

    img

跟ndarray类似

  • 进行向量化计算

    • 加减乘除
  • numpy的很多函数也能够作用于Series对象

    • np.sqrt(s),np.square(s)

3)时间序列

  • Series对象最重要的功能是保存和处理时间序列数据

  • 金融领域的数据一般都是时间序列数据

  • Pandas能够很好地支持时间序列数据

  • pandas的data_range函数创建一个时间序列

    # 生成从2018年9月1日开始,十天的时间序列索引,频率为10分钟
    rng = pd.date_range('9/1/2018', periods=1440, freq='10Min')
    rng[:5]
    

    img

  • 创建Series对象,对应索引为时间序列

    ts = pd.Series(np.random.rand(1440), index=rng)
    ts.head()
    

    img

    ts.count()
    

    img

  • 切片的方式提取和访问数据

    ts[:5]
    

    img

    ts[:10:2]
    

    img

  • 时间日期与切片结合的方式提取数据

    # 时间字符串索引
    ts['9/6/2018'][140:]
    

    img

    # datetime类型的索引
    from datetime import datetime
    ts[datetime(2018, 9, 9):][::60]
    

    img

2、DataFrame对象的创建与保存

1)创建DataFrame对象

  • DataFrame是一种带索引的二维数据结构

  • 二维数据

    • 二维列表
    • ndarray对象
  • 一维数据

    • 一维列表
      • 多个一维列表要求长度相同
      • 组成一个字典
    • Series对象
      • 组成一个字典
  • 包含字典的列表

  • 三维数据

    • 可传入三维列表数据,但无法解析
    • 不能传入ndarray三维数组

2)保存到文件数据库

DataFrame数据导出到文件

  • Tushare是一个免费、开源的python财经数据接口包

  • Tushare返回的绝大部分的数据格式都是pandas DataFrame类型,非常便于用pandas进行数据分析

  • 安装:pip install tushare

  • 官方文档:http://tushare.org/
    img
    img
    img

  • 导出到MySQL数据库
    img

3)读取文件/数据库

  • 读取Excel、json文件

    • read_excel()读取Excel文件数据
    • Excel文件可以是包含单个表的文件
    • Excel也可以是包含多个表的工作薄,这时需要指定工作表名称
    • read_json()读取json文件内容
  • 读取数据库table内的表

    • 建立数据库连接
    • read_sql()读取指定表的内容

3、DataFrame的数据操作

  • 选择、添加与删除数据

    • 选择行和列
    • 添加新列
      • 基于已有列添加新列
      • 用标量赋值
      • Series对象
      • 指定列插入
    • 删除列
      • pop()删除指定列,返回指定列
      • del 删除指定列,无返回值
  • 分组计算与汇总

    • 导入数据
    • 按照条件对所有的数值型变量进行汇总
      • 分组:groupby()
      • 汇总:sum()
    • 选择有现实意义的数值型变量进行汇总
      • 添加变量的索引进行汇总
    • 分组汇总单列数据
    • mean()求平均值
    • describe()进行描述性统计
    • 多个分类变量对数据进行汇总
  • 数据融合

    • merge()基于指定列进行连接

      df1 = pd.DataFrame({'name': ['hellof', 'masonsxu', 'a', 'b', 'c']})
      df2 = pd.DataFrame({'name': ['hellof', 'masonsxu', 'A', 'B', 'C']})
      pd.merge(df1, df2, on='name')
      

      img

    • inner内连接

      pd.merge(df1, df2, how='inner')
      

      img

    • left左连接

      pd.merge(df1, df2, how='left')
      

      img

    • right右连接

      pd.merge(df1, df2, how='right')
      

      img

    • outer外连接

      pd.merge(df1, df2, how='outer')
      

      img

五、matplotlib库

绘图区域

image-20200411225454819

image-20200411225558991

这个地方我解释一下,211,2两个图,1表示1列,最后一个1表示在上面,同理2表示在下面,所以有两个图

plot()函数

image-20200411225942663

例如

image-20200411230013557

image-20200411230130021

image-20200411230155350

image-20200411230211066

例如

image-20200411230229263

image-20200411230501429

中文显示

image-20200411230538137

image-20200412104302882

image-20200412104500419

image-20200412104558747

image-20200412104618701

文本显示

image-20200412110429706

image-20200412110445479

image-20200412110534874

子绘图区域

image-20200412110654468

image-20200412111438481

image-20200412111525082

image-20200412112127674

六、Pyecharts库

1.柱形图

from pyecharts import Bar
# 数据
goods =["衬衫", "羊毛衫", "雪纺衫", "裤子", "高跟鞋", "袜子"]
sales1 =[5, 20, 36, 10, 10, 100] # 商家A各个产品对应的销售量
sales2 =[55, 60, 16, 20, 15, 80] # 商家B各个产品对应的销售量

bar = Bar('柱形图-销售量', '显示服装的各个子类的销售量')
bar.add('服装', goods, sales1,  is_label_show=True) # is_label_show在柱形图上方显示销售量
bar.render(path='results/1.柱形图.html')

bar2 = Bar("显示标记线和标记点")
bar2.add('商家A', goods, sales1, mark_point=['average']) # mark_point标记商家A与平均值最接近的销售量
bar2.add('商家B', goods, sales2, mark_line=['min', 'max']) # mark_line标记商家B的销售量最大值和最小值
bar2.render(path='results/2.标记点柱形图.html')

bar3 = Bar("水平显示")
bar3.add('商家A', goods, sales1)
bar3.add('商家B', goods, sales2, is_convert=True) # is_convert 交换 XY 轴
bar3.render(path='results/3.水平柱形图.html')

image-20200415172809279

image-20200415172834359

image-20200415172846220

2. 柱形图+datazoom_slider

import random
from pyecharts import Bar

days = ["{}天".format(i) for i in range(1,31)] # 横坐标为每一天
sales1 = [random.randint(0, 100) for _ in range(1,31)] # 纵坐标为每一天的销售量
bar = Bar("展示一个月每一天的销售量","Bar_datazoom_slider 示例")
bar.add("", days, sales1, is_label_show=False, is_datazoom_show=True) # is_datazoom_show 显示下方的滑动条
bar.render(path='results/4.datazoom_slider.html')

image-20200415173127641

3. 柱形图+datazoom_inside

import random
from pyecharts import Bar

days = ["{}天".format(i) for i in range(1,31)]
sales1 = [random.randint(0, 100) for _ in range(1,31)]
bar = Bar("展示一个月每一天的销售量","Bar_datazoom_inside 示例")
bar.add(
    "",
    days,
    sales1,
    is_datazoom_show=True,
    datazoom_type="both", # 取值可以"inside"或"both","inside"没有下方的滑动条,但可以通过滑动鼠标滚轮控制显示柱形图个数。
    # "both"即显示下方的滑动条,又可以用鼠标滚轮控制显示个数。
    datazoom_range=[10, 25],
)
bar.render(path='results/5.datazoom_inside.html')

image-20200415173547365

4. 柱形图+多个datazoom

import random
from pyecharts import Bar
days = ["{}天".format(i) for i in range(1,30)]
sales1 = [random.randint(0, 100) for _ in range(1,30)]
bar = Bar("展示一个月每一天的销售量","Bar_datazoom_xaxis/yaxis 示例")
bar.add(
    "",
    days,
    sales1,
    # 默认为 X 轴,横向
    is_datazoom_show=True,
    datazoom_type="slider",
    datazoom_range=[10, 25],
    # 新增额外的 dataZoom 控制条,纵向
    is_datazoom_extra_show=True,
    datazoom_extra_type="slider",
    datazoom_extra_range=[10, 25],
    is_toolbox_show=False,
)
bar.render(path='results/6.datazoom_xaxis_yaxis.html')

image-20200415173723379

5. 坐标轴标签旋转示例

import random
from pyecharts import Bar
days = ["第{}天".format(i) for i in range(1,31)]
sales1= [random.randint(0,100) for _ in range(1,31)]
bar = Bar("坐标轴标签旋转示例")
bar.add("", days, sales1, xaxis_interval=0, xaxis_rotate=30, yaxis_rotate=20)
bar.render(path='results/7.坐标轴标签旋转示例.html')

image-20200415173835380

6. 双向条形图

from pyecharts import Bar

months = ["{}月".format(i) for i in range(1, 8)]
cost = [1000.0, 150.0, 120.0, 130.0, 200.0, 150.0, 200.0]
income = [200.0, 300.0, 260.0, 300.0, 230.0, 180.0, 320.0]
bar = Bar("成本收入对比图","双向条形图")
# 利用第一个 add() 图例的颜色为透明,即 'rgba(0,0,0,0)',并且设置 is_stack 标志为 True
bar.add("cost", months, cost,  is_label_show=True,is_stack=True, label_pos='inside')
bar.add("income", months, income, is_label_show=True, is_stack=True, label_pos='inside', is_convert=True)
bar.render(path='results/8.成本收入对比图.html')

image-20200415174006516

7. 对比柱状图

from pyecharts import Bar

attr = ["{}月".format(i) for i in range(1, 13)]
v1 = [2.0, 4.9, 7.0, 23.2, 25.6, 76.7, 135.6, 162.2, 32.6, 20.0, 6.4, 3.3]
v2 = [2.6, 5.9, 9.0, 26.4, 28.7, 70.7, 175.6, 182.2, 48.7, 18.8, 6.0, 2.3]
bar = Bar("柱状图示例","副标题",extra_html_text_label=["额外的文本标签", "color:red"])
bar.add("蒸发量", attr, v1, mark_line=["average"], mark_point=["max", "min"])
bar.add("降水量", attr, v2, mark_line=["average"], mark_point=["max", "min"])
bar.render(path='results/9.降水量与蒸发量.html')

image-20200415204647297

8. 3D 柱状图

from pyecharts import Bar3D
import pandas as pd
#假设我们的数据集是一个数据框。
#该数据集有三个维度,分别是month、city、sales。其中month、city是类别变量,sales是数值型变量。
data=pd.DataFrame({'month':['1月','2月','3月','1月','2月','3月'],
                   'city':['北京','北京','北京','上海','上海','上海'],
                   'sales':[400,500,430,550,600,420] })
#由于Bar3D处理的数据要求是列表型,这里对数据框数据做一些处理。
#x,y轴表示类目轴,取值是独立不重复的。
x_name = list(set(data.iloc[:, 0]))
y_name = list(set(data.iloc[:, 1]))

#将原始数据框数据转换成列表型。
data_xyz=[]
for i in range(len(data)):
     x=x_name.index(data.iloc[i,0])
     y=y_name.index(data.iloc[i,1])
     z=data.iloc[i,2]
     data_xyz.append([x,y,z])
#注意:这里将类别数据转换成了数值数据,便于在x、y、z轴绘制出图形。
#初始化图形。
bar3d=Bar3D("1-3月各城市销量","单位:万件",title_pos="center",width=1200,height=800)
#随机选取几种颜色编码用于区分
range_color = ['#313695', '#4575b4', '#74add1', '#abd9e9', '#e0f3f8', '#ffffbf',
               '#fee090', '#fdae61', '#f46d43', '#d73027', '#a50026']
#添加数据层,并配置图形参数。
bar3d.add('', #''表示图表标题为空
x_name,y_name, #x_name、y_name是类别值
data_xyz,#data_xyz是处理后的数据
is_label_show=True,#is_label_show=True表示显示数据标签
is_visualmap=True, #是否以热图显示
visual_range_color=range_color, #热图颜色范围
visual_range=[0, 500],#visual_range调整数据颜色深度,这里超过500的数值颜色更深
grid3d_shading='lambert',# 让柱形图看起来更加真实
is_grid3d_rotate=True, # 启动自动旋转功能
grid3d_rotate_speed=90, # 调节旋转速度
grid3d_width=150, #柱形宽度
grid3d_depth=50)#柱形高度
bar3d.render(path='results/10.3D柱状图.html')

image-20200415205357695

9. 箱形图

from pyecharts import Boxplot

boxplot = Boxplot("箱形图")
x_axis = ['expr1', 'expr2', 'expr3', 'expr4', 'expr5']
y_axis = [
    [850, 740, 900, 1070, 930, 850, 950, 980, 980, 880,
    1000, 980, 930, 650, 760, 810, 1000, 1000, 960, 960],
    [960, 940, 960, 940, 880, 800, 850, 880, 900, 840,
    830, 790, 810, 880, 880, 830, 800, 790, 760, 800],
    [880, 880, 880, 860, 720, 720, 620, 860, 970, 950,
    880, 910, 850, 870, 840, 840, 850, 840, 840, 840],
    [890, 810, 810, 820, 800, 770, 760, 740, 750, 760,
    910, 920, 890, 860, 880, 720, 840, 850, 850, 780],
    [890, 840, 780, 810, 760, 810, 790, 810, 820, 850,
    870, 870, 810, 740, 810, 940, 950, 800, 810, 870]
]
_yaxis = boxplot.prepare_data(y_axis)       # 转换数据
boxplot.add("boxplot", x_axis, _yaxis)
boxplot.render(path='results/11.箱型图.html')

image-20200417104756684

10. 对比箱型图

from pyecharts import Boxplot

boxplot = Boxplot("箱形图")
x_axis = ['expr1', 'expr2']
y_axis1 = [
    [850, 740, 900, 1070, 930, 850, 950, 980, 980, 880,
    1000, 980, 930, 650, 760, 810, 1000, 1000, 960, 960],
    [960, 940, 960, 940, 880, 800, 850, 880, 900, 840,
    830, 790, 810, 880, 880, 830, 800, 790, 760, 800],
]
y_axis2 = [
    [890, 810, 810, 820, 800, 770, 760, 740, 750, 760,
    910, 920, 890, 860, 880, 720, 840, 850, 850, 780],
    [890, 840, 780, 810, 760, 810, 790, 810, 820, 850,
    870, 870, 810, 740, 810, 940, 950, 800, 810, 870]
]
boxplot.add("category1", x_axis, boxplot.prepare_data(y_axis1))
boxplot.add("category2", x_axis, boxplot.prepare_data(y_axis2))
boxplot.render(path='results/11.箱型图2.html')

image-20200417104926208

11. 动态散点图

from pyecharts import EffectScatter

v1 = [10, 20, 30, 40, 50, 60]
v2 = [25, 20, 15, 10, 60, 33]
es = EffectScatter("动态散点图示例")
es.add("effectScatter", v1, v2)
es.render(path='results/12.动态散点图.html')

image-20200417105046125

12. 动态散点图2

from pyecharts import EffectScatter
es = EffectScatter("动态散点图各种图形示例")
es.add(
    "",
    [10],
    [10],
    symbol_size=20,
    effect_scale=3.5,
    effect_period=3,
    symbol="pin",
)
es.add(
    "",
    [20],
    [20],
    symbol_size=12,
    effect_scale=4.5,
    effect_period=4,
    symbol="rect",
)
es.add(
    "",
    [30],
    [30],
    symbol_size=30,
    effect_scale=5.5,
    effect_period=5,
    symbol="roundRect",
)
es.add(
    "",
    [40],
    [40],
    symbol_size=10,
    effect_scale=6.5,
    effect_brushtype="fill",
    symbol="diamond",
)
es.add(
    "",
    [50],
    [50],
    symbol_size=16,
    effect_scale=5.5,
    effect_period=3,
    symbol="arrow",
)
es.add(
    "",
    [60],
    [60],
    symbol_size=6,
    effect_scale=2.5,
    effect_period=10,
    symbol="triangle",
)
es.render(path='results/12.动态散点图2.html')

image-20200417105212201

13. 地图

from pyecharts import Geo

data = [
    ("海门", 9),("鄂尔多斯", 12),("招远", 12),("舟山", 12),("齐齐哈尔", 14),("盐城", 15),
    ("赤峰", 16),("青岛", 18),("乳山", 18),("金昌", 19),("泉州", 21),("莱西", 21),
    ("日照", 21),("胶南", 22),("南通", 23),("拉萨", 24),("云浮", 24),("梅州", 25),
    ("文登", 25),("上海", 25),("攀枝花", 25),("威海", 25),("承德", 25),("厦门", 26),
    ("汕尾", 26),("潮州", 26),("丹东", 27),("太仓", 27),("曲靖", 27),("烟台", 28),
    ("福州", 29),("瓦房店", 30),("即墨", 30),("抚顺", 31),("玉溪", 31),("张家口", 31),
    ("阳泉", 31),("莱州", 32),("湖州", 32),("汕头", 32),("昆山", 33),("宁波", 33),
    ("湛江", 33),("揭阳", 34),("荣成", 34),("连云港", 35),("葫芦岛", 35),("常熟", 36),
    ("东莞", 36),("河源", 36),("淮安", 36),("泰州", 36),("南宁", 37),("营口", 37),
    ("惠州", 37),("江阴", 37),("蓬莱", 37),("韶关", 38),("嘉峪关", 38),("广州", 38),
    ("延安", 38),("太原", 39),("清远", 39),("中山", 39),("昆明", 39),("寿光", 40),
    ("盘锦", 40),("长治", 41),("深圳", 41),("珠海", 42),("宿迁", 43),("咸阳", 43),
    ("铜川", 44),("平度", 44),("佛山", 44),("海口", 44),("江门", 45),("章丘", 45),
    ("肇庆", 46),("大连", 47),("临汾", 47),("吴江", 47),("石嘴山", 49),("沈阳", 50),
    ("苏州", 50),("茂名", 50),("嘉兴", 51),("长春", 51),("胶州", 52),("银川", 52),
    ("张家港", 52),("三门峡", 53),("锦州", 54),("南昌", 54),("柳州", 54),("三亚", 54),
    ("自贡", 56),("吉林", 56),("阳江", 57),("泸州", 57),("西宁", 57),("宜宾", 58),
    ("呼和浩特", 58),("成都", 58),("大同", 58),("镇江", 59),("桂林", 59),("张家界", 59),
    ("宜兴", 59),("北海", 60),("西安", 61),("金坛", 62),("东营", 62),("牡丹江", 63),
    ("遵义", 63),("绍兴", 63),("扬州", 64),("常州", 64),("潍坊", 65),("重庆", 66),
    ("台州", 67),("南京", 67),("滨州", 70),("贵阳", 71),("无锡", 71),("本溪", 71),
    ("克拉玛依", 72),("渭南", 72),("马鞍山", 72),("宝鸡", 72),("焦作", 75),("句容", 75),
    ("北京", 79),("徐州", 79),("衡水", 80),("包头", 80),("绵阳", 80),("乌鲁木齐", 84),
    ("枣庄", 84),("杭州", 84),("淄博", 85),("鞍山", 86),("溧阳", 86),("库尔勒", 86),
    ("安阳", 90),("开封", 90),("济南", 92),("德阳", 93),("温州", 95),("九江", 96),
    ("邯郸", 98),("临安", 99),("兰州", 99),("沧州", 100),("临沂", 103),("南充", 104),
    ("天津", 105),("富阳", 106),("泰安", 112),("诸暨", 112),("郑州", 113),("哈尔滨", 114),
    ("聊城", 116),("芜湖", 117),("唐山", 119),("平顶山", 119),("邢台", 119),("德州", 120),
    ("济宁", 120),("荆州", 127),("宜昌", 130),("义乌", 132),("丽水", 133),("洛阳", 134),
    ("秦皇岛", 136),("株洲", 143),("石家庄", 147),("莱芜", 148),("常德", 152),("保定", 153),
    ("湘潭", 154),("金华", 157),("岳阳", 169),("长沙", 175),("衢州", 177),("廊坊", 193),
    ("菏泽", 194),("合肥", 229),("武汉", 273),("大庆", 279)]

geo = Geo(
    "全国主要城市空气质量",
    "data from pm2.5",
    title_color="#fff",
    title_pos="center",
    width=1200,
    height=600,
    background_color="#404a59",
)
attr, value = geo.cast(data)
geo.add(
    "",
    attr,
    value,
    visual_range=[0, 200],
    visual_text_color="#fff",
    symbol_size=15,
    is_visualmap=True,
)
geo.render(path='./results/13.地图1.html')

geo = Geo(
    "全国主要城市空气质量",
    "data from pm2.5",
    title_color="#fff",
    title_pos="center",
    width=1200,
    height=600,
    background_color="#404a59",
)
attr, value = geo.cast(data)
geo.add(
    "",
    attr,
    value,
    visual_range=[0, 200],
    visual_text_color="#fff",
    symbol_size=15,
    is_visualmap=True,
    is_piecewise=True,
    visual_split_number=6,
)
geo.render(path='./results/13.地图2.html')

geo = Geo(
    "全国主要城市空气质量",
    "data from pm2.5",
    title_color="#fff",
    title_pos="center",
    width=1200,
    height=600,
    background_color="#404a59",
)
attr, value = geo.cast(data)
geo.add(
    "",
    attr,
    value,
    type="heatmap",
    is_visualmap=True,
    visual_range=[0, 300],
    visual_text_color="#fff",
)
geo.render(path='results/13.地图3.html')

image-20200417110234668

image-20200417110313352

14.地图2

from pyecharts import Geo

data = [
    ("海门", 9), ("鄂尔多斯", 12), ("招远", 12), ("舟山", 12), ("齐齐哈尔", 14), ("盐城", 15)
]
geo = Geo(
    "全国主要城市空气质量",
    "data from pm2.5",
    title_color="#fff",
    title_pos="center",
    width=1200,
    height=600,
    background_color="#404a59",
)
attr, value = geo.cast(data)
geo.add("", attr, value, type="effectScatter", is_random=True, effect_scale=5)
geo.render(path='results/14.地图1.html')

image-20200417110655612

15. 广东空气质量

from pyecharts import Geo

data = [("汕头市", 50), ("汕尾市", 60), ("揭阳市", 35), ("阳江市", 44), ("肇庆市", 72)]
geo = Geo(
    "广东城市空气质量",
    "data from pm2.5",
    title_color="#fff",
    title_pos="center",
    width=1200,
    height=600,
    background_color="#404a59",
)
attr, value = geo.cast(data)
geo.add(
    "",
    attr,
    value,
    maptype="广东",
    type="effectScatter",
    is_random=True,
    effect_scale=5,
    is_legend_show=True,
    
)
geo.render(path='results/15.广东空气质量.html')

image-20200417111143807

16.英国空气质量

from pyecharts import Geo

data = [("Oxford", 15), ("London", 12)]

geo = Geo(
    "英国主要城市空气质量",
    "data from pm2.5",
    title_color="#fff",
    title_pos="center",
    background_color="#404a59",
)
attr, value = geo.cast(data)
geo.add_coordinate('Oxford', 51.7520209,-1.2577263000000585)
geo.add_coordinate('London', 51.5073509,-0.12775829999998223)
geo.add(
    "",
    attr,
    value,
    maptype="英国",
    # 使用 coordinate_region,指定检索英国范围内的坐标,如上述的 Oxford。
    # 默认为中国
    coordinate_region="英国",
    visual_range=[0, 200],
    visual_text_color="#fff",
    symbol_size=15,
    is_visualmap=True,
)

geo.render(path='results/16.英国空气质量.html')

image-20200417111719680

17. 地理坐标系

from pyecharts import GeoLines, Style

style = Style(
    title_top="#fff",
    title_pos = "center",
    width=1200,
    height=600,
    background_color="#404a59"
)

data_guangzhou = [
    ["广州", "上海"],
    ["广州", "北京"],
    ["广州", "南京"],
    ["广州", "重庆"],
    ["广州", "兰州"],
    ["广州", "杭州"]
]
geolines = GeoLines("GeoLines 示例", **style.init_style)
geolines.add("从广州出发", data_guangzhou, is_legend_show=False)
geolines.render(path='results/17.地理坐标.html')

image-20200417111704740

18. 关系图

from pyecharts import Graph

nodes = [{"name": "结点1", "symbolSize": 10},
         {"name": "结点2", "symbolSize": 20},
         {"name": "结点3", "symbolSize": 30},
         {"name": "结点4", "symbolSize": 40},
         {"name": "结点5", "symbolSize": 50},
         {"name": "结点6", "symbolSize": 40},
         {"name": "结点7", "symbolSize": 30},
         {"name": "结点8", "symbolSize": 20}]
links = []
for i in nodes:
    for j in nodes:
        links.append({"source": i.get('name'), "target": j.get('name')})
graph = Graph("关系图-力引导布局示例")
graph.add("", nodes, links, repulsion=8000)
graph.render(path='results/18.关系图.html')

image-20200419150909132

19. 微博转发关系图

from pyecharts import Graph
import os
import json
with open(os.path.join("data", "weibo-1.json"), "r", encoding="utf-8") as f:
    j = json.load(f)
    nodes, links, categories, cont, mid, userl = j
graph = Graph("微博转发关系图", width=1200, height=600)
graph.add(
    "",
    nodes,#节点
    links,#不同点之间连线
    categories,#分类
    label_pos="right",#标签位置 右侧
    graph_repulsion=50,#不同点之间斥力
    is_legend_show=False,#是否显示图例
    line_curve=0.2,#线条玩去程度
    label_text_color=None,#标签文本颜色
)
graph.render(path='results/19.微博转发关系图.html')

image-20200419150807754

20. 广东地图

from pyecharts import Map

value = [20, 190, 253, 77, 65]
attr = ['汕头市', '汕尾市', '揭阳市', '阳江市', '肇庆市']
map = Map("广东地图示例", width=1200, height=600)
map.add(
    "", attr, value, maptype="广东", is_visualmap=True, visual_text_color="#000"
)
map.render(path='results/20.广东地图.html')

image-20200419152943825

21. 世界地图

from pyecharts import Map
value = [95.1, 23.2, 43.3, 66.4, 88.5]
attr= ["China", "Canada", "Brazil", "Russia", "United States"]
map = Map("世界地图示例", width=1200, height=600)
map.add(
    "",
    attr,
    value,
    maptype="world",
    is_visualmap=True,
    visual_text_color="#000",
)
map.render(path='results/21.世界地图.html')

image-20200419152953650

七、时间数据可视化

1、连续型数据处理

阶梯图

阶梯图是曲线保持在同一个值,直到发生变化,直接跳跃到下一个值。它的形状就类似于平时楼道里面的楼梯。比如说,银行的利率,它一般会持续几个月不变,然后某一天出现上调或下调。楼盘价格长时间停留在某个值,突然有一天因为各种调控,出现调整。对于这类的数据类型就可以使用阶梯图

如何使用Python画出阶梯图,这里用的是pyecharts模块,图形3-3展示的就是最终的图表。它表现的是美国邮政投递信件的资费变化图。注意一点,这里的变化不是定期变化的。这里可以看出1995-1999是4年没发生变化,但是2006-2009就是每年涨一次。

代码:

from pyecharts import Line
line = Line("美国邮票阶梯图")
datax=[1995,1996,1997,1998,1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009]
datay = [0.32,0.32,0.32,0.32,0.33,0.33,0.34,0.37,0.37,0.37,0.37,0.39,0.41,0.42,0.44]
line.add("Price",datax, datay, is_step=True,is_label_show=True,
yaxis_min=0.3,yaxis_max=0.45)
line.render()

image-20200411234927229

上述代码功能是这样的,事先数据准备,这里用2个列表存储数据datax存储的事时间数据,datay存储的是邮费数据。如果数据量大的话可以用文件存数据,下面3.2.2会涉及到,这里就不加概述。最后用pyecharts. Line来画这个梯形图,另外如果将line.add()函数中的is_step去掉就是呈现的一个折线图

折线图

折线图是用直线段将各数据点连接起来而组成的图形,以折线方式显示数据的变化趋势。在时间数据中,折线图的沿水平轴均匀分布的是时间,沿垂直轴均匀分布的是所有值数据。折线图比较适用于趋势类的需求。常用于,人口增长趋势,书籍销售量,粉丝增长进度等等

如何在python中创建时间序列的折线图,这里使用了画图包的里的另一个matplotlib模块,下面就举例讲解下。首先基础数据的准备,这里是从网站(http://datasets.flowingdata.com/world-population.csv)下载了一个每年世界人口的数据统计。然后载入数据

代码:

import csv
import matplotlib.pyplot as plt
filename = "data/world-population.csv"
datax = []
datay = []
with open(filename) as f:
    reader = csv.reader(f)
    for datarow in reader:
        if reader.line_num != 1:
            print(reader.line_num,datarow)
            datax.append(datarow[0])
            datay.append(datarow[1])
plt.plot(datax,datay)
plt.show()

image-20200411171018213

拟合曲线

拟合曲线是根据所给定的离散数据点绘制的曲线,称为不规则曲线。实际工作中,变量间未必都有线性关系,曲线拟合是指选择适当的曲线类型来拟合观测数据,并用拟合的曲线方程分析两变量间的关系。所谓曲线拟合方法是由给定的离散数据点,建立数据关系(数学模型),求出一系列微小的直线段把这些插值点连接成曲线,只要插值点的间隔选择得当,就可以形成一条光滑的曲线。比如获取的数据很多,或者数据很杂乱,可能很难甚至无法辨认出其中的发展趋势和模式。所以为了估算出一条趋势,从而就用到拟合估算

代码:

import numpy as np
import matplotlib.pyplot as plt
import csv
import sys
filename = "unemployment-rate-1948-2010.csv"
xa = []
ya = []
try:
    with open(filename) as f:
        reader = csv.reader(f)
        for datarow in reader:
            if reader.line_num != 1:
                ya.append(float(datarow[3]))
                xa.append(int(datarow[1]))
except csv.Error:
    print("Error reading csv file")
    sys.exit(-1)
plt.figure()
plt.scatter(xa[:], ya[:], s=10,c='g',marker='o',alpha=0.5)
poly = np.polyfit(xa, ya, deg = 3)  
plt.plot(xa, np.polyval(poly, xa))  
plt.show()

image-20200411171346827

2、离散型数据处理

散点图

散点图,顾名思义就是由一些散乱的点组成的图表。值由点在图表中的位置表示。在时间数据中,水平轴表示时间,数值则在垂直轴上。散点图用位置作为视觉线索。如果将图表区域比做一个盘子,那么这些散图的点就是“大珠小珠落玉盘”,有如一颗颗繁星,分布在广袤的天空。在比较的效果中,散点图包含的数据越多,效果越好

这类图形就是散点图,特点是能直观表现出影响因素和预测对象之间的总体关系趋势。优点是能通过直观醒目的图形方式反映变量间关系的变化形态,以便决定用何种数学表达方式来模拟变量之间的关系。这里使用的从此网站(http://datasets.flowingdata.com/flowingdata_subscribers.csv)下载的数据源,关于FlowingData网站于2010年1月计算的订阅者的数量,最后得出的图表

这个散点图呈现的是上升的趋势,但是在1月的中旬的时候突然下降很大,这个数据就有可能是数据报告出现错误。散点图不仅可传递变量间关系类型的信息,也能反映变量间关系的明确程度。python代码实现如下:

import pandas as pd
from matplotlib import pyplot as plt
subscriber=pd.read_csv("data/flowingdata_subscribers.csv")
fig,ax=plt.subplots()
time=[pd.to_datetime(i) for i in subscriber["Date"]]
ax.plot(time,subscriber["Subscribers"],"o",color="blue")
ax.set(xlabel="Date",ylabel="Number of subsribers")
ax.set_title("Growth of subscribers --- Jan 2010")
ax.annotate("2 days where \nit went wrong",xy=(0.43,0.06),xycoords='axes fraction',\
            xytext=(0.56,0.1),textcoords='axes fraction',\
            arrowprops=dict(facecolor='black', shrink=0.05))
ax.annotate("25047",xy=(0.046,0.8),xycoords='axes fraction',\
            xytext=(0.004,0.68),textcoords='axes fraction',\
            arrowprops=dict(arrowstyle="-"))
ax.annotate("27611\n(+10%)",xy=(0.955,0.92),xycoords='axes fraction',\
            xytext=(0.905,0.76),textcoords='axes fraction',\
            arrowprops=dict(arrowstyle="-"))
ax.spines["left"].set_visible(False)
ax.spines["right"].set_visible(False)
ax.spines["top"].set_visible(False)
plt.show()

柱形图

柱形图又称条形图、直方图,是以宽度相等的条形高度或长度的差异来显示统计指标数值多少或大小的一种图形。柱形图简明、醒目,是一种常用的统计图形。图3-11显示了其基本框架。

柱形图一般用于显示一段时间内的数据变化或显示各项之间的比较情况。另外,数值的体现就是柱形的高度。柱形越矮数值越小,柱形越高数值越大。还有柱形的宽度与相邻柱形间的间距决定了整个柱形图的视觉效果是否美观。如果柱形的宽度小于间距的话,则会给读者在读表的时候注意力集中在空白处而忽略了数据。所以合理的选择宽度很重要。下面讲个简单的列子说明下怎么在python中创建柱形图。数据来源(http://datasets.flowingdata.com/ hot-dog-contest-winners.csv),过去30年的热狗大胃王的比赛结果。最终图表如图3-12所示。

image-20200411234953329

                            图3-12  大胃王比赛成绩的柱形图

从图表所示,获胜者从最初的10个左右到后面60左右,可以看出差不多是增长的趋势。具体的python程序如下。

from pyecharts import Bar, Scatter3D
from pyecharts import Page
import csv
page = Page()

bar = Bar("柱状图数据堆叠示例")
filename = "data/hot-dog-contest-winners.csv"
datax = []
datay = []
with open(filename) as f:
    reader = csv.reader(f)
    for datarow in reader:
        if reader.line_num != 1:
            datay.append(datarow[2])
            datax.append(datarow[0])
bar.add("A", datax, datay, is_stack=True)
page.add(bar)
page.render()

堆叠柱形图

堆叠柱形图的几何形状和常规柱形图很相似,在柱形图中,数据值为并行排列,而在堆叠柱图则是一个个叠加起来的。它的特点就是如果数据存在子分类,并且这些子分类相加有意义的话,此时就可以使用堆叠柱形图来表示。

堆叠柱形图也是一个使用频繁的一个图标类型,这里使用python实现。也是先载入源数据,(http://datasets.flowingdata.com/hot-dog-places.csv)下载数据然后画图。图表如图3-14所示。

image-20200411235005295

                         图3-14  热狗大胃王的堆叠柱形图

源数据是一个热狗大胃王比赛,这里没有只关注冠军的数据,而是关注了前三名的选手数据。所以每一个柱形就包含三个子柱形,每个子柱形就表示前三名的其中一名选手的数据。python的实现代码如下,这里是将源数据事先下载到本地目录,直接读取的,也可以直接通过url获取,这里就不概述了。

from pyecharts import Bar, Scatter3D
from pyecharts import Page
import csv
page = Page()
bar = Bar("柱状图数据堆叠示例")
filename = "data/hot-dog-places.csv"
datax = []
datay = []
with open(filename) as f:
     reader = csv.reader(f)
     for datarow in reader:
         datax.append(datarow)
x= datax[0]
y1=datax[1]
y2=datax[2]
y3=datax[3]
bar.add("A", x, y1, is_stack=True)
bar.add("B", x, y2, is_stack=True)
bar.add("c", x, y2, is_stack=True)
page.add(bar)
page.render()

八、比例数据可视化

比例数据介绍

对于比例,我们通常想要得到最大值、最小值和总体分布。前两者比较简单,将数据由小到大进行排列,位于两端的分别就是最小值和最大值。对于投票选举结果的处理,那么它们就分别代表了得票最少的被选举人和得票最多的被选举人。如果你绘制了食物各部分的卡路里含量图,那么就会看到哪部分的卡路里最少,哪部分的卡路里含量最多。

其实,对于最小值和最大值我们没有必要用图表来展现。我们真正所感兴趣的应该是比例的分配。投票选举中某个被选举人与其他被选举人有什么不同?脂肪、蛋白质、碳水化合物都含有同样的卡路里吗?是不是存在某一种卡路里含量占绝大多数?

饼图

饼图采用了饼干的隐喻,用环状方式呈现各分量在整体中的比例。这种分块方式是环状树图等可视化表达的基础。饼图是非常常见的,常用于统计学模型。

饼图的原理也是很简单的。如图4-1所示,首先一个圆代表了整体,然后把它们切成楔形,每一个楔形都代表整体中的一部分。所有楔形所占百分比的总和应该等于100%,如果不等,那就表明出错了。

有些人可能不太喜欢使用饼图,因为它不太擅于对数据精确的表示,所以他们认为饼图对数据可视化并没有很好的效果。确实,饼图没有体现精确的数据,但是饼图可以呈现各部分在整体中的比列,能够体现部分与整体之间的关系。那如果我们抓住饼图的这一优点,良好的组织数据,饼图对于数据的可视化还是有帮助的。

创建饼图:

代码:

from pyecharts import Pie
import pandas as pd
vote_result = pd.read_csv('data/vote_result.csv')
pie = Pie("数据可视化-用户感兴趣领域",
          "以下是读者的投票结果。\n"
          "读者对金融、医疗保健、市场业3个领域最感兴趣。",title_pos='left')
#pie = Pie("饼图示例")
pie.add("", vote_result['Areas_of_interest'], vote_result['Votes'], center=[60, 60],legend_orient="vertical",
    legend_pos="right",is_label_show=True)
#pie.add("", vote_result['Areas_of_interest'], vote_result['Votes'],is_legend_show=False,is_label_show=True)
#pie.add("", vote_result['Areas_of_interest'], vote_result['Votes'], is_label_show=False)
pie.render('饼图.html')

截图

image-20200412113554468

环形图

代码:

from pyecharts import Pie
import pandas as pd

vote_result = pd.read_csv('data/vote_result.csv')
pie = Pie("数据可视化-用户感兴趣领域",
          "以下是读者的投票结果。\n"
          "读者对金融、医疗保健、市场业3个领域最感兴趣。",title_pos='left')
pie.add("", vote_result['Areas_of_interest'], vote_result['Votes'], center=[60, 60],legend_orient="vertical",
radius=[30, 75],legend_pos="right",is_label_show=True)
pie.render('2.环形图.html')

截图:

image-20200412114626708

堆叠柱形图

代码:

from pyecharts import Bar
import pandas as pd
pre_approval_rate = pd.read_csv('data/presidential_approval_rate.csv')
bar = Bar("柱状图数据堆叠示例")
bar.add("支持", pre_approval_rate['political_issue'], pre_approval_rate['support'], is_stack=True)
bar.add("反对", pre_approval_rate['political_issue'], pre_approval_rate['oppose'], is_stack=True)
bar.add("不发表意见", pre_approval_rate['political_issue'], pre_approval_rate['no_opinion'],xaxis_rotate=30, is_stack=True)
bar.render('3.堆叠柱形图.html')


#另外一种写法
from pyecharts import Bar
import pandas as pd
pre_approval_rate = pd.read_csv('data/presidential_approval_rate.csv')
bar = Bar("柱状图数据堆叠示例",title_pos='center')
list_support = ['支持','反对','不发表意见']
for i in range(pre_approval_rate.iloc[:,0].size):
    issue = pre_approval_rate.loc[i,'political_issue']
    bar.add(issue, list_support, pre_approval_rate.loc[i,['support','oppose','no_opinion']], legend_orient="vertical",legend_pos="right",is_stack=True)
bar.render('3.2堆叠柱形图.html')

截图:

image-20200412114916503

树图

代码

import os
import json
import codecs
from pyecharts import Tree
with codecs.open(os.path.join("data", "GDP_data.json"), "r", encoding="utf-8") as f:
    j = json.load(f)
data = [j]
tree = Tree(width=1200, height=800)
tree.add("", data) #, tree_collapse_interval=2
tree.render('4.树图.html')

image-20200412115854439

矩形树图

# encoding:utf-8
import os
import json
from pyecharts import TreeMap
with open(os.path.join("data/GDP_data_1.json"),"r", encoding="utf-8") as f:
    data = json.load(f)
treemap = TreeMap("矩形树图示例", width= 1200, height=600)
treemap.add("演示数据", data, is_labelshow= True, label_pos='inside')
#,treemap_left depth=1
treemap.render('矩形树图.html')

image-20200415165659303

九、文本数据可视化

1.文本数据在大数据中的应用

鉴于人们对文本信息需求的多样性,我需要从不同层级提取与呈现文本信息。一般把对文本的理解需求分成三级:词汇级(Lexical Level)、
语法级(Syntactic Level)和语义级(Semantic Level)。不同级的信息挖掘方法也不同,词汇级是使用各类分词算法,而语法级使用句法
分析算法,语义级则是使用主题抽取算法。文本信息的类别多种多样,一般包括单文本、文档集合和时序文本数据三大类。针对文本信息的多样性,人们不仅提出多种普适性的可视化技术,并针对特定的分析需求研发了具有特性的可视化技术。

image-20200426083323028

2.文本信息分析

文本属于非结构化数据,不能直接用于可视化,需要使用向量符号将文本度量成数学模型。常用的将文本转化为向量的方法:
1、VSM(向量空间模型,vector space model)
2、主题抽取,如LDA( Latent Dirichlet Allocation,文档主题生成
模型 )、LSI(Latent Semantic Indexing,隐含语义检索模型)

2.1 VSM

向量空间模型是使用向量符号对文本进行度量的代数模型,把对文本内容的处理简化为向量空间中的向量运算,并且以空间相似度表达
语义相似度。
VSM的两大核心:
1、词袋模型
2、TF-idf度量

2.1.1 词袋模型

词袋模型(Bag of Words)指在信息检索中,将某一文本仅看作是一个词集合,而不考虑其语法、词序等信息。文本中每个词相互独立,不依赖于
其他词的出现与否。词袋模型是向量空间模型构造文本向量的常用方法之一,常用来提取词汇级文本信息。
词袋模型,就是忽略掉词序、语法和语句,过滤掉对文本内容影响较弱的词(停用词),将文本看作一系列关键词汇的集合所形成的向量,每个词
汇表示一个维度,维度的值就是该词汇在文档中出现的频率。

以Charles Dickens的《双城记》中的一段文字为例。
“It was the best of times, it was the worst of times, it was the age of wisdom,
it was the age of foolishness.”
根据词袋模型的概念,可以构建一个词袋,假设建立一个数组用于映射匹配:
[it、was、the、best、of、times、worst、age、wisdom、foolishness]
则上述四个句子可以用以下向量表示:
[1, 1, 1, 1, 1, 1, 0, 0, 0, 0]、 [1, 1, 1, 0, 1, 1, 1, 0, 0, 0]、 [1, 1, 1, 0, 1, 0, 0, 1, 1, 0]、
[1, 1, 1, 0, 1, 0, 0, 1, 0, 1]
这四个词频向量就是词袋模型,可以很明显的看到语序关系已经完全丢失。

2.1.2 TF-IDF

TF-IDF(Term Frequency-Inverse Document Frequency)是一种用于信息检索与数据挖掘的常用加权技术。
TF的含义是词频(Term Frequency),是一个词语在一篇文件中出现的次数除以该文件的总词语数。
IDF的含义是逆文本频率指数(Inverse Document Frequency)。即文本频率(DF)的倒数。DF指包含的某个词的文件个数除以该文档集里文件总数。

TF-IDF用于评估某个单词或字在一个文档集或语料库的重要程度。
TF-IDF的主要思想是:如果某个词或短语在一篇文章中出现的频率(TF)高,并且在其他文章中很少出现,则可认为此词或者短语具有很好的类别区
分能力,适合用来分类。也就是说,字词在某个文档的重要性与它在这个文档中出现的次数正相关,但同时也会随着它在文档集合中出现的频率增加而下降。

image-20200426085050826

image-20200426085113389

2.2 主题抽取

一个文档的语义内容可描述为多主题的组合表达,一个主题可认为是一系列字词的概率分布。
主题模型是对文字中隐含主题的一种建模方法,它从语义级别描述文档集中的各个文本信息。
文本主题的抽取算法大致可分为两类:基于贝叶斯的概率模型和基于矩阵分解的非概率模型。

1、概率模型:其主题被当成多个词项的概率分布,文档可以理解成由多个主题的组合而产生的。如LDA文本主题生成模型,是一个三层贝叶斯概率模
型,包含词、主题和文档三层结构。我们认为一篇文章的每个词都是通过“以一定概率选择了某个主题,并从这个主题中以一定概率选择某个词语”这样一个过程得到。文档到主题、主题到词服都从多项式分布。
2、非概率模型:它将词项-文档矩阵投影到K维空间中,每个维度代表一个主题。在主题空间中,每个文档由K个主题的线性组合来表示。如LSI ,是
基于主题间的正交性假设,采用SVD分解词项-文档矩阵的非概率模型。

3.文本信息可视化

文本数据可视化可以分为文本内容的可视化、文本关系的可视化以及文本多特征信息的可视化。
• 文本内容可视化是对文本内的关键信息分析后的展示;
• 文本关系的可视化既可以对单个文本进行内部的关系展示,也可以对多个文本进行文本之间的关系展示;
• 文本多特征信息的可视化,是结合文本的多个特征进行全方位的可视化展示。

3.1 文本内容可视化

文本的内容可以通过关键词、短语、句子和主题进行展现。
对于文本内容的可视化,主要体现在以下三方面:
• 关键词可视化
• 时序文本可视化
• 文本分布可视化

3.1.1 关键词可视化

一个词语若在一个文本中出现的频率较高,那么,这个词语就可能是这个文本的关键词,它可以在一定程度上反映出一个文本内容所要表
达的含义。
关键词可视化是用一个文本中的关键词来展示该文本的内容。常用
技术有:
• 标签云(tag cloud)
• 文档散( DocuBurst )

关键词可视化——标签云

标签云(Tag Clould)是一种最常见的、简单的关键词可视化方法,主要可分为如下两步。
① 统计文本中词语的出现频率,提取出现频率较高的关键词。
② 按照一定的顺序和规律将这些关键词展示出来。例如,用颜色的深浅,或者字体的大小,来区分关键词的重要性。

关键词可视化——文档散
文档散(DocuBurst)是由多伦多大学的Christopher Collins教授制作的一个在线文本分析可视化工具,通过导入TXT格式的文本数据,
生成HTML格式的可视化图片。文档散使用词汇库中的结构关系来布局关键词,同时使用词语关系网中具有上下语义关系的词语来布局关键词,从而揭示文本中的内容。上下语义关系是指词语之间往往存在语义层级的关系,也就是说,一些词语是某些词语的下义词。而在一篇文章中,具有上下语义关系的词语一般是同时存在的。

image-20200426090742987

3.1.2 时序文本可视化

时序文本的特性就是具有时间性和顺序性,比如,新闻会随着时间
变化,小说的故事情节会随着时间变化。
时序文本可视化常用技术有:
• 主题河流(ThemeRiver)
• 文本流(TextFlow)
• 故事流(StoryFlow)

主题河流(ThemeRiver)是由Susan Havre等学者于2000年提出的一种时序数据可视化方法,主要用于反映文本主题强弱变化的过程。
经典的主题河流模型包括以下两个属性。
① 颜色,表示主题的类型,一个主题用一个单一颜色的涌流表示。但是,颜色种类有限,若使用一种颜色表示一个主题,则会限制主题的数量,因此,可以使用一种颜色表示一类主题。
② 宽度,表示主题的数量(或强度),涌流的状态随着主题的变化,可能扩展、收缩或者保持不变。

image-20200426090852890

image-20200426090909957

image-20200426090929207

3.1.3 文本分布可视化

前面的文档数据可视化方法都是通过关键词、文本主题来总结文本内容,但是文档中的其他特征,如词语的分布情况、句子的平均长度、
词汇量等并没有展示出来。
体现文本分布的可视化方法有:
• 文本弧(TextArc)
• 文献指纹(Literature Fingerprinting)

文本分布可视化——文本弧
文本弧(TextArc)可视化技术不仅可以展示词频,还可以展示词的分布情况。文本弧的特性如下:
① 用一条螺旋线表示一篇文章,螺旋线的首尾对应着文章的首尾,文章的词语有序地布局在螺旋线上。
② 若词语在整片文章中出现都比较频繁,则靠近画布的中心分布。
③ 若词语只是局部出现得比较频繁,则靠近螺旋线分布。
④ 字体的大小和颜色深度代表着词语的出现频率

image-20200426091033087

文本分布可视化——文献指纹
文献指纹(Literature Fingerprinting)是体现全文特征分布的一项工作。一个像素块代表一段文本,一组像素块代表一本书。颜色映射的是文本特征,如使用句子的平均长度进行颜色映射。

image-20200426091101932

3.2 文本关系可视化

文本关系包括文本内或者文本间的关系,以及文本集合之间的关系,比如文本的相似性、互相引用的情况、链接等。文本关系可
视化的目的就是呈现出这些关系。
• 文本内的关系有词语的前后关系;
• 文本间的关系有网页之间的超链接关系,文本之间内容的相似性,文本之间的引用等;
• 文本集合之间的关系是指文本集合内容的层次性等关系。

3.2.1 文本内容关系可视化

文本内容关系可视化经常采用的是基于图的方式进行可视化,如词语树(word tree)、网络短语(phrase nets)、矩阵树图(NewsMap)等。

文本内容关系可视化——word tree
词语树(Word Tree)使用树形图展示词语在文本中的出现情况,可以直观地呈现出一个词语和其前后的词语。用户可自定义感兴趣的词语作为中心节点。中心节点向前扩展,就是文本中处于该词语前面的词语;中心节点向后扩展,就是文本中处于该词语后面的词语。字号大小代表了词语在文本中出现的频率。

image-20200426094054394

文本内容关系可视化——phrase nets短语网络(Phrase Nets)包括以下两种属性。
① 节点,代表一个词语或短语。
② 带箭头的连线,表示节点与节点之间的关系,这个关系需要用户定义,比如,“A is B”,其中的is用连线表示,A和B是is前
后的两个节点词语。A在is前面,B在is后面,那么,箭头就由A指向B。连线的宽度越宽,就说明这个短语在文中出现的频率越高

image-20200426094142866

image-20200426094209618

3.2.2 文档间关系可视化
当对多个文档进行可视化展示时,针对文本内容做可视化的方法就不适合了。此时可以引入向量空间模型来计算出各个文档之间的相似性,
单个文档被定义成单个特征向量,最终以投影等方式来呈现各文档之间的关系。
文档间关系可视化的方法有:星系视图、文档集抽样投影、主题地貌(Theme map)等

文档间关系可视化——星系视图
星系视图(Galaxy View)可用于表征多个文档之间的相似性。假设一篇文档是一颗星星,每篇文档都有其主题,将所有文档按照主题投影到二维平面上,就如同星星在星系中一样。文档的主题越相似,星星之间的距离就越近;文档的主题相差越大,星星之间的距离就越远。星星聚集得越多,就表示这些文档的主题越相近,并且数量较多;若存在多个聚集点则说明文档集合中包含多种主题的文档。

image-20200426094319405

文档间关系可视化——文档集抽样投影
当一个文档集中包含的文档数量过大时,投影出来的星系视图中就会产生很多重叠的星星。为了避免这种重叠情况的出现,用户可以对文档集进行抽样,有选择性地抽取部分文档进行投影,这样可以更加清晰地显示每个样本。

文档间关系可视化——主题地貌
主题地貌(ThemeScape)是对星系图的改进。把等高线加入投影的二维平面中,文档相似性相同的放在一个等高线内,再用颜
色来编码文本分布的密集程度,把二维平面背景变成一幅地图,这样就把刚才星系图中的星团变成了一座座山丘。文档越相似,则分布约密集,这座山峰就越高。

image-20200509112441930

3.3 文本多特征信息可视化——平行标签云

平行标签云(Parallel Tag Clouds)结合了平行坐标(该视图在多维数据可视化中经常使用)和标签云视图。每一列是一个层面的标签云,然后连接的折线展现了选中标签在多个层面的分布。实质是将标签云在水平方向上基于多个不同的特征进行显示,每一个特征对应着一列标签云,列与列之间的特征都不一样。

文本多特征信息可视化——FaceAtlas
FaceAtlas 结合了气泡集和节点-链接图两种视图,用于表达文本各层面信息内部和外部的关联。每个节点表示一个实体,用 KDE 方法刻画出气泡图的轮廓,然后用线将同一层面的实体链接起来,一种颜色代表一种实体。

image-20200426094501934

image-20200426094830147

4.jieba分词

jieba.cut 方法接受三个输入参数: 需要分词的字符串;cut_all 参数用来控制是否采用全模式;HMM 参数用来控制是否使用 HMM 模型
# encoding=utf-8
import jieba

seg_list = jieba.cut("我来到北京清华大学", cut_all=True)
print("Full Mode: " + "/ ".join(seg_list))  # 全模式
# Full Mode: 我/ 来到/ 北京/ 清华/ 清华大学/ 华大/ 大学

seg_list = jieba.cut("我来到北京清华大学", cut_all=False)
print("Default Mode: " + "/ ".join(seg_list))  # 精确模式
# Default Mode: 我/ 来到/ 北京/ 清华大学

image-20200427085305879

停用词:

import jieba
content = 'I have a dream that one day \
this nation will rise up and live out the \
true meaning of its creed: "We hold these \
truths to be self-evident, that all men are created equal."'
seg_list = jieba.cut(content)
stopwords = ['a','the','that',' ','"',':','of','to','-',',','be','.','this','will','its','these','are','was','\n']
final=[]
for seg in seg_list:
    if seg not in stopwords:
        final.append(seg)
print(len(final),",".join(final))

import jieba
text ='''
"It was the best of times,
it was the worst of times,
it was the age of wisdom,
it was the age of foolishness."
'''
seg_list = jieba.cut(text.lower())
stopwords = ['a','the','that',' ','"',':','of',
             'to','-',',','be','.','this','will',
             'its','these','are','was','\n']
final=[]
for seg in seg_list:
    if seg not in stopwords:
        final.append(seg)
print(len(final),",".join(final))
word_dict = {}
for word in final:
    if word in word_dict:  # word已经出现过,将计数增加1
        word_dict[word] += 1
    else:  # word还没有出现过,创建新的键值对
        word_dict[word] = 1
print(word_dict)

image-20200427090008077

基于TF-IDF算法进行关键词抽取
jieba.analyse.extract_tags(sentence, topK=20, withWeight=False, allowPOS=())

sentence 为待提取的文本

topK 为返回几个 TF/IDF 权重最大的关键词,默认值为 20

withWeight 为是否一并返回关键词权重值,默认值为 False

allowPOS 仅包括指定词性的词,默认值为空,即不筛选
from jieba import analyse
# 引入TF-IDF关键词抽取接口
tfidf = analyse.extract_tags

# 原始文本
text = "线程是程序执行时的最小单位,它是进程的一个执行流,\
        是CPU调度和分派的基本单位,一个进程可以由很多个线程组成,\
        线程间共享进程的所有资源,每个线程有自己的堆栈和局部变量。\
        线程由CPU独立调度执行,在多CPU环境下就允许多个线程同时运行。\
        同样多线程也可以实现并发操作,每个请求分配一个线程来处理。"

# 基于TF-IDF算法进行关键词抽取
keywords = tfidf(text)
print("keywords by tfidf:") 
# 输出抽取出的关键词
for keyword in keywords:
    print(keyword ,end="/")

image-20200427091801856

5.wordcloud词云图

#coding=utf-8
import wordcloud
import matplotlib.pyplot as plt
w = wordcloud.WordCloud()
w.generate("President Xi Jinping and Premier \
           Li Keqiang sent condolence messages \
           on Sunday to their Sri Lankan \
           counterparts after multiple \
           deadly attacks shook the country.")
w.to_file(r'G:\pythonProject\pc\数据可视化\文本数据\results\result.png')
# 以下代码显示图片
plt.imshow(w)
plt.axis("off")
plt.show()

image-20200427094530621

import wordcloud
import matplotlib.pyplot as plt
w = wordcloud.WordCloud(font_path='simkai.ttf')
w.generate("使用 直方图 和 密度曲线 展现 世界 各国 的 出生率")
w.to_file(r'G:\pythonProject\pc\数据可视化\文本数据\results\result2.png')
# 以下代码显示图片
plt.imshow(w)
plt.axis("off")
plt.show()

image-20200427094719220

#Wordcloud自定义字体以支持中文,同时引入jieba中文分词
# -*- coding: utf-8 -*-
import matplotlib.pyplot as plt
from wordcloud import WordCloud, ImageColorGenerator, STOPWORDS
import jieba

# 读入背景图片
backgroud_Image = plt.imread(r'G:\pythonProject\pc\数据可视化\文本数据\data\love.jpg')
# 读取要生成词云的文件
text_from_file_with_apath = open("data/test.txt",encoding='utf-8').read()
# 通过jieba分词进行分词并通过空格分隔
wordlist_after_jieba = jieba.cut(text_from_file_with_apath, cut_all=False)
wl_space_split = " ".join(wordlist_after_jieba)
my_wordcloud = WordCloud(
    background_color='white',    # 设置背景颜色
    mask=backgroud_Image,        # 设置背景图片
    max_words=100,               # 设置最大显示的字数
    stopwords=STOPWORDS,         # 设置停用词
    ###########################################添加下面这行代码,同时百度,下载字体库到目录中
    font_path='simkai.ttf',# 设置字体格式,如不设置显示不了中文
#     max_font_size=40,            # 设置字体最大值
    random_state=300,     # 设置有多少种随机生成状态,即有多少种配色方案
    scale=5,              #按照比例进行放大画布
    width=1600,
    height=800
    ).generate(wl_space_split)

# 根据图片生成词云颜色
image_colors = ImageColorGenerator(backgroud_Image)
my_wordcloud.recolor(color_func=image_colors)
my_wordcloud.to_file('result.png')
# 以下代码显示图片
plt.imshow(my_wordcloud)
plt.axis("off")
plt.show()

image-20200427110025860

实验

1、词云图

add(name, attr, value,
    shape="circle",
    word_gap=20,
    word_size_range=None,
    rotate_step=45)
name -> str
图例名称
attr -> list
属性名称
value -> list
属性所对应的值
shape -> list
词云图轮廓,有'circle', 'cardioid', 'diamond', 'triangle-forward', 'triangle', 'pentagon', 'star'可选
word_gap -> int
单词间隔,默认为 20。
word_size_range -> list
单词字体大小范围,默认为 [12, 60]。
rotate_step -> int
旋转单词角度,默认为 45

代码:

from pyecharts import WordCloud
name = [
    'Sam S Club', 'Macys', 'Amy Schumer', 'Jurassic World', 'Charter Communications',
    'Chick Fil A', 'Planet Fitness', 'Pitch Perfect', 'Express', 'Home', 'Johnny Depp',
    'Lena Dunham', 'Lewis Hamilton', 'KXAN', 'Mary Ellen Mark', 'Farrah Abraham',
    'Rita Ora', 'Serena Williams', 'NCAA baseball tournament', 'Point Break']
value = [
    10000, 6181, 4386, 4055, 2467, 2244, 1898, 1484, 1112,
    965, 847, 582, 555, 550, 462, 366, 360, 282, 273, 265]

wordcloud = WordCloud(width=1300, height=620)
wordcloud.add("", name, value, word_size_range=[20, 100])
wordcloud.render(path="1.2词云图.html")

image-20200412160950726

第二种用pandas,主要提取两列数据

image-20200412161326881

from pyecharts import WordCloud
import pandas as pd
post_data = pd.read_csv('data/post_data.csv')
wordcloud = WordCloud(width=1300, height=620)
post_data2=post_data.groupby(by=['category']).agg({'views':sum}).reset_index()
wordcloud.add("", post_data2['category'], post_data2['views'], word_size_range=[20, 100])
wordcloud.render(path="1.词云图.html")

image-20200412161237689

2、主题河流

代码

from pyecharts import ThemeRiver

data = [
    ['2015/11/08', 10, '分支1'], ['2015/11/09', 15, '分支1'], ['2015/11/10', 35, '分支1'],
    ['2015/11/14', 7, '分支1'], ['2015/11/15', 2, '分支1'], ['2015/11/16', 17, '分支1'],
    ['2015/11/17', 33, '分支1'], ['2015/11/18', 40, '分支1'], ['2015/11/19', 32, '分支1'],
    ['2015/11/20', 26, '分支1'], ['2015/11/21', 35, '分支1'], ['2015/11/22', 40, '分支1'],
    ['2015/11/23', 32, '分支1'], ['2015/11/24', 26, '分支1'], ['2015/11/25', 22, '分支1'],
    ['2015/11/08', 35, '分支2'], ['2015/11/09', 36, '分支2'], ['2015/11/10', 37, '分支2'],
    ['2015/11/11', 22, '分支2'], ['2015/11/12', 24, '分支2'], ['2015/11/13', 26, '分支2'],
    ['2015/11/14', 34, '分支2'], ['2015/11/15', 21, '分支2'], ['2015/11/16', 18, '分支2'],
    ['2015/11/17', 45, '分支2'], ['2015/11/18', 32, '分支2'], ['2015/11/19', 35, '分支2'],
    ['2015/11/20', 30, '分支2'], ['2015/11/21', 28, '分支2'], ['2015/11/22', 27, '分支2'],
    ['2015/11/23', 26, '分支2'], ['2015/11/24', 15, '分支2'], ['2015/11/25', 30, '分支2'],
    ['2015/11/26', 35, '分支2'], ['2015/11/27', 42, '分支2'], ['2015/11/28', 42, '分支2'],
    ['2015/11/08', 21, '分支3'], ['2015/11/09', 25, '分支3'], ['2015/11/10', 27, '分支3'],
    ['2015/11/11', 23, '分支3'], ['2015/11/12', 24, '分支3'], ['2015/11/13', 21, '分支3'],
    ['2015/11/14', 35, '分支3'], ['2015/11/15', 39, '分支3'], ['2015/11/16', 40, '分支3'],
    ['2015/11/17', 36, '分支3'], ['2015/11/18', 33, '分支3'], ['2015/11/19', 43, '分支3'],
    ['2015/11/20', 40, '分支3'], ['2015/11/21', 34, '分支3'], ['2015/11/22', 28, '分支3'],
    ['2015/11/14', 7, '分支4'], ['2015/11/15', 2, '分支4'], ['2015/11/16', 17, '分支4'],
    ['2015/11/17', 33, '分支4'], ['2015/11/18', 40, '分支4'], ['2015/11/19', 32, '分支4'],
    ['2015/11/20', 26, '分支4'], ['2015/11/21', 35, '分支4'], ['2015/11/22', 40, '分支4'],
    ['2015/11/23', 32, '分支4'], ['2015/11/24', 26, '分支4'], ['2015/11/25', 22, '分支4'],
    ['2015/11/26', 16, '分支4'], ['2015/11/27', 22, '分支4'], ['2015/11/28', 10, '分支4'],
    ['2015/11/08', 10, '分支5'], ['2015/11/09', 15, '分支5'], ['2015/11/10', 35, '分支5'],
    ['2015/11/11', 38, '分支5'], ['2015/11/12', 22, '分支5'], ['2015/11/13', 16, '分支5'],
    ['2015/11/14', 7, '分支5'], ['2015/11/15', 2, '分支5'], ['2015/11/16', 17, '分支5'],
    ['2015/11/17', 33, '分支5'], ['2015/11/18', 40, '分支5'], ['2015/11/19', 32, '分支5'],
    ['2015/11/20', 26, '分支5'], ['2015/11/21', 35, '分支5'], ['2015/11/22', 4, '分支5'],
    ['2015/11/23', 32, '分支5'], ['2015/11/24', 26, '分支5'], ['2015/11/25', 22, '分支5'],
    ['2015/11/26', 16, '分支5'], ['2015/11/27', 22, '分支5'], ['2015/11/28', 10, '分支5'],
    ['2015/11/08', 10, '分支6'], ['2015/11/09', 15, '分支6'], ['2015/11/10', 35, '分支6'],
    ['2015/11/11', 38, '分支6'], ['2015/11/12', 22, '分支6'], ['2015/11/13', 16, '分支6'],
    ['2015/11/14', 7, '分支6'], ['2015/11/15', 2, '分支6'], ['2015/11/16', 17, '分支6'],
    ['2015/11/17', 33, '分支6'], ['2015/11/18', 4, '分支6'], ['2015/11/19', 32, '分支6'],
    ['2015/11/20', 26, '分支6'], ['2015/11/21', 35, '分支6'], ['2015/11/22', 40, '分支6'],
    ['2015/11/23', 32, '分支6'], ['2015/11/24', 26, '分支6'], ['2015/11/25', 22, '分支6']
]
colors_list=['#FFA07A','#32CD32','#4169E1','#FAA460','#F0E68C','#8c564b','#e377c2','#7f7f7f','#bcbd22','#17becf']#备用颜色列表
tr = ThemeRiver("主题河流图示例图")
tr.add(['分支1', '分支2', '分支3', '分支4', '分支5', '分支6'], data, is_label_show=False,label_color=colors_list)
tr.render(path="2.主题河流.html")

image-20200412161451940

3、关系图

from pyecharts import Graph

nodes = [{"name": "结点1", "symbolSize": 10},
         {"name": "结点2", "symbolSize": 20},
         {"name": "结点3", "symbolSize": 30},
         {"name": "结点4", "symbolSize": 40},
         {"name": "结点5", "symbolSize": 50},
         {"name": "结点6", "symbolSize": 40},
         {"name": "结点7", "symbolSize": 30},
         {"name": "结点8", "symbolSize": 20}]
links = []
for i in nodes:
    for j in nodes:
        links.append({"source": i.get('name'), \
                      "target": j.get('name')})
graph = Graph("关系图-力引导布局示例")
graph.add("", nodes, links, repulsion=8)
graph.render()
graph

image-20200427093047055

graph = Graph("关系图-环形布局示例")
graph.add(
    "",
    nodes,
    links,
    is_label_show=True,
    graph_repulsion=8000,
    graph_layout="circular",
    label_text_color=None,
)
# graph.render()
# graph

image-20200427093125526

微博转发关系图

from pyecharts import Graph
import os
import json
with open(os.path.join("data", "weibo-2.json"), "r", encoding="utf-8") as f:
    j = json.load(f)
    #print(j)
    nodes, links, categories, cont, mid, userl = j
    #这种写法可以参考
    #print(mid)
graph = Graph("微博转发关系图", width=1200, height=600)
graph.add(
    "",
    nodes,
    links,
    categories,
    label_pos="right",
    graph_repulsion=50,
    is_legend_show=False,
    line_curve=0.2,
    label_text_color=None,
)
graph.render(path="3.关系图.html")

image-20200412162953933

十、多元变量及数据分布可视化

1、多元变量及数据分布常用图形

  • 少数变量
    • 相关性——因果性,相似但不一定相同
  • 多元变量
    • 多个变量直接存在正相关行、负相关行和弱相关性
    • 正相关:线条呈现平行
    • 负相关:线条一直交叉(顶端与底端相连)
    • 弱相关:方向不清晰
  • 数据分布
    • 通过不同的图表(例如:散点图、柱状图)来观察数据分布
    • 箱线图
      img
      • 上四分位数于下四分位数之间的范围称为四分位间距

2、数据可视化交互

2018年北京AQI全年走势图

代码:

import pandas as pd
from pyecharts import Line

df = pd.read_csv('data/beijing_AQI_2018.csv')
attr = df['Date']
v1 = df['AQI']
line = Line("2018年北京AQI全年走势图", title_pos='center', title_top='18', width=800, height=400)
line.add("AQI值:", attr, v1, mark_line=['average'], is_fill=True, area_color="#000", area_opacity=0.3, mark_point=["max", "min"], mark_point_symbol="circle", mark_point_symbolsize=25)
line.render("2018年北京AQI全年走势图.html")

image-20200412171224112

2018年北京PM2.5基本走势图

代码:

import pandas as pd
from pyecharts import Line

df = pd.read_csv('data/beijing_AQI_2018.csv')
attr = df['Date']
v1 = df['PM']
line = Line("2018年北京PM2.5全年走势图", title_pos='center', title_top='18', width=800, height=400)
line.add("PM2.5值:", attr, v1, mark_line=['average'], is_fill=True, area_color="#000", area_opacity=0.3, mark_point=["max", "min"], mark_point_symbol="circle", mark_point_symbolsize=25)
line.render("2018年北京PM2.5全年走势图.html")

image-20200412171524711

2018年北京月均AQI走势图

import numpy as np
import pandas as pd
from pyecharts import Line

df = pd.read_csv('data/beijing_AQI_2018.csv')
dom = df[['Date', 'AQI']]
list1 = []
for j in dom['Date']:
    time = j.split('/')[1]
    list1.append(time)
df['month'] = list1

month_message = df.groupby(['month'])
month_com = month_message['AQI'].agg(['mean'])
month_com.reset_index(inplace=True)
month_com_last = month_com.sort_index()

attr = ["{}".format(str(i) + '月') for i in range(1, 13)]
v1 = np.array(month_com_last['mean'])
v1 = ["{}".format(int(i)) for i in v1]

line = Line("2018年北京月均AQI走势图", title_pos='center', title_top='18', width=800, height=400)
line.add("AQI月均值", attr, v1, mark_point=["max", "min"])
line.render("2018年北京月均AQI走势图.html")

image-20200412172605181

2018年北京月均PM2.5走势图

import numpy as np
import pandas as pd
from pyecharts import Line

df = pd.read_csv('data/beijing_AQI_2018.csv')

dom = df[['Date', 'PM']]
list1 = []
for j in dom['Date']:
    time = j.split('/')[1]
    list1.append(time)
df['month'] = list1

month_message = df.groupby(['month'])
month_com = month_message['PM'].agg(['mean'])
month_com.reset_index(inplace=True)
month_com_last = month_com.sort_index()

attr = ["{}".format(str(i) + '月') for i in range(1, 13)]
v1 = np.array(month_com_last['mean'])
v1 = ["{}".format(int(i)) for i in v1]

line = Line("2018年北京月均PM2.5走势图", title_pos='center', title_top='18', width=800, height=400)
line.add("", attr, v1, mark_point=["max", "min"])
line.render("2018年北京月均PM2.5走势图.html")

image-20200412172741618

2018年北京季度AQI箱形图

import pandas as pd
from pyecharts import Boxplot

df = pd.read_csv('data/beijing_AQI_2018.csv')

dom = df[['Date', 'AQI']]
data = [[], [], [], []]
dom1, dom2, dom3, dom4 = data
for i, j in zip(dom['Date'], dom['AQI']):
    time = i.split('/')[1]
    if time in ['1', '2', '3']:
        dom1.append(j)
    elif time in ['4', '5', '6']:
        dom2.append(j)
    elif time in ['7', '8', '9']:
        dom3.append(j)
    else:
        dom4.append(j)

boxplot = Boxplot("2018年北京季度AQI箱形图", title_pos='center', title_top='18', width=800, height=400)
x_axis = ['第一季度', '第二季度', '第三季度', '第四季度']
y_axis = [dom1, dom2, dom3, dom4]
_yaxis = boxplot.prepare_data(y_axis)
boxplot.add("", x_axis, _yaxis)
boxplot.render("2018年北京季度AQI箱形图.html")

image-20200412172936192

2018年北京季度PM2.5箱形图

import pandas as pd
from pyecharts import Boxplot

df = pd.read_csv('data/beijing_AQI_2018.csv')

dom = df[['Date', 'PM']]
data = [[], [], [], []]
dom1, dom2, dom3, dom4 = data
for i, j in zip(dom['Date'], dom['PM']):
    time = i.split('/')[1]
    if time in ['1', '2', '3']:
        dom1.append(j)
    elif time in ['4', '5', '6']:
        dom2.append(j)
    elif time in ['7', '8', '9']:
        dom3.append(j)
    else:
        dom4.append(j)
boxplot = Boxplot("2018年北京季度PM2.5箱形图", title_pos='center', title_top='18', width=800, height=400)
x_axis = ['第一季度', '第二季度', '第三季度', '第四季度']
y_axis = [dom1, dom2, dom3, dom4]
_yaxis = boxplot.prepare_data(y_axis)
boxplot.add("", x_axis, _yaxis)
boxplot.render("result/2018年北京季度PM2.5箱形图.html")

image-20200412193439363

2018年北京全年空气质量情况

import pandas as pd
from pyecharts import Pie

df = pd.read_csv('data/beijing_AQI_2018.csv')

rank_message = df.groupby(['Quality_grade'])
rank_com = rank_message['Quality_grade'].agg(['count'])
rank_com.reset_index(inplace=True)
rank_com_last = rank_com.sort_values('count', ascending=False)

attr = rank_com_last['Quality_grade']
v1 = rank_com_last['count']

pie = Pie("2018年北京全年空气质量情况", title_pos='center', title_top=0)
pie.add("", attr, v1, radius=[40, 75], label_text_color=None, is_label_show=True, legend_orient="vertical", legend_pos="left", legend_top="%10")
pie.render('result/2018年北京全年空气质量情况.html')

image-20200412193604341

2018年北京PM2.5指数日历图

import datetime
import random
import numpy as np
import pandas as pd
from pyecharts import HeatMap

df = pd.read_csv('data/beijing_AQI_2018.csv')
#v1 = ["{}".format(int(i)) for i in np.array(df['PM'])]

#begin = datetime.date(2018, 1, 1)
#end = datetime.date(2018, 12, 31)

#data = [[str(begin + datetime.timedelta(days=i)), v1[i]] for i in range((end - begin).days + 1)]
#random.randint(1000, 25000)
#data = [[str(begin + datetime.timedelta(days=i)), random.randint(0, 400)] for i in range((end - begin).days + 1)]
dom = df[['Date', 'PM']]
list1 = []
for i, j in zip(dom['Date'], dom['PM']):
    time_list = i.split('/')
    time = datetime.date(int(time_list[0]),int(time_list[1]),int(time_list[2]))
    PM = int(j)
    list1.append([str(time),str(PM)])

heatmap = HeatMap("2018年北京PM2.5指数日历图", title_pos='40%', title_top='10', width=800, height=400)
heatmap.add(
    "",
    list1,
    is_calendar_heatmap=True,
    visual_text_color="#000",
    visual_range_text=["", ""],
    visual_range=[0, 300],
    calendar_cell_size=["auto", 30],
    is_visualmap=True,
    calendar_date_range="2018",
    visual_orient="horizontal",
    visual_pos="26%",
    visual_top="70%",
    is_piecewise=True,
    visual_split_number=6,
)
heatmap.render('result/2018年北京PM2.5指数日历图.html')

image-20200412193815976

2018年北上广深AQI轴向运动图

import numpy as np
import pandas as pd
from pyecharts import Line

citys = ['beijing', 'shanghai', 'guangzhou', 'shenzhen']
cityes_AQI = []
for i in range(4):
    filename = 'data/'+ citys[i] + '_AQI' + '_2018.csv' # 文件内容:"日期","质量等级","AQI指数","当天AQI排名","PM2.5"
    aqi_data = pd.read_csv(filename)

    get_data = aqi_data[['Date', 'AQI']] # 提取 "日期","AQI指数"两列内容进行分析
    month_for_data = []
    for j in get_data['Date']:
        time = j.split('/')[1]
        month_for_data.append(time)
    aqi_data['Month'] = month_for_data # 获取每行数据的月份

    # 求每个月AQI平均值
    month_data = aqi_data.groupby(['Month'])
    month_AQI = month_data['AQI'].agg(['mean'])
    month_AQI.reset_index(inplace=True)
    month_AQI_average = month_AQI.sort_index()

    # 获取每个城市月均AQI的数据,转化为int数据类型
    month_AQI_data = np.array(month_AQI_average['mean'])
    month_AQI_data_int = ["{}".format(int(i)) for i in month_AQI_data]
    cityes_AQI.append(month_AQI_data_int)

months = ["{}".format(str(i) + '月') for i in range(1, 13)]

line = Line("2018年北上广深AQI全年走势图", title_pos='center', title_top='0', width=800, height=400)
line.add("北京", months, cityes_AQI[0], line_color='red', legend_top='8%')
line.add("上海", months, cityes_AQI[1], line_color='purple', legend_top='8%')
line.add("广州", months, cityes_AQI[2], line_color='blue', legend_top='8%')
line.add("深圳", months, cityes_AQI[3], line_color='orange', legend_top='8%')
line.render("result/2018年北上广深AQI全年走势图.html")

image-20200412194325496

2018年北上广深PM2.5走势图

import numpy as np
import pandas as pd
from pyecharts import Line

citys = ['beijing', 'shanghai', 'guangzhou', 'shenzhen']
cityes_PM = []
for i in range(4):
    filename ='data/'+  citys[i] + '_AQI' + '_2018.csv'  # 文件内容:"日期","质量等级","AQI指数","当天AQI排名","PM2.5"
    aqi_data = pd.read_csv(filename)

    get_data = aqi_data[['Date', 'PM']] # 提取 "日期","PM2.5"两列内容进行分析
    month_for_data = []
    for j in get_data['Date']:
        time = j.split('/')[1]
        month_for_data.append(time)
    aqi_data['Month'] = month_for_data # 获取每行数据的月份

    # 求每个月PM2.5平均值
    month_data = aqi_data.groupby(['Month'])
    month_PM = month_data['PM'].agg(['mean'])
    month_PM.reset_index(inplace=True)
    month_PM_average = month_PM.sort_index()

    # 获取每个城市每个月AQI的数据,转化为int数据类型
    month_PM_data = np.array(month_PM_average['mean'])
    month_PM_data_int = ["{}".format(int(i)) for i in month_PM_data]
    cityes_PM.append(month_PM_data_int)

months = ["{}".format(str(i) + '月') for i in range(1, 13)]

line = Line("2018年北上广深PM2.5全年走势图", title_pos='center', title_top='0', width=800, height=400)
line.add("北京", months, cityes_PM[0], line_color='red', legend_top='8%')
line.add("上海", months, cityes_PM[1], line_color='purple', legend_top='8%')
line.add("广州", months, cityes_PM[2], line_color='blue', legend_top='8%')
line.add("深圳", months, cityes_PM[3], line_color='orange', legend_top='8%')
line.render("result/2018年北上广深PM2.5全年走势图.html")

image-20200412203050148

2018年北上广深一级空气质量情况

import numpy as np
import pandas as pd
from pyecharts import Pie, Grid

citys = ['beijing', 'shanghai', 'guangzhou', 'shenzhen']
v = []
attrs = []
for i in range(4):
    filename = 'data/'+ citys[i] + '_AQI' + '_2018.csv'
    df = pd.read_csv(filename) #pd.read_csv(filename, header=None, names=["Date", "Quality_grade", "AQI", "AQI_rank", "PM"])

    Quality_grade_message = df.groupby(['Quality_grade'])
    Quality_grade_com = Quality_grade_message['Quality_grade'].agg(['count'])
    Quality_grade_com.reset_index(inplace=True)
    Quality_grade_com_last = Quality_grade_com.sort_values('count', ascending=False)

    Quality_grade_array = Quality_grade_com_last['Quality_grade']
    Quality_grade_array = np.array(Quality_grade_com_last['Quality_grade'])
    attrs.append(Quality_grade_array)
    Quality_grade_count = Quality_grade_com_last['count']
    Quality_grade_count = np.array(Quality_grade_com_last['count'])
    v.append(Quality_grade_count)

pie1 = Pie("北京", title_pos="28%", title_top="24%")
pie1.add("", attrs[0], v[0], radius=[20, 40], center=[30, 27], legend_pos="63%", legend_top="40%", legend_orient="vertical",is_label_show=True)

pie2 = Pie("上海", title_pos="52%", title_top="24%")
pie2.add("", attrs[1], v[1], radius=[20, 40], center=[54, 27], is_label_show=False, is_legend_show=False)

pie3 = Pie("广州", title_pos='28%', title_top='77%')
pie3.add("", attrs[2], v[2], radius=[20, 40], center=[30, 80], is_label_show=False, is_legend_show=False)

pie4 = Pie("深圳", title_pos='52%', title_top='77%')
pie4.add("", attrs[3], v[3], radius=[20, 40], center=[54, 80], is_label_show=False, is_legend_show=False)

grid = Grid("2018年北上广深全年空气质量情况", width=1200)
grid.add(pie1)
grid.add(pie2)
grid.add(pie3)
grid.add(pie4)
grid.render('result/2018年北上广深全年空气质量情况.html')

image-20200412203158607

十一、关系数据可视化

直接上代码

import ggplot as gp
# print(type(gp.mtcars))
# print(gp.mtcars)

#基本三个图层
gp_data =gp.ggplot(gp.aes(x='mpg',y='wt'),data=gp.mtcars)#数据层
gp_geom = gp.geom_point(color="red")#几何图像层
gp_title = gp.ggtitle('mtcarts')#美学层
print(gp_data+gp_geom+gp_title)

image-20200422170808311

import ggplot as gp
gp_data =gp.ggplot(gp.aes(x='mpg',y='wt',color='factor(cyl)'),data=gp.mtcars)#数据层
gp_geom = gp.geom_point()#几何图像层
gp_title = gp.ggtitle('hhhh')#美学层
print(gp_data+gp_geom+gp_title)
#读数据绘制散点图
import ggplot as gp
import pandas as pd
crime = pd.read_csv("data/crimeRatesByState2005.csv")
plot = gp.ggplot(gp.aes(x='murder', y='burglary'), data=crime)
points = gp.geom_point(color='red')
print(plot + points)

image-20200422171156826

查看关系

import ggplot as gp
import pandas as pd
crime = pd.read_csv("./data/crimeRatesByState2005.csv")
crime = crime[crime.state != "United States"]
crime = crime[crime.state != "District of Columbia"]
plot = gp.ggplot(gp.aes(x='murder', y='burglary'), data=crime)
points = gp.geom_point(color='red')
# smooth = gp.stat_smooth(method='loess', color='red')
print(plot + points )

image-20200422171144035

import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
crime = pd.read_csv("./data/crimeRatesByState2005.csv")
crime = crime[crime.state != "United States"]
crime = crime[crime.state != "District of Columbia"]
crime = crime.drop(['state'], axis=1)
crime = crime.drop(['population'], axis=1)
g = sns.pairplot(crime, diag_kind="kde", kind="reg")
plt.show()

image-20200422171310627

气泡图
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
crime = pd.read_csv("./data/crimeRatesByState2005.csv")
crime2 = crime[crime.state != "United States"]
crime2 = crime2[crime2.state != "District of Columbia"]
s = list(crime2.population/10000)
colors = np.random.rand(len(list(crime2.murder)))
cm = plt.cm.get_cmap()
plt.scatter(x=list(crime2.murder), y=list(crime2.burglary), s=s, c=colors, cmap=cm, linewidth=0.5, alpha=0.5)
plt.xlabel("murder")
plt.ylabel("burglary")
plt.show()

image-20200422171435586

茎叶图只适用于小数点后两位的数据
from itertools import groupby
import pandas as pd
birth = pd.read_csv("./data/birth-rate.csv")
birth.dropna(subset=['2008'], inplace=True)
dirt = {}
data = list(round(birth['2008'], 1))
range_num = []
for k, g in groupby(sorted(data), key=lambda x: int(x)):
    lst = map(str, list(map(lambda y: divmod(int(y * 10), 10)[1], list(g))))
    dirt[k] = ' '.join(lst)
    range_num.append(k)
num = list(range(range_num[0], range_num[-1], 2))
for i in num:
   a = ""
   for k in sorted(dirt.keys()):
      if 0 <= k - i <= 1:
          a = a + ' ' + dirt[k]
      elif k- i > 1:
          break
   print(str(i).rjust(5), '|', a)

image-20200422171548701

# 直方图
import pandas as pd
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei']  # 解决中文不能正常显示的问题
titanic = pd.read_csv('./data/birth-rate.csv')
titanic.dropna(subset=['2008'], inplace=True)
plt.style.use('ggplot')
plt.hist(titanic['2008'], bins=15, color='steelblue', edgecolor='k', label="直方图")
plt.tick_params(top='off', right='off')
plt.legend()
plt.show()

image-20200422171641931

# 密度图
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.mlab as mlab
plt.rcParams['font.sans-serif'] = ['Microsoft YaHei']
plt.rcParams['axes.unicode_minus'] = False
titanic = pd.read_csv('./data/birth-rate.csv')
titanic.dropna(subset=['2008'], inplace=True)
kde = mlab.GaussianKDE(titanic['2008'])
x2 = np.linspace(titanic['2008'].min(), titanic['2008'].max(), 1000)
line2 = plt.plot(x2, kde(x2), 'g-', linewidth=2)
plt.show()

image-20200422171721989

# 基于Python的直方图结合密度图的实现
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.mlab as mlab
plt.rcParams['font.sans-serif'] = ['SimHei'] # 解决中文不能正常显示的问题
titanic = pd.read_csv('./data/birth-rate.csv')
titanic.dropna(subset=['2008'], inplace=True)
plt.style.use('ggplot')
plt.hist(titanic['2008'], bins=np.arange(titanic['2008'].min(),
titanic['2008'].max(), 3), normed=True, color= 'steelblue', edgecolor='k')
plt.title(' 2008出生直方图和密度图')
plt.xlabel('出生率')
plt.ylabel('频率')
kde = mlab.GaussianKDE(titanic['2008'])
x2 = np.linspace(titanic['2008'].min(), titanic['2008'].max(), 1000)
line2 = plt.plot(x2, kde(x2), 'g-', linewidth=2)
plt.tick_params(top='off', right='off')
plt.show()

image-20200422171822165

十二、空间数据可视化

1、地理坐标系-Geo

1)地理坐标系-散点图

img

image-20200412204120320

image-20200412204203676

image-20200412204221657

image-20200412204232652

image-20200412204247771

4、空间数据可视化实验

实验环境

  • pyecharts=1.7.2

各城市最低气温可视化

All_Data = []
ua = UserAgent(use_cache_server=False)
# 网页的解析函数
def parse_page(url):
    headers = {
        'User-Agent': ua.random
    }
    response = requests.get(url, headers=headers)
    text = response.content.decode('utf-8')
    soup = BeautifulSoup(text, 'lxml')
    conMidtab = soup.find('div', {'class': 'conMidtab'})
    tables = conMidtab.find_all('table')
#     查看是否拿到了每个城市的天气
    for table in tables:
        trs = table.find_all('tr')[2:]
        for index, tr in enumerate(trs):
            tds = tr.find_all('td')
            if len(tds) >= 8:
                city_td = tds[0]
                if index == 0:
                    city_td = tds[1]
    #             获取标签里面的字符串属性返回一个生成器,因此要转化为一个列表
                city = city_td.get_text()
                temp_td = tds[-2]
                min_temp = temp_td.get_text()
    #             将数据添加到列表
                All_Data.append({'城市': city, '最低气温': int(min_temp)})
def main():
    urls = [
        'http://www.weather.com.cn/textFC/hb.shtml',
        'http://www.weather.com.cn/textFC/db.shtml',
        'http://www.weather.com.cn/textFC/hz.shtml',
        'http://www.weather.com.cn/textFC/hn.shtml',
        'http://www.weather.com.cn/textFC/hd.shtml',
        'http://www.weather.com.cn/textFC/xb.shtml',
        'http://www.weather.com.cn/textFC/xn.shtml',
        'http://www.weather.com.cn/textFC/gat.shtml'
    ]
    for url in urls:
        parse_page(url)
    # 分析数据,根据最低气温进行排序
    All_Data.sort(key=lambda data: data['最低气温'])
    data = All_Data[0:10]  # 取出前10的最低气温及其城市
    return data
if __name__ == '__main__':
    datas = main()
    city = []
    temp = []
    plt.figure(figsize=(15, 9.27))
    plt.rcParams['font.sans-serif'] = ['SimHei']  # 用来正常显示中文标签
    plt.rcParams['axes.unicode_minus'] = False  # 用来正常显示负号
    for data in datas:
        city.append(data['城市'])
        temp.append(data['最低气温'])
    plt.bar(range(len(city)), temp, tick_label=city)
    plt.show()

img

import pandas as pd

def main():
    aqi_data = pd.read_csv('data/china_city_AQI.csv')
    print('基本信息:')
    print(aqi_data.info())

    print('数据预览:')
    print(aqi_data.head())

    # 基本统计
    print('AQI最大值:', aqi_data['AQI'].max())
    print('AQI最小值:', aqi_data['AQI'].min())
    print('AQI均值:', aqi_data['AQI'].mean())

    # top10
    top10_cities = aqi_data.sort_values(by=['AQI']).head(10)
    print('空气质量最好的10个城市:')
    print(top10_cities)

    # bottom10
    # bottom10_cities = aqi_data.sort_values(by=['AQI']).tail(10)
    bottom10_cities = aqi_data.sort_values(by=['AQI'], ascending=False).head(10)
    print('空气质量最差的10个城市:')
    print(bottom10_cities)

    # 保存csv文件
    top10_cities.to_csv('data/top10_aqi.csv', index=False)
    bottom10_cities.to_csv('data/bottom10_aqi.csv', index=False)


if __name__ == '__main__':
    main()

img

def main():
    aqi_data = pd.read_csv('data/china_city_AQI.csv')
    print('基本信息:')
    print(aqi_data.info())

    print('数据预览:')
    print(aqi_data.head())

    # 数据清洗
    # 只保留AQI>0的数据
    # filter_condition = aqi_data['AQI'] > 0
    # clean_aqi_data = aqi_data[filter_condition]

    clean_aqi_data = aqi_data[aqi_data['AQI'] > 0]

    # 基本统计
    print('AQI最大值:', clean_aqi_data['AQI'].max())
    print('AQI最小值:', clean_aqi_data['AQI'].min())
    print('AQI均值:', clean_aqi_data['AQI'].mean())

    # top50
    top50_cities = clean_aqi_data.sort_values(by=['AQI']).head(50)
    print(top50_cities)
    top50_cities.plot(kind='bar', x='City', y='AQI', title='空气质量最好的50个城市',
                      figsize=(20, 10))
    plt.figure(figsize=(15, 9.27))
    plt.savefig('data/top50_aqi_bar.png')
    plt.show()


if __name__ == '__main__':
    main()

img

img

from pyecharts.globals import CurrentConfig, NotebookType
CurrentConfig.NOTEBOOK_TYPE = NotebookType.JUPYTER_LAB
from pyecharts.globals import ThemeType
from pyecharts.charts import Bar
import pyecharts.options as opts

aqi_data = pd.read_csv('data/china_city_AQI.csv')
print('基本信息: ')
print(aqi_data.info())

print('数据预览: ')
print(aqi_data.head())

#     数据清洗
#     只保留AQI>0的数据
clean_aqi_data = aqi_data[aqi_data['AQI']  > 0]

#     基本统计
print('AQI最大值:{}'.format(clean_aqi_data['AQI'].max()))
print('AQI最小值:{}'.format(clean_aqi_data['AQI'].min()))
print('AQI均值:{}'.format(clean_aqi_data['AQI'].mean()))

top50_cities = clean_aqi_data.sort_values(by=['AQI']).head(50)
bar = (
    Bar(init_opts=opts.InitOpts(theme=ThemeType.DARK))
    .add_xaxis(top50_cities['City'].tolist())
    .add_yaxis('', top50_cities['AQI'].tolist(), label_opts=opts.LabelOpts(is_show=False), category_gap='50%')
    .set_global_opts(title_opts=opts.TitleOpts(title='空气质量指数最优TOP50城市'),
                     xaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(rotate=30, interval=0)),
                     datazoom_opts=[opts.DataZoomOpts(), opts.DataZoomOpts(type_='inside')]
                    )
)
bar.load_javascript()
bar.render_notebook()

img