数据挖掘


安装模块

matplotlib
numpy
pandas
TA-Lib
tables
jupyter

案例测试

def matplolib_demo():
    """画图"""
    plt.figure(figsize=(20, 8), dpi=100)
    plt.plot([1,2,3], [4,5,6])
    plt.show()
    plt.savefig("./jupyter_demo01.png")
    return None

def read_csv_dem():
    """分析"""
    stock_key = pd.read_csv("./jupyter_demo01.png")
    print(stock_key)
    return None

if __name__ == "__main__":
    matplolib_demo()
    read_csv_dem()



Jupyter Notebook

介绍

Jupyter Notebook是一个开源的Web应用程序,允许用户创建和共享包含代码、方程式、可视化和文本的文档。它的用途包括:数据清理和转换、数值模拟、统计建模、数据可视化、机器学习等等。

名字源于Julia,Python,和R(数据科学的三种开源语言)

是一款程序员和工作者的编程/文档/展示软件

.ipynb文件格式是用于计算型叙述的JSON文档格式的正式规范

优势

可选择语言:支持超过40种编程语言,包括Python、R、Julia、Scala等。
分享笔记本:可以使用电子邮件、Dropbox、GitHub和Jupyter Notebook Viewer与他人共享。
交互式输出:代码可以生成丰富的交互式输出,包括HTML、图像、视频、LaTeX等等。
大数据整合:通过Python、R、Scala编程语言使用Apache Spark等大数据框架工具。支持使用pandas、scikit-learn、ggplot2、TensorFlow来探索同一份数据。


启动

在终端运行

jupyter notebook
或
ipython notebook

在浏览器输入localhost:8888,进入该页面

点击一下day01_jupyter_demo.ipynb


测试

运行代码 shift + enter



Matplotlib

介绍

Matplotlib 是一个 Python 的 2D绘图库,它以各种硬拷贝格式和跨平台的交互式环境生成出版质量级别的图形 [1] 。

通过 Matplotlib,开发者可以仅需要几行代码,便可以生成绘图,直方图,功率谱,条形图,错误图,散点图等


案例

from matplotlib import pyplot

pyplot.figure()
pyplot.plot([1, 0, 9], [4, 5, 6])
pyplot.show()


三层结构

容器层: 主要由Canvas、Figure、Axes组成。

Canvas是位于最底层的系统层,在绘图的过程中充当画板的角色,即放置画布(Figure)的工具。

Figure是Canvas上方的第一层,也是需要用户来操作的应用层的第一层,在绘图的过程中充当画布的角色。

Axes是应用层的第二层,在绘图的过程中相当于画布上的绘图区的角色。

Figure:指整个图形(可以通过plt.figure()设置画布的大小和分辨率等)
Axes(坐标系):数据的绘图区域
Axis(坐标轴):坐标系中的一条轴,包含大小限制、刻度和刻度标签

注意点:
一个figure(画布)可以包含多个axes(坐标系/绘图区),但是一个axes只能属于一个figure
一个axes(坐标系/绘图区)可以包含多个axis(坐标轴),包含两个即为2d坐标系,3个即为3d坐标系

辅助显示层
辅助显示层为Axes(绘图区)内的除了根据数据绘制出的图像以外的内容,主要包括Axes外观(facecolor)、边框线(spines)、坐标轴(axis)、坐标轴名称(axis label)、坐标轴刻度(tick)、坐标轴刻度标签(tick label)、网格线(grid)、图例(legend)、标题(title)等内容。
该层的设置可使图像显示更加直观更加容易被用户理解,但又不会对图像产生实质的影响。

图像层

图像层指Axes内通过plot、scatter、bar、histogram、pie等函数根据数据绘制出的图像。

总结
Canvas(画板)位于最底层,用户一般接触不到
Figure(画布)建立在Canvas之上
Axes(绘图区)建立在Figure之上
坐标轴(axis)、图例(legend)等辅助显示层以及图像层都是建立在Axes之上


折线图

from matplotlib import pyplot

# 创建画布
pyplot.figure()
# 绘制图像
pyplot.plot([1, 2, 3, 4, 5, 6, 7], [17, 17, 18, 15, 11, 11, 13])
# 显示图像
pyplot.show()

设置画布属性和图片保存

def figure(num=None,  # autoincrement if None, else integer from 1-N
           figsize=None,  # defaults to rc figure.figsize
           dpi=None,  # defaults to rc figure.dpi
           facecolor=None,  # defaults to rc figure.facecolor
           edgecolor=None,  # defaults to rc figure.edgecolor
           frameon=True,
           FigureClass=Figure,
           clear=False,
           **kwargs
           ):

num:整型或者字符串,可选参数,默认:None。
如果不提供该参数,一个新的画布(figure)将被创建而且画布数量将会增加。
如果提供该参数,带有id的画布是已经存在的,激活该画布并返回该画布的引用。
如果这个画布不存在,创建并返回画布实例。
如果num是字符串,窗口标题将被设置为该图的数字。
figsize:整型元组,可选参数 ,默认:None。
每英寸的宽度和高度。如果不提供,默认值是figure.figsize。
dpi:整型,可选参数,默认:None。每英寸像素点。如果不提供,默认是figure.dpi。
facecolor:背景色。如果不提供,默认值:figure.facecolor。
edgecolor:边界颜色。如果不提供,默认值:figure.edgecolor。
framemon:布尔类型,可选参数,默认值:True。如果是False,禁止绘制画图框。
FigureClass:源于matplotlib.figure.Figure的类。(可选)使用自定义图实例。
clear:布尔类型,可选参数,默认值:False。如果为True和figure已经存在时,这是清理掉改图。


# 创建画布
pyplot.figure(figsize=(20, 8), dpi=40)
# 绘制图像
pyplot.plot([1, 2, 3, 4, 5, 6, 7], [17, 17, 18, 15, 11, 11, 13])
# 保存图像
pyplot.savefig("test_plot.png")
# 显示图像
pyplot.show()

注意:pyplot.show()会释放figure资源,如果在显示图像之后保存图片只能保存空图片


增加图形信息

import random
import matplotlib.pyplot as plt

# 准备数据x,y
x = range(60)
y_shanghai = [random.uniform(15, 18) for i in x]
y_beijing = [random.uniform(15, 18) for i in x]
# 创建画布
plt.figure(figsize=(20, 8), dpi=80)

# 绘制图像
# 八种颜色 b:blue   g:green    r:red   c:cyan   m:magenta   y:yellow  k:black  w:white
# 四种线形 - 实线; -- 虚线; -.  点实线  : 点虚线
plt.plot(x, y_shanghai, color="r", linestyle="--", label="上海")
plt.plot(x, y_beijing, color="b", label="北京")
# 显示图例(结合上方的label)
# best;upper right;upper left;lower left;lower right;right;center left;center right;lower center;upper center;center
plt.legend(loc="upper center")

# 显示中文标签
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False

# 修改x,y刻度,标签
x_label = ["11点{}分".format(i) for i in x]
plt.xticks(x[::5], x_label[::5])
plt.yticks(range(10, 30, 5))

# 添加网格显示
plt.grid(True, linestyle="--", alpha=0.5)

# 添加描述信息
plt.xlabel("时间")z
plt.ylabel("温度")
plt.title("北京,上海中午11点到12点之间的温度变化")

# 显示图像
plt.show()


多个绘图区

import random
import matplotlib.pyplot as plt

# 准备数据x,y
x = range(60)
y_shanghai = [random.uniform(15, 18) for i in x]
y_beijing = [random.uniform(15, 18) for i in x]
# 创建画布
# plt.figure(figsize=(20, 8), dpi=80)
figure, axes = plt.subplots(nrows=1, ncols=2, figsize=(20, 8), dpi=80)

# 绘制图像
# 八种颜色 b:blue   g:green    r:red   c:cyan   m:magenta   y:yellow  k:black  w:white
# 四种线形 - 实线; -- 虚线; -.  点划线  : 点虚线
axes[0].plot(x, y_shanghai, color="r", linestyle="--", label="上海")
axes[1].plot(x, y_beijing, color="b", label="北京")
# 显示图例(结合上方的label)
axes[0].legend(loc="upper center")
axes[1].legend(loc="upper center")

# 显示中文标签
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False

# 修改x,y刻度,标签
x_label = ["11点{}分".format(i) for i in x]
axes[0].set_xticks(x[::5])
axes[0].set_xticklabels(x_label[::5])
axes[0].set_yticks(range(10, 30, 5))
axes[1].set_xticks(x[::5])
axes[1].set_xticklabels(x_label[::5])
axes[1].set_yticks(range(10, 30, 5))

# 添加网格显示
axes[0].grid(True, linestyle="--", alpha=0.5)
axes[1].grid(True, linestyle="--", alpha=0.5)

# 添加描述信息
axes[0].set_xlabel("时间")
axes[0].set_ylabel("温度")
axes[0].set_title("上海中午11点到12点之间的温度变化")
axes[1].set_xlabel("时间")
axes[1].set_ylabel("温度")
axes[1].set_title("北京中午11点到12点之间的温度变化")

# 显示图像
plt.show()


结合数学表达式

import matplotlib.pyplot as plt
import numpy as np

# 准备x,y数据
x = np.linspace(-1, 1, 1000)
y = 2 * x * x

# 创建画布
plt.figure(figsize=(20, 8), dpi=80)

# 绘制图像
plt.plot(x, y)

# 添加网格
plt.grid(True, linestyle="--", alpha=0.5)

# 显示
plt.show()


散点图

import matplotlib.pyplot as plt

x = [225.98, 247.07, 253.14, 457.85, 241.58, 301.01,  20.67, 288.64,
       163.56, 120.06, 207.83, 342.75, 147.9 ,  53.06, 224.72,  29.51,
        21.61, 483.21, 245.25, 399.25, 343.35]

y = [196.63, 203.88, 210.75, 372.74, 202.41, 247.61,  24.9 , 239.34,
       140.32, 104.15, 176.84, 288.23, 128.79,  49.64, 191.74,  33.1 ,
        30.74, 400.02, 205.35, 330.64, 283.45]

plt.figure(figsize=(20, 8), dpi=80)
plt.scatter(x, y)
plt.show()


柱状图

import matplotlib.pyplot as plt


# 准备数据
movie_names = ['雷神3:诸神黄昏','正义联盟','东方快车谋杀案','寻梦环游记','全球风暴', '降魔传','追捕','七十七天','密战','狂兽','其它']
tickets = [73853,57767,22354,15969,14839,8725,8716,8318,7916,6764,52222]

# 创建画布
plt.figure(figsize=(20, 8), dpi=80)

# 绘制柱状图
x_ticks = range(len(movie_names))
plt.bar(x_ticks, tickets, color=['b','r','g','y','c','m','y','k','c','g','b'])

plt.rcParams["font.sans-serif"] = ["SimHei"]
plt.rcParams["axes.unicode_minus"] = True

# 修改x的刻度
plt.xticks(x_ticks, movie_names)

# 添加标题
plt.title("电影票房收入")

# 添加网格
plt.grid(linestyle="--", alpha=0.5)

# 显示图像
plt.show()

import matplotlib.pyplot as plt


# 1、准备数据
movie_names = ['雷神3:诸神黄昏','正义联盟','寻梦环游记']

first_day = [10587.6,10062.5,1275.7]
first_weekend=[36224.9,34479.6,11830]

# 创建画布
plt.figure(figsize=(20, 8), dpi=80)

# 绘制柱状图
x_ticks = range(len(movie_names))
plt.bar(x_ticks, first_day, color='r', width=0.2, label="首日票房")
plt.bar([x_tick+0.2 for x_tick in x_ticks], first_weekend, color='c', width=0.2, label="首周票房")
plt.legend()

plt.rcParams["font.sans-serif"] = ["SimHei"]
plt.rcParams["axes.unicode_minus"] = True

# 修改x的刻度
plt.xticks([x_tick+0.1 for x_tick in x_ticks], movie_names)

# 添加标题
plt.title("电影票房收入")

# 添加网格
plt.grid(linestyle="--", alpha=0.5)

# 显示图像
plt.show()


直方图

import matplotlib.pyplot as plt

# 准备数据
time = [131,  98, 125, 131, 124, 139, 131, 117, 128, 108, 135, 138, 131, 102, 107, 114, 119, 128, 121, 142, 127, 130, 124, 101, 110, 116, 117, 110, 128, 128, 115,  99, 136, 126, 134,  95, 138, 117, 111,78, 132, 124, 113, 150, 110, 117,  86,  95, 144, 105, 126, 130,126, 130, 126, 116, 123, 106, 112, 138, 123,  86, 101,  99, 136,123, 117, 119, 105, 137, 123, 128, 125, 104, 109, 134, 125, 127,105, 120, 107, 129, 116, 108, 132, 103, 136, 118, 102, 120, 114,105, 115, 132, 145, 119, 121, 112, 139, 125, 138, 109, 132, 134,156, 106, 117, 127, 144, 139, 139, 119, 140,  83, 110, 102,123,107, 143, 115, 136, 118, 139, 123, 112, 118, 125, 109, 119, 133,112, 114, 122, 109, 106, 123, 116, 131, 127, 115, 118, 112, 135,115, 146, 137, 116, 103, 144,  83, 123, 111, 110, 111, 100, 154,136, 100, 118, 119, 133, 134, 106, 129, 126, 110, 111, 109, 141,120, 117, 106, 149, 122, 122, 110, 118, 127, 121, 114, 125, 126,114, 140, 103, 130, 141, 117, 106, 114, 121, 114, 133, 137,  92,121, 112, 146,  97, 137, 105,  98, 117, 112,  81,  97, 139, 113,134, 106, 144, 110, 137, 137, 111, 104, 117, 100, 111, 101, 110,105, 129, 137, 112, 120, 113, 133, 112,  83,  94, 146, 133, 101,131, 116, 111,  84, 137, 115, 122, 106, 144, 109, 123, 116, 111,111, 133, 150]

# 创建画布
plt.figure(figsize=(20, 8), dpi=80)

# 绘制直方图
distance = 2
group_num = int(max(time)-min(time) / distance)

# 默认显示的是频数,使用density是频率
plt.hist(time, bins=group_num, density=True)

# 修改x轴刻度
plt.xticks(range(min(time), max(time)+2, distance))

# 添加网格
plt.grid(linestyle="--", alpha=0.5)

# 显示图像
plt.show()

hist参数详解:https://blog.csdn.net/ToYuki_/article/details/104114925


饼图

import matplotlib.pyplot as plt

# 准备数据
movie_name = ['雷神3:诸神黄昏','正义联盟','东方快车谋杀案','寻梦环游记','全球风暴','降魔传','追捕','七十七天','密战','狂兽','其它']
place_count = [60605,54546,45819,28243,13270,9945,7679,6799,6101,4621,20105]

# 准备画布
plt.figure(figsize=(20, 8), dpi=80)

plt.rcParams["font.sans-serif"] = ["SimHei"]
plt.rcParams["axes.unicode_minus"] = True
# 绘制饼图,autopct为显示格式
plt.pie(place_count, labels=movie_name, colors=['b','r','g','y','c','m','y','k','c','g','y'], autopct="%1.2f%%")
plt.legend()

# 为了让饼图显示圆形,保证长宽一致
plt.axis('equal')

# 显示
plt.show()


总结


Numpy

介绍

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

NumPy 的前身 Numeric 最早是由 Jim Hugunin 与其它协作者共同开发,2005 年,Travis Oliphant 在 Numeric 中结合了另一个同性质的程序库 Numarray 的特色,并加入了其它扩展而开发了 NumPy。NumPy 为开放源代码并且由许多协作者共同维护开发。

NumPy 是一个运行速度非常快的数学库,主要用于数组计算,包含:

  • 一个强大的N维数组对象 ndarray
  • 广播功能函数
  • 整合 C/C++/Fortran 代码的工具
  • 线性代数、傅里叶变换、随机数生成等功能

Ndarray

NumPy 最重要的一个特点是其 N 维数组对象 ndarray,它是一系列同类型数据的集合,以 0 下标为开始进行集合中元素的索引。

ndarray 对象是用于存放同类型元素的多维数组。

ndarray 中的每个元素在内存中都有相同存储大小的区域。

ndarray 内部由以下内容组成:

  • 一个指向数据(内存或内存映射文件中的一块数据)的指针。
  • 数据类型或 dtype,描述在数组中的固定大小值的格子。
  • 一个表示数组形状(shape)的元组,表示各维度大小的元组。
  • 一个跨度元组(stride),其中的整数指的是为了前进到当前维度下一个元素需要”跨过”的字节数。

ndarray 的内部结构:

跨度可以是负数,这样会使数组在内存中后向移动,切片中 obj[::-1] 或 obj[:,::-1] 就是如此。

创建一个 ndarray 只需调用 NumPy 的 array 函数即可:

numpy.array(object, dtype = None, copy = True, order = None, subok = False, ndmin = 0)
名称 描述
object 数组或嵌套的数列
dtype 数组元素的数据类型,可选
copy 对象是否需要复制,可选
order 创建数组的样式,C为行方向,F为列方向,A为任意方向(默认)
subok 默认返回一个与基类类型一致的数组
ndmin 指定生成数组的最小维度

import numpy as np

score = np.array([[80, 89, 86, 67, 79],
                  [78, 97, 89, 67, 81],
                  [90, 94, 78, 67, 74],
                  [91, 91, 90, 67, 69],
                  [76, 87, 75, 67, 86],
                  [70, 79, 84, 67, 84],
                  [94, 92, 93, 67, 64],
                  [86, 85, 83, 67, 80]])
print(score)
print(type(score))

输出

[[80 89 86 67 79]
 [78 97 89 67 81]
 [90 94 78 67 74]
 [91 91 90 67 69]
 [76 87 75 67 86]
 [70 79 84 67 84]
 [94 92 93 67 64]
 [86 85 83 67 80]]
<class 'numpy.ndarray'>

ndarray与Python原生list运算效率对比

# ndarray和list效率对比
python_list = []
start_time = datetime.datetime.now()
for i in range(100000000):
    python_list.append(random.random())
end_time = datetime.datetime.now()
print("list的运行时间:", end_time-start_time)

start_time = datetime.datetime.now()
ndarray_list = np.array(python_list)
end_time = datetime.datetime.now()
print("ndarray的运行时间:", end_time-start_time)

输出

list的运行时间: 0:00:22.598421
ndarray的运行时间: 0:00:04.590315

啧啧啧,这能比???

为啥Ndarray这么快

  1. 内存块风格

    ndarray到底跟原生python列表有什么不同呢,请看一张图:

    从图中我们可以看出ndarray在存储数据的时候,数据与数据的地址都是连续的,这样就给使得批量操作数组元素时速度更快。

    这是因为ndarray中的所有元素的类型都是相同的,而Python列表中的元素类型是任意的,所以ndarray在存储元素时内存可以连续,而python原生list就只能通过寻址方式找到下一个元素,这虽然也导致了在通用性能方面Numpy的ndarray不及Python原生list,但在科学计算中,Numpy的ndarray就可以省掉很多循环语句,代码使用方面比Python原生list简单的多。

  2. ndarray支持并行化运算(向量化运算)

    numpy内置了并行运算功能,当系统有多个核心时,做某种计算时,numpy会自动做并行计算

  3. 效率远高于纯Python代码

    Numpy底层使用C语言编写,内部解除了GIL(全局解释器锁),其对数组的操作速度不受Python解释器的限制,所以,其效率远高于纯Python代码。


Ndarray的属性

属性 说明
ndarray.ndim 秩,即轴的数量或维度的数量
ndarray.shape 数组的维度,对于矩阵,n 行 m 列
ndarray.size 数组元素的总个数,相当于 .shape 中 n*m 的值
ndarray.dtype ndarray 对象的元素类型
ndarray.itemsize ndarray 对象中每个元素的大小,以字节为单位
ndarray.flags ndarray 对象的内存信息
ndarray.real ndarray元素的实部
ndarray.imag ndarray 元素的虚部
ndarray.data 包含实际数组元素的缓冲区,由于一般通过数组的索引获取元素,所以通常不需要使用这个属性。
score = np.array([[80, 89, 86, 67, 79],
                  [78, 97, 89, 67, 81],
                  [90, 94, 78, 67, 74],
                  [91, 91, 90, 67, 69],
                  [76, 87, 75, 67, 86],
                  [70, 79, 84, 67, 84],
                  [94, 92, 93, 67, 64],
                  [86, 85, 83, 67, 80]])
print(type(score))

print(score.shape)  # (8, 5)
print(score.ndim)  # 2
print(score.size)  # 40
print(score.dtype)  # int32 默认
print(score.itemsize)  # 4

输出

<class 'numpy.ndarray'>
(8, 5)
2
40
int32
4

Ndarray数据类型

名称 描述
bool_ 布尔型数据类型(True 或者 False)
int_ 默认的整数类型(类似于 C 语言中的 long,int32 或 int64)
intc 与 C 的 int 类型一样,一般是 int32 或 int 64
intp 用于索引的整数类型(类似于 C 的 ssize_t,一般情况下仍然是 int32 或 int64)
int8 字节(-128 to 127)
int16 整数(-32768 to 32767)
int32 整数(-2147483648 to 2147483647)
int64 整数(-9223372036854775808 to 9223372036854775807)
uint8 无符号整数(0 to 255)
uint16 无符号整数(0 to 65535)
uint32 无符号整数(0 to 4294967295)
uint64 无符号整数(0 to 18446744073709551615)
float_ float64 类型的简写
float16 半精度浮点数,包括:1 个符号位,5 个指数位,10 个尾数位
float32 单精度浮点数,包括:1 个符号位,8 个指数位,23 个尾数位
float64 双精度浮点数,包括:1 个符号位,11 个指数位,52 个尾数位
complex_ complex128 类型的简写,即 128 位复数
complex64 复数,表示双 32 位浮点数(实数部分和虚数部分)
complex128 复数,表示双 64 位浮点数(实数部分和虚数部分)

numpy 的数值类型实际上是 dtype 对象的实例,并对应唯一的字符,包括 np.bool_,np.int32,np.float32,等等。

import numpy as np
data = np.array([1.1, 1.2, 1.3], dtype=np.float32)
print(data)
print(data.dtype)

输出

[1.1 1.2 1.3]
float32

Ndarray常用操作

生成0和1数组

zero = np.zeros([3, 4])
print(zero)
print("元素类型", zero.dtype)

print("------------------")

one = np.ones([3, 4], dtype=np.int_)
print(one)

输出

[[0. 0. 0. 0.]
 [0. 0. 0. 0.]
 [0. 0. 0. 0.]]
元素类型 float64
------------------
[[1 1 1 1]
 [1 1 1 1]
 [1 1 1 1]]

从现有的数组中生成

print("-----array(深拷贝)-----")
data01[0, 3] = 100
print("原始数据:", score[0])
print("array产生的数组修改后的数据(data01):", data01[0])
print("array产生的数组修改后的数据(score):", score[0])

print("-----asarray(浅拷贝)-----")
data02[0, 3] = 110
print("原始数据:", score[0])
print("array产生的数组修改后的数据(data02):", data02[0])
print("array产生的数组修改后的数据(score):", score[0])

print("-----copy(深拷贝)-----")
data03[0, 3] = 120
print("原始数据:", score[0])
print("array产生的数组修改后的数据(data02):", data03[0])
print("array产生的数组修改后的数据(score):", score[0])

输出

-----array(深拷贝)-----
原始数据: [80 89 86 67 79]
array产生的数组修改后的数据(data01)[ 80  89  86 100  79]
array产生的数组修改后的数据(score)[80 89 86 67 79]
-----asarray(浅拷贝)-----
原始数据: [ 80  89  86 110  79]
array产生的数组修改后的数据(data02)[ 80  89  86 110  79]
array产生的数组修改后的数据(score)[ 80  89  86 110  79]
-----copy(深拷贝)-----
原始数据: [ 80  89  86 110  79]
array产生的数组修改后的数据(data02)[ 80  89  86 120  79]
array产生的数组修改后的数据(score)[ 80  89  86 110  79]

生成固定范围的数组

arr = np.linspace(0, 10, 5)  # [0, 10] 等距离,num默认是50
print(arr)
arr = np.arange(0, 10, 2.5)  #  [a, b) c是步长,step默认是1
print(arr)

输出

[ 0.   2.5  5.   7.5 10. ]
[0.  2.5 5.  7.5]

均匀分布

data = np.random.uniform(-1, 1, 1000000)
plt.figure(figsize=(20, 8), dpi=80)
plt.hist(data, bins=1000)
plt.show()


正态分布

data = np.random.normal(1.75, 0.1, 100000)
plt.figure(figsize=(20, 8), dpi=80)
plt.hist(data, bins=1000)
plt.show()


案例:随机生成8只股票2周的交易日涨幅数据

stock_change = np.random.normal(loc=0, scale=1, size=(8, 10))
print(stock_change)
# 获取第一个股票的前3个交易日的涨跌幅数据
stock_change[0, :3]

输出

[[-0.03469926,  1.68760014,  0.05915316,  2.4473136 , -0.61776756,
  -0.56253866, -1.24738637,  0.48320978,  1.01227938, -1.44509723],
 [-1.8391253 , -1.10142576,  0.09582268,  1.01589092, -1.20262068,
  0.76134643, -0.76782097, -1.11192773,  0.81609586,  0.07659056],
 [-0.74293074, -0.7836588 ,  1.32639574, -0.52735663,  1.4167841 ,
  2.10286726, -0.21687665, -0.33073563, -0.46648617,  0.07926839],
 [ 0.45914676, -0.78330377, -1.10763289,  0.10612596, -0.63375855,
  -1.88121415,  0.6523779 , -1.27459184, -0.1828502 , -0.76587891],
 [-0.50413407, -1.35848099, -2.21633535, -1.39300681,  0.13159471,
  0.65429138,  0.32207255,  1.41792558,  1.12357799, -0.68599018],
 [ 0.3627785 ,  1.00279706, -0.68137875, -2.14800075, -2.82895231,
  -1.69360338,  1.43816168, -2.02116677,  1.30746801,  1.41979011],
 [-2.93762047,  0.22199761,  0.98788788,  0.37899235,  0.28281886,
  -1.75837237, -0.09262863, -0.92354076,  1.11467277,  0.76034531],
 [-0.39473551,  0.28402164, -0.15729195, -0.59342945, -1.0311294 ,
  -1.07651428,  0.18618331,  1.5780439 ,  1.31285558,  0.10777784]]


[ 0.75372007  0.37205739 -0.45823456]

形状修改

print(stock_change.reshape((10, 8)).shape)
stock_change.resize((10, 8))
print(stock_change.shape)
print(stock_change.T.shape)

输出

(10, 8)
(10, 8)
(8, 10)

序列化

print(stock_change.tostring())

输出

b'\x1cDY5\xba\xf6\xfd?\x1f!\xa4"H\x12\xd3\xbf\x8a\xb8\n"n\x86\xe8?V\xc8E\x01\x0c\xba\xe4?#\xa5\xcd4\xfd8\xdc?-\xfb\x01\x9by\xee\xb5?\x97\xca\xc6\xd3\xaf;\xe0?\x9b;\x1f\xd9d\x17\xfb\xbfY\x10\xca\x9c\x99D\xe5?d\xbf\x93\xfe\xfbr\xf1\xbfQ\x89\x0f\xca\x88:\xf7\xbfo\xdd22=\x9d\xf2\xbf\xa1,\xbc\xc7>B\xf0\xbfl\x8d\......省略

数组去重

data = np.array([[1,2,3,4],[3,4,5,6]])
print(np.unique(data))
print(set(data.flatten()))

输出

[1 2 3 4 5 6]
{1, 2, 3, 4, 5, 6}


Ndarray运算

逻辑运算

import numpy as np

stock_change = np.random.normal(1.5, 2, (8, 10))
# 逻辑判断, 如果涨跌幅大于等于0.5就标记为True 否则为False
print(stock_change >= 0.5)
# 修改所有涨幅小于0.5的为0.5
stock_change[stock_change < 0.5] = 0.5

输出

[[False  True  True  True False  True False  True False  True]
 [False  True  True  True  True  True False  True  True False]
 [ True  True  True False  True  True False  True False False]
 [ True  True False  True  True  True False False  True False]
 [ True  True  True False  True  True  True False False  True]
 [ True  True  True  True  True  True  True  True  True False]
 [ True  True  True  True  True  True  True  True  True  True]
 [ True  True  True  True  True  True  True  True  True  True]]

where运算

temp = stock_change[:4, :4]
print(temp)
print(np.where(temp > 0.5, 1, 0))
# 判断前四个股票前四天的涨跌幅 大于0.5并且小于1的,换为1,否则为0
# 判断前四个股票前四天的涨跌幅 大于0.5或者小于-0.5的,换为1,否则为0
print(np.where(np.logical_and(temp > 0.5, temp < 1), 1, 0))
print(np.where(np.logical_or(temp > 0.5, temp < -0.5), 1, 0))

输出

[[ 2.11334994  2.75371732 -1.45919878 -0.54644526]
 [ 2.50898042  2.49334823  3.46757975  1.67814258]
 [-1.63742684  2.21757841  0.51642822 -1.10437119]
 [ 1.08439702  0.2920416   0.31753524  2.20334352]]

[[1 1 0 0]
 [1 1 1 1]
 [0 1 1 0]
 [1 0 0 1]]

[[0 0 0 0]
 [0 0 0 0]
 [0 0 1 0]
 [0 0 0 0]]

[[1 1 1 1]
 [1 1 1 1]
 [1 1 1 1]
 [1 0 0 1]]

最大值最小值

print(np.max(stock_change))
# 0代表列,1代表行
print(np.max(stock_change, axis=0))
print(np.max(stock_change, axis=1))
# 最大值的位置
print(np.argmax(stock_change, axis=0))
print(np.argmax(stock_change, axis=1))

输出

6.693146605729187
[6.69314661 2.82844572 5.81205157 5.35317406 4.01567427 5.66452237
 2.61476055 3.99797746 4.19418698 5.17729721]
[4.48925181 4.29683647 3.99797746 2.09293751 5.81205157 5.35317406
 5.17729721 6.69314661]
[7 4 4 5 6 7 2 2 5 6]
[5 0 7 1 2 3 9 0]

广播机制

简单理解:对两个数组,分别比较他们的每一个维度(若其中一个数组没有当前维度则忽略),满足:

  • 数组拥有相同形状。
  • 当前维度的值相等。
  • 当前维度的值有一个是 1
A (3d array):         256 × 256 × 3
B (1d array):                        3
Result (3d array):   256 × 256 × 3

A (4d array):         9 × 1 × 7 × 1
B (3d array):             8 × 1 × 5
Result (4d array):   9 × 8 × 7 × 5

A (2d array):         5 × 4
B (1d array):             1
Result (2d array):   5 × 4

A (3d array):         15 × 3 × 5
B (3d array):         15 × 1 × 1
Result (3d array):   15 × 3 × 5

矩阵运算

两种方法存储矩阵

  1. ndarray 二维数组
  2. matrix数据结构

data = np.array([[80, 86],
                [82, 80],
                [85, 78],
                [90, 90],
                [86, 82],
                [82, 90],
                [78, 80],
                [92, 94]])

# matrix存储矩阵
data_mat = np.mat([[80, 86],
                    [82, 80],
                    [85, 78],
                    [90, 90],
                    [86, 82],
                    [82, 90],
                    [78, 80],
                    [92, 94]])

weights = np.array([[2], [3]])
weights_mat = np.mat([[2], [3]])
# 矩阵乘法
print(np.matmul(data, weights))
print(np.dot(data, weights))
print(data @ weights)
print(data_mat * weights_mat)

输出

[[418]
 [404]
 [404]
 [450]
 [418]
 [434]
 [396]
 [466]]
.....都是一样的,就省略了

合并

data_1 = np.array([1, 2, 3])
data_2 = np.array([5, 6, 7])
print(np.hstack((data_1, data_2)))  # 水平拼接 horizontally
print(np.vstack((data_1, data_2)))  # 竖直拼接 vertically

data_1 = np.array([[1, 2, 3], [2, 3, 4], [3, 4, 5]])
data_2 = np.array([[5, 6, 7]])
print(np.concatenate((data_1, data_2), axis=0))  # 自定义合并
print(np.concatenate((data_1, data_2.T), axis=1))  # 自定义合并

输出

[1 2 3 5 6 7]

[[1 2 3]
 [5 6 7]]

[[1 2 3]
 [2 3 4]
 [3 4 5]
 [5 6 7]]

[[1 2 3 5]
 [2 3 4 6]
 [3 4 5 7]]

分割

print("-----分割-----")
data = np.arange(0, 10)
print(np.split(data, 2))
print(np.split(data, [4, 6]))

输出

[array([0, 1, 2, 3, 4]), array([5, 6, 7, 8, 9])]
[array([0, 1, 2, 3]), array([4, 5]), array([6, 7, 8, 9])]

IO操作和数值处理

文件内容

id,value1,value2,value3
1,123,1.4,23
2,110,,18
3,,2.1,19

代码

test = np.genfromtxt("test.csv", delimiter=",")
print(test)
print(type(test[0, 0]))

输出

[[  nan   nan   nan   nan]
 [  1.  123.    1.4  23. ]
 [  2.  110.    nan  18. ]
 [  3.    nan   2.1  19. ]]
<class 'numpy.float64'>

我们可以看到,出现了缺失值nan。

为什么呢?当我们读取本地的文件为float的时候,如果数据类型不对(或者为None),就会出现nan

上方的[0,0]明明是字符串,但是是按float读取的,就出现了nan。这是由ndarray的数据结构决定的


总结



Pandas

介绍

Pandas 是 Python 的核心数据分析支持库,提供了快速、灵活、明确的数据结构,旨在简单、直观地处理关系型、标记型数据。Pandas 的目标是成为 Python 数据分析实践与实战的必备高级工具,其长远目标是成为最强大、最灵活、可以支持任何语言的开源数据分析工具。经过多年不懈的努力,Pandas 离这个目标已经越来越近了。

Pandas 适用于处理以下类型的数据:

  • 与 SQL 或 Excel 表类似的,含异构列的表格数据;
  • 有序和无序(非固定频率)的时间序列数据;
  • 带行列标签的矩阵数据,包括同构或异构型数据;
  • 任意其它形式的观测、统计数据集, 数据转入 Pandas 数据结构时不必事先标记。

Pandas 的主要数据结构是 Series(一维数据)与 DataFrame(二维数据),这两种数据结构足以处理金融、统计、社会科学、工程等领域里的大多数典型用例。对于 R 用户,DataFrame 提供了比 R 语言 data.frame 更丰富的功能。Pandas 基于 NumPy 开发,可以与其它第三方科学计算支持库完美集成。

Pandas 就像一把万能瑞士军刀,下面仅列出了它的部分优势 :

  • 处理浮点与非浮点数据里的缺失数据,表示为 NaN;
  • 大小可变:插入或删除 DataFrame 等多维对象的列;
  • 自动、显式数据对齐:显式地将对象与一组标签对齐,也可以忽略标签,在 Series、DataFrame 计算时自动与数据对齐;
  • 强大、灵活的分组(group by)功能:拆分-应用-组合数据集,聚合、转换数据;
  • 把 Python 和 NumPy 数据结构里不规则、不同索引的数据轻松地转换为 DataFrame 对象;
  • 基于智能标签,对大型数据集进行切片、花式索引、子集分解等操作;
  • 直观地合并(merge)、连接(join)数据集;
  • 灵活地重塑(reshape)、透视(pivot)数据集;
  • 轴支持结构化标签:一个刻度支持多个标签;
  • 成熟的 IO 工具:读取文本文件(CSV 等支持分隔符的文件)、Excel 文件、数据库等来源的数据,利用超快的 HDF5 格式保存 / 加载数据;
  • 时间序列:支持日期范围生成、频率转换、移动窗口统计、移动窗口线性回归、日期位移等时间序列功能。

这些功能主要是为了解决其它编程语言、科研环境的痛点。处理数据一般分为几个阶段:数据整理与清洗、数据分析与建模、数据可视化与制表,Pandas 是处理数据的理想工具。

其它说明:

  • Pandas 速度很快。Pandas 的很多底层算法都用 Cython 优化过。然而,为了保持通用性,必然要牺牲一些性能,如果专注某一功能,完全可以开发出比 Pandas 更快的专用工具。
  • Pandas 是 statsmodels 的依赖项,因此,Pandas 也是 Python 中统计计算生态系统的重要组成部分。
  • Pandas 已广泛应用于金融领域。

数据结构

维数 名称 描述
1 Series 带标签的一维同构数组
2 DataFrame 带标签的,大小可变的,二维异构表格

Pandas 数据结构就像是低维数据的容器。比如,DataFrame 是 Series 的容器,Series 则是标量的容器。使用这种方式,可以在容器中以字典的形式插入或删除对象。

此外,通用 API 函数的默认操作要顾及时间序列与截面数据集的方向。多维数组存储二维或三维数据时,编写函数要注意数据集的方向,这对用户来说是一种负担;如果不考虑 C 或 Fortran 中连续性对性能的影响,一般情况下,不同的轴在程序里其实没有什么区别。Pandas 里,轴的概念主要是为了给数据赋予更直观的语义,即用“更恰当”的方式表示数据集的方向。这样做可以让用户编写数据转换函数时,少费点脑子。

处理 DataFrame 等表格数据时,index(行)或 columns(列)比 axis 0 和 axis 1 更直观。用这种方式迭代 DataFrame 的列,代码更易读易懂:

大小可变与数据复制

Pandas 所有数据结构的值都是可变的,但数据结构的大小并非都是可变的,比如,Series 的长度不可改变,但 DataFrame 里就可以插入列。

Pandas 里,绝大多数方法都不改变原始的输入数据,而是复制数据,生成新的对象。 一般来说,原始输入数据不变更稳妥。


DataFrame

创建

import pandas as pd
import numpy as np

stock_change = np.random.normal(loc=0, scale=1, size=(8, 5))
# 添加行索引
stock = ["股票{}".format(i) for i in range(8)]
# 添加列索引
date = pd.date_range(start="20180101", periods=5, freq="B")
print(pd.DataFrame(stock_change, index=stock, columns=date))

输出

     2018-01-01  2018-01-02  2018-01-03  2018-01-04  2018-01-05
股票0   -0.486596   -1.022783    0.887238   -2.115517   -0.797992
股票1   -1.248282    0.070521   -0.529684   -1.883903   -0.153754
股票2   -0.267424   -0.105139    1.883874    0.680138   -0.371504
股票3   -1.378413   -0.315324   -0.094621    0.041267    0.446303
股票4   -0.177192    0.981938    1.864708    0.979935   -0.368555
股票5    0.156191   -0.231942    0.812946   -0.999557    1.179616
股票6   -0.464277    0.008084   -0.821086   -0.154590   -1.361048
股票7    0.235237    0.159509    0.034401   -1.820553    2.109502

属性

print(data.shape)
print(data.index)   # 行索引
print(data.columns)  # 列索引
print(data.values)
print(data.T)
print(data.head(3))  # 返回前3行,默认是5
print(data.tail())  # 默认返回后5行

修改索引,重置索引

# 修改索引
print("-----修改索引-----")
# 不能进行单个修改,只能整体修改
# data.index[1] = "股票88"
data.index = ["股票{}".format(i*i) for i in range(8)]
print(data.index)

# 重置索引
print(data.reset_index())
print(data.reset_index(drop=True))

输出

Index(['股票0', '股票1', '股票4', '股票9', '股票16', '股票25', '股票36', '股票49'], dtype='object')
  index  2018-01-01 00:00:00  ...  2018-01-04 00:00:00  2018-01-05 00:00:00
0   股票0             0.847878  ...             0.456471            -1.729287
1   股票1            -1.521886  ...            -0.102665             1.081724
2   股票4            -0.256047  ...            -0.630488             2.886318
3   股票9             0.769578  ...            -0.320012             0.754771
4  股票16            -0.401677  ...            -1.381074             0.191465
5  股票25             1.865108  ...             1.219035             0.937094
6  股票36            -0.317925  ...            -0.447988            -1.343928
7  股票49            -1.760294  ...             0.248152             0.475328

[8 rows x 6 columns]
   2018-01-01  2018-01-02  2018-01-03  2018-01-04  2018-01-05
0    0.847878   -0.043265   -0.470509    0.456471   -1.729287
1   -1.521886   -1.308316   -1.427331   -0.102665    1.081724
2   -0.256047   -0.269125   -1.229579   -0.630488    2.886318
3    0.769578    0.030514   -0.141035   -0.320012    0.754771
4   -0.401677    1.628133    1.290187   -1.381074    0.191465
5    1.865108    0.329742   -0.790539    1.219035    0.937094
6   -0.317925    0.518043   -0.997188   -0.447988   -1.343928
7   -1.760294    0.609189   -1.660057    0.248152    0.475328

设置新索引

# 设置新索引
df = pd.DataFrame({'month': [1, 4, 7, 10],
                    'year': [2012, 2014, 2013, 2014],
                    'sale':[55, 40, 84, 31]})
print(df.set_index("month", drop=True))
new_df = df.set_index(["year", "month"], drop=True)
print(new_df)
print(new_df.index)

输出

       year  sale
month            
1      2012    55
4      2014    40
7      2013    84
10     2014    31

            sale
year month      
2012 1        55
2014 4        40
2013 7        84
2014 10       31

MultiIndex([(2012,  1),
            (2014,  4),
            (2013,  7),
            (2014, 10)],
           names=['year', 'month'])

索引操作

# 先列后行
print(data["open"]["2018-02-26"])
# 先行后列
print(data.loc["2018-02-26"]["open"])
print(data.iloc[1][0])
# 组合索引
print(data.iloc[0:4, data.columns.get_indexer(["open", "close", "high", "low"])])

输出

22.8
22.8
22.8
             open  close   high    low
2018-02-27  23.53  24.16  25.88  23.53
2018-02-26  22.80  23.53  23.78  22.80
2018-02-23  22.88  22.82  23.37  22.71
2018-02-22  22.25  22.28  22.76  22.02

Series

import numpy as np
import pandas as pd

data = pd.Series(np.arange(10))
print(data, end="\n\n")

data = pd.Series([6.5, 2.6, 9, 23.5, 4], index=[1, 2, 3, 4, 5])
print(data, end="\n\n")

data = pd.Series({"red": 100, "blue": 200, "yellow": 1000, "green": 500})
print(data, end="\n\n")

输出

0    0
1    1
2    2
3    3
4    4
5    5
6    6
7    7
8    8
9    9
dtype: int32

1     6.5
2     2.6
3     9.0
4    23.5
5     4.0
dtype: float64

red        100
blue       200
yellow    1000
green      500
dtype: int64

修改控制台显示

查看pandas的文档,这个问题可以通过pandas内置的set_option()方法解决,从上面的属性设置中可以看到,与显示的行数列数有关的选项主要是【display】中的【max_columns,max_rows,max_colwidth,line_width】等这几项,只需要将这几项属性值设置得大一些就可以解决。

import pandas as pd

pd.set_option('display.max_columns', 1000)
pd.set_option('display.width', 1000)
pd.set_option('display.max_colwidth', 1000)
pd.set_option('display.max_rows', 1000)

排序

import pandas as pd

pd.set_option('display.max_columns', 1000)
pd.set_option('display.width', 1000)
pd.set_option('display.max_colwidth', 1000)
# pd.set_option('display.max_rows', 1000)


data = pd.read_csv("stock_day.csv")
# 按内容进行排序
print(data.sort_values(by="high", ascending=False).head(), end="\n\n\n")
print(data.sort_values(by=["high", "close"], ascending=False).head(), end="\n\n\n")
# 按索引进行排序
print(data.sort_index(ascending=False).head(), end="\n\n\n")


sr = data["open"]
# 只有一个值,不需要指定了
print(sr.sort_values().head(), end="\n\n\n")

输出

             open   high  close    low     volume  price_change  p_change     ma5    ma10    ma20      v_ma5     v_ma10     v_ma20  turnover
2015-06-10  34.10  36.35  33.85  32.23  269033.12          0.51      1.53  30.538  28.660  27.424  176305.53  152266.76  149078.50      9.21
2015-06-12  34.69  35.98  35.21  34.01  159825.88          0.82      2.38  33.420  30.513  28.683  197248.25  154480.41  153888.00      5.47
2017-10-31  32.62  35.22  34.44  32.20  361660.88          2.38      7.42  32.350  30.077  28.406  372824.04  334531.90  241075.48      9.05
2015-06-15  34.99  34.99  31.69  31.69  199369.53         -3.52    -10.00  33.696  30.964  29.114  201148.55  164608.26  158362.17      6.82
2015-06-11  33.17  34.98  34.39  32.51  173075.73          0.54      1.59  32.016  29.572  28.036  193141.45  151337.71  151428.57      5.92


             open   high  close    low     volume  price_change  p_change     ma5    ma10    ma20      v_ma5     v_ma10     v_ma20  turnover
2015-06-10  34.10  36.35  33.85  32.23  269033.12          0.51      1.53  30.538  28.660  27.424  176305.53  152266.76  149078.50      9.21
2015-06-12  34.69  35.98  35.21  34.01  159825.88          0.82      2.38  33.420  30.513  28.683  197248.25  154480.41  153888.00      5.47
2017-10-31  32.62  35.22  34.44  32.20  361660.88          2.38      7.42  32.350  30.077  28.406  372824.04  334531.90  241075.48      9.05
2015-06-15  34.99  34.99  31.69  31.69  199369.53         -3.52    -10.00  33.696  30.964  29.114  201148.55  164608.26  158362.17      6.82
2015-06-11  33.17  34.98  34.39  32.51  173075.73          0.54      1.59  32.016  29.572  28.036  193141.45  151337.71  151428.57      5.92


             open   high  close    low    volume  price_change  p_change     ma5    ma10    ma20     v_ma5    v_ma10    v_ma20  turnover
2018-02-27  23.53  25.88  24.16  23.53  95578.03          0.63      2.68  22.942  22.142  22.875  53782.64  46738.65  55576.11      2.39
2018-02-26  22.80  23.78  23.53  22.80  60985.11          0.69      3.02  22.406  21.955  22.942  40827.52  42736.34  56007.50      1.53
2018-02-23  22.88  23.37  22.82  22.71  52914.01          0.54      2.42  21.938  21.929  23.022  35119.58  41871.97  56372.85      1.32
2018-02-22  22.25  22.76  22.28  22.02  36105.01          0.36      1.64  21.446  21.909  23.137  35397.58  39904.78  60149.60      0.90
2018-02-14  21.49  21.99  21.92  21.48  23331.04          0.44      2.05  21.366  21.923  23.253  33590.21  42935.74  61716.11      0.58


2015-03-02    12.25
2015-09-02    12.30
2015-03-03    12.52
2015-03-04    12.80
2015-03-05    12.88
Name: open, dtype: float64

运算

算术运算

print(data["open"].add(3).head())
print(data.sub(100).head())
print(data["close"].sub(data["open"]).head())

输出

2018-02-27    26.53
2018-02-26    25.80
2018-02-23    25.88
2018-02-22    25.25
2018-02-14    24.49

Name: open, dtype: float64
             open   high  close    low  ...     v_ma5    v_ma10    v_ma20  turnover
2018-02-27 -76.47 -74.12 -75.84 -76.47  ...  53682.64  46638.65  55476.11    -97.61
2018-02-26 -77.20 -76.22 -76.47 -77.20  ...  40727.52  42636.34  55907.50    -98.47
2018-02-23 -77.12 -76.63 -77.18 -77.29  ...  35019.58  41771.97  56272.85    -98.68
2018-02-22 -77.75 -77.24 -77.72 -77.98  ...  35297.58  39804.78  60049.60    -99.10
2018-02-14 -78.51 -78.01 -78.08 -78.52  ...  33490.21  42835.74  61616.11    -99.42

[5 rows x 14 columns]
2018-02-27    0.63
2018-02-26    0.73
2018-02-23   -0.06
2018-02-22    0.03
2018-02-14    0.43
dtype: float64

逻辑运算

print(data[data["open"] > 33])
print(data[(data["open"] > 33) & (data["low"] < 33)])
print(data.query("open > 33 & low < 33"))
print(data["turnover"].isin([2.39, 1.53, 1.32]))

输出

             open   high  close  ...     v_ma10     v_ma20  turnover
2017-11-01  33.85  34.34  33.83  ...  346829.10  233701.92      5.81
2015-06-15  34.99  34.99  31.69  ...  164608.26  158362.17      6.82
2015-06-12  34.69  35.98  35.21  ...  154480.41  153888.00      5.47
2015-06-11  33.17  34.98  34.39  ...  151337.71  151428.57      5.92
2015-06-10  34.10  36.35  33.85  ...  152266.76  149078.50      9.21

[5 rows x 14 columns]

             open   high  close  ...     v_ma10     v_ma20  turnover
2015-06-15  34.99  34.99  31.69  ...  164608.26  158362.17      6.82
2015-06-11  33.17  34.98  34.39  ...  151337.71  151428.57      5.92
2015-06-10  34.10  36.35  33.85  ...  152266.76  149078.50      9.21
[3 rows x 14 columns]
             open   high  close  ...     v_ma10     v_ma20  turnover
2015-06-15  34.99  34.99  31.69  ...  164608.26  158362.17      6.82
2015-06-11  33.17  34.98  34.39  ...  151337.71  151428.57      5.92
2015-06-10  34.10  36.35  33.85  ...  152266.76  149078.50      9.21
[3 rows x 14 columns]


2018-02-27     True
2018-02-26     True
2018-02-23     True
2018-02-22    False
2018-02-14    False
              ...  
2015-03-06    False
2015-03-05    False
2015-03-04    False
2015-03-03    False
2015-03-02    False

统计运算

print(data.describe())
data.max(axis=1)  # 默认是0(列)
print(data.idxmax())  

输出

50%就是中位数了

[8 rows x 14 columns]
2018-02-27     95578.03
2018-02-26     60985.11
2018-02-23     56372.85
2018-02-22     60149.60
2018-02-14     61716.11
                ...    
2015-03-06    179831.72
2015-03-05     98904.79
2015-03-04    100812.93
2015-03-03    139071.61
2015-03-02     96291.73
Length: 643, dtype: float64


open            2015-06-15
high            2015-06-10
close           2015-06-12
low             2015-06-12
volume          2017-10-26
price_change    2015-06-09
p_change        2015-08-28
ma5             2015-06-15
ma10            2015-06-18
ma20            2015-06-18
v_ma5           2017-10-26
v_ma10          2017-11-02
v_ma20          2017-11-15
turnover        2017-10-26
dtype: object

累计统计函数

函数 解释
cumprod 累积
cumsum 累和
cummin 累计中最小的值
cummax 累计中最大的值
print(data["p_change"].sort_index().cumsum())
data["p_change"].sort_index().cumsum().plot()
plt.show()

输出

2015-03-02      2.62
2015-03-03      4.06
2015-03-04      5.63
2015-03-05      7.65
2015-03-06     16.16
               ...  
2018-02-14    112.59
2018-02-22    114.23
2018-02-23    116.65
2018-02-26    119.67
2018-02-27    122.35
Name: p_change, Length: 643, dtype: float64


自定义显示

# 自定义运算
print(data[["open", "close"]].apply(lambda x: x.max() - x.min(), axis=0))

输出

open     22.74
close    22.85
dtype: float64

图形显示

import pandas as pd
# 一定要导入
import matplotlib.pyplot as plt

data["p_change"].sort_index().cumsum().plot()
# 展示
plt.show()

import pandas as pd
import matplotlib.pyplot as plt

data = pd.read_csv("stock_day.csv")

data.plot(x="volume", y="turnover", kind="scatter")
plt.show()

data.plot(x="high", y="low", kind="scatter")
plt.show()

在这里插入图片描述


文件的读取和存储

读取CSV

import pandas as pd

# 读取csv
# 带字段
data = pd.read_csv("stock_day.csv", usecols=["high", "low", "open", "close"])
print(data)

# 不带字段,自己指定
data = pd.read_csv("stock_day2.csv",  names=["open", "high", "close", "low", "volume", "price_change", "p_change", "ma5", "ma10", "ma20", "v_ma5", "v_ma10", "v_ma20", "turnover"])
print(data)

# 保存'open'列的数据
data[:10]["open"].to_csv("test_open.csv")
data[:10].to_csv("test_open2.csv", columns=["open"], index=False, mode="w", header=False)
print(pd.read_csv("test_open2.csv"))

输出

   23.53
0  22.80
1  22.88
2  22.25
3  21.49
4  21.40
5  20.70
6  21.20
7  21.79
8  22.69

文件


读取HDF5

import pandas as pd

# 读取文件
day_close = pd.read_hdf("stock_data/day/day_close.h5")
print(day_close)

# 保存文件,指定key
day_close.to_hdf("test_day.h5", key="close")
pd.read_hdf("stock_data/day/day_open.h5").to_hdf("test_day.h5", key="open")

# 此时有两个test_day.h5文件,必须要指定key才能读取
print(pd.read_hdf("test_day.h5", key="close"))
print(pd.read_hdf("test_day.h5", key="open"))


读取Json

import pandas as pd

data = pd.read_json("Sarcasm_Headlines_Dataset.json", orient="records", lines=True)
print(data)

data.to_json("test.json", orient="records", lines=True)

缺失值处理(nan)

import pandas as pd
import numpy as np


movie = pd.read_csv("IMDB/IMDB-Movie-Data.csv")

# 缺失值判断
print(np.any(pd.isna(movie)))  # 为True,就表明存在nan
print(np.all(pd.notna(movie)))  # 为False,就表明存在nan
print(pd.isna(movie).any())
print(pd.isnull(movie).any())
print(pd.notnull(movie).all())

# 缺失值处理
# 方法一:删除含有缺失值的样本
movie_drop = movie.dropna()
# movie_drop = movie.dropna(inplace=True)


# 方法二:替换,inplace在原表中修改
movie["Revenue (Millions)"].fillna(movie["Revenue (Millions)"].mean, inplace=True)
movie["Metascore"].fillna(movie["Metascore"].mean, inplace=True)
print(pd.isna(movie).any())

输出

True
False

Rank                  False
Title                 False
Genre                 False
Description           False
Director              False
Actors                False
Year                  False
Runtime (Minutes)     False
Rating                False
Votes                 False
Revenue (Millions)     True
Metascore              True
dtype: bool

...其他的省略了

缺失值处理(其他标记)

将特殊标记替换成我们的nan,然后按nan的方式进行处理就可以了

# 获取数据
path = "https://archive.ics.uci.edu/ml/machine-learning-databases/breast-cancer-wisconsin/breast-cancer-wisconsin.data"
name = ["Sample code number", "Clump Thickness", "Uniformity of Cell Size", "Uniformity of Cell Shape", "Marginal Adhesion", "Single Epithelial Cell Size", "Bare Nuclei", "Bland Chromatin", "Normal Nucleoli", "Mitoses", "Class"]
data = pd.read_csv(path, names=name)

print(data[data["Bare Nuclei"] == "?"])
# 替换缺失值
data_new = data.replace(to_replace="?", value=np.nan)
print(data_new[data_new["Bare Nuclei"].isna()])


# 处理缺失值
# 方法一:删除
data_new.dropna(inplace=True)
print(data_new.isna().any())
# 方法二:替换(以处理nan的方式处理就可以了)

输出(部分输出)

     Sample code number  Clump Thickness  Uniformity of Cell Size  Uniformity of Cell Shape  Marginal Adhesion  Single Epithelial Cell Size Bare Nuclei  Bland Chromatin  Normal Nucleoli  Mitoses  Class
23              1057013                8                        4                         5                  1                            2           ?                7                3        1      4
40              1096800                6                        6                         6                  9                            6           ?                7                8        1      2
139             1183246                1                        1                         1                  1                            1           ?                2                1        1      2



     Sample code number  Clump Thickness  Uniformity of Cell Size  Uniformity of Cell Shape  Marginal Adhesion  Single Epithelial Cell Size Bare Nuclei  Bland Chromatin  Normal Nucleoli  Mitoses  Class
23              1057013                8                        4                         5                  1                            2         NaN                7                3        1      4
40              1096800                6                        6                         6                  9                            6         NaN                7                8        1      2
139             1183246                1                        1                         1                  1                            1         NaN                2                1        1      2
145 


Sample code number             False
Clump Thickness                False
Uniformity of Cell Size        False
Uniformity of Cell Shape       False
Marginal Adhesion              False
Single Epithelial Cell Size    False
Bare Nuclei                    False
Bland Chromatin                False
Normal Nucleoli                False
Mitoses                        False
Class                          False
dtype: bool

数据离散化

介绍

数据离散化是一个非常重要的思想。

为什么要离散化?当以权值为下标的时候,有时候值太大,存不下。 所以把要离散化的每一个数组里面的数映射到另一个值小一点的数组里面去。

打个比方,某个题目告诉你有10^4个数,每个数大小不超过10^10,要你对这些数进行操作,那么肯定不能直接开10^10大小的数组,但是10^4的范围就完全没问题。

我们来看一下定义:离散化,把无限空间中有限的个体映射到有限的空间中去,以此提高算法的时空效率。(by百度百科)

通俗的说,离散化是在不改变数据相对大小的条件下,对数据进行相应的缩小。例如:

原数据:1,999,100000,15;处理后:1,3,4,2;

原数据:{100,200},{20,50000},{1,400};

处理后:{3,4},{2,6},{1,5};

但是离散化仅适用于只关注元素之间的大小关系而不关注元素本身的值!


操作

import pandas as pd

pd.set_option("display.max_columns", 1000)
pd.set_option("display.width", 1000)

data = pd.Series([165,174,160,180,159,163,192,184], index=['No1:165', 'No2:174','No3:160', 'No4:180', 'No5:159', 'No6:163', 'No7:192', 'No8:184'])

# 分位数分组
sr = pd.qcut(data, 3)
# 转换为one-hot编码
print(pd.get_dummies(sr, prefix="height"))

# 自定义分组(bins)
sr = pd.cut(data, 3)  # 平均分组
print(pd.get_dummies(sr, prefix="height"))

bins = [150, 165, 180, 195]
sr = pd.cut(data, bins)  # 指定分组
print(pd.get_dummies(sr, prefix="height"))

# 统计
print(sr.value_counts())

输出

         height_(158.999, 163.667]  height_(163.667, 178.0]  height_(178.0, 192.0]
No1:165                          0                        1                      0
No2:174                          0                        1                      0
No3:160                          1                        0                      0
No4:180                          0                        0                      1
No5:159                          1                        0                      0
No6:163                          1                        0                      0
No7:192                          0                        0                      1
No8:184                          0                        0                      1
         height_(158.967, 170.0]  height_(170.0, 181.0]  height_(181.0, 192.0]
No1:165                        1                      0                      0
No2:174                        0                      1                      0
No3:160                        1                      0                      0
No4:180                        0                      1                      0
No5:159                        1                      0                      0
No6:163                        1                      0                      0
No7:192                        0                      0                      1
No8:184                        0                      0                      1
         height_(150, 165]  height_(165, 180]  height_(180, 195]
No1:165                  1                  0                  0
No2:174                  0                  1                  0
No3:160                  1                  0                  0
No4:180                  0                  1                  0
No5:159                  1                  0                  0
No6:163                  1                  0                  0
No7:192                  0                  0                  1
No8:184                  0                  0                  1

(150, 165]    4
(180, 195]    2
(165, 180]    2
dtype: int64

股票案例

import pandas as pd


pd.set_option('display.max_columns', 1000)
pd.set_option('display.width', 1000)
pd.set_option('display.max_colwidth', 1000)
pd.set_option('display.max_rows', 1000)

stock = pd.read_csv("stock_day.csv")
p_change = stock["p_change"]
sr = pd.qcut(p_change, 10)
data_ = pd.get_dummies(sr, prefix="p_change")

print(data_.head())

输出


合并

按方向合并

import pandas as pd

stock = pd.read_csv("stock_day.csv")
open = pd.read_csv("stock_day.csv")

print(stock.shape)
print(pd.concat([stock, open], axis=1).shape)
print(pd.concat([stock, open], axis=0).shape)

输出

(643, 14)
(643, 28)
(1286, 14)

按索引合并

pandas中的merge()函数类似于SQL中join的用法,可以将不同数据集依照某些字段(属性)进行合并操作,得到一个新的数据集。

def merge(left, right, how: str = "inner",on=None,left_on=None, right_on=None, left_index: bool = False,right_index: bool = False,sort: bool = False, suffixes=("_x", "_y"),copy: bool = True,indicator: bool = False,validate=None,) 
参数 说明
how 默认为inner,可设为inner/outer/left/right
on 根据某个字段进行连接,必须存在于两个DateFrame中(若未同时存在,则需要分别使用left_on和right_on来设置)
left_on 左连接,以DataFrame1中用作连接键的列
right_on 右连接,以DataFrame2中用作连接键的列
left_index 将DataFrame1行索引用作连接键
right_index 将DataFrame2行索引用作连接键
sort 根据连接键对合并后的数据进行排列,默认为True
suffixes 对两个数据集中出现的重复列,新数据集中加上后缀_x,_y进行区别

例子

left = pd.DataFrame({'key1': ['K0', 'K0', 'K1', 'K2'],
                    'key2': ['K0', 'K1', 'K0', 'K1'],
                    'A': ['A0', 'A1', 'A2', 'A3'],
                    'B': ['B0', 'B1', 'B2', 'B3']})

right = pd.DataFrame({'key1': ['K0', 'K1', 'K1', 'K2'],
                    'key2': ['K0', 'K0', 'K0', 'K0'],
                    'C': ['C0', 'C1', 'C2', 'C3'],
                    'D': ['D0', 'D1', 'D2', 'D3']})

print(pd.merge(left, right, how="inner", on=["key1"]), end="\n\n")
print(pd.merge(left, right, how="inner", on=["key1", "key2"]), end="\n\n")
print(pd.merge(left, right, how="left", on=["key1", "key2"]))
print(pd.merge(left, right, how="outer", on=["key1", "key2"]))

输出

  key1 key2_x   A   B key2_y   C   D
0   K0     K0  A0  B0     K0  C0  D0
1   K0     K1  A1  B1     K0  C0  D0
2   K1     K0  A2  B2     K0  C1  D1
3   K1     K0  A2  B2     K0  C2  D2
4   K2     K1  A3  B3     K0  C3  D3

  key1 key2   A   B   C   D
0   K0   K0  A0  B0  C0  D0
1   K1   K0  A2  B2  C1  D1
2   K1   K0  A2  B2  C2  D2

  key1 key2   A   B    C    D
0   K0   K0  A0  B0   C0   D0
1   K0   K1  A1  B1  NaN  NaN
2   K1   K0  A2  B2   C1   D1
3   K1   K0  A2  B2   C2   D2
4   K2   K1  A3  B3  NaN  NaN

  key1 key2    A    B    C    D
0   K0   K0   A0   B0   C0   D0
1   K0   K1   A1   B1  NaN  NaN
2   K1   K0   A2   B2   C1   D1
3   K1   K0   A2   B2   C2   D2
4   K2   K1   A3   B3  NaN  NaN
5   K2   K0  NaN  NaN   C3   D3

交叉表和透视表

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


stock = pd.read_csv("stock_day.csv")


# 准备涨跌幅数据列
stock["pona"] = np.where(stock["p_change"] > 0, 1, 0)
print(stock[stock["pona"] == 0]["pona"].value_counts(), end="\n\n")
date = pd.to_datetime(stock.index)
stock["week"] = date.weekday

# 交叉表操作
stock_wp = pd.crosstab(stock["week"], stock["pona"])
print(stock_wp, end="\n\n")

data = stock_wp.div(stock_wp.sum(axis=1), axis=0)
print(data)
data.plot(kind="bar", stacked=True)
# plt.show()

# 透视表操作
print(stock.pivot_table(["pona"], index=["week"]))

输出

0    301
Name: pona, dtype: int64

pona   0   1
week        
0     63  62
1     55  76
2     61  71
3     63  65
4     59  68

pona         0         1
week                    
0     0.504000  0.496000
1     0.419847  0.580153
2     0.462121  0.537879
3     0.492188  0.507812
4     0.464567  0.535433

          pona
week          
0     0.496000
1     0.580153
2     0.537879
3     0.507812
4     0.535433


分组与聚合

操作

import pandas as pd

col =pd.DataFrame({'color': ['white','red','green','red','green'], 'object': ['pen','pencil','pencil','ashtray','pen'],'price1':[5.56,4.20,1.30,0.56,2.75],'price2':[4.75,4.12,1.60,0.75,3.15]})
# 进行分组,在进行聚合
print(col.groupby(by="color"))
print(col.groupby(by="color")["price1"].max())
print(col["price1"].groupby(col["color"]).max())

输出

<pandas.core.groupby.generic.DataFrameGroupBy object at 0x000001A40053D1C0>

color
green    2.75
red      4.20
white    5.56
Name: price1, dtype: float64

color
green    2.75
red      4.20
white    5.56
Name: price1, dtype: float64

案例

# 准备数据
starbucks = pd.read_csv("directory.csv")
# 按国家进行分组
starbucks_brand = starbucks.groupby(by=["Country", "State/Province"]).count()["Brand"].sort_values(ascending=False).head(10)
print(starbucks_brand)
starbucks_brand.plot(kind="bar", figsize=(20, 8), fontsize=40)
plt.show()

输出

Country  State/Province
US       CA                2821
         TX                1042
GB       ENG                787
US       WA                 757
         FL                 694
         NY                 645
         IL                 575
CN       31                 551
CA       ON                 534
US       AZ                 488
Name: Brand, dtype: int64


综合案例

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


pd.set_option('display.max_columns', 1000)
pd.set_option('display.width', 1000)
pd.set_option('display.max_colwidth', 1000)
pd.set_option('display.max_rows', 1000)

# 读取数据
movie = pd.read_csv("./IMDB/IMDB-Movie-Data.csv")
print(movie.head())

# 平均分
score_aver = movie["Metascore"].mean()
print(score_aver)

# 导演的人数
movie_director = np.unique(movie["Director"])
movie_director_sum = movie_director.size
print(movie_director_sum)

# 呈现Rating,Runtime的分布情况
# movie["Rating"].plot(kind="hist", figsize=(20, 8), fontsize=50, grid="--")
plt.figure(figsize=(20, 8), dpi=80)
plt.hist(movie["Rating"], 20)
plt.xticks(np.linspace(movie["Rating"].min(), movie["Rating"].max(), 21))
plt.grid(linestyle="--", alpha=0.5)
plt.show()

# 统计电影分类情况
# movie_genre = movie.groupby(by="Genre").count()["Rank"].sort_values(ascending=False)
# 先获取电影的类别有哪些
movie_genre = [i.split(",") for i in movie["Genre"]]
movie_class = np.unique([j for i in movie_genre for j in i])
# 统计每个类别有几个电影
count = pd.DataFrame(np.zeros(shape=[1000, 20], dtype=np.int_), columns=movie_class)
for i in range(movie.count()["Rank"]):
    count.loc[i, movie_genre[i]] = 1
print(count.head())
# 画图
count.sum().sort_values(ascending=False).plot(kind="bar", figsize=(20, 8), fontsize=30, colormap="cool")
plt.show()

输出

总结



文章作者: 小莫の咕哒君
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 小莫の咕哒君 !
评论
  目录