Python机器科学计算库的使用

1.matplotlib

import matplotlib.pyplot as plt
import random

# 画出温度变化图

# 0.准备x, y坐标的数据
x = range(60)   # 生成一个列表,含60个个数,作为横坐标 [0,1,2....]
# random.uniform生成[15-18]之间的小数
y_shanghai = [random.uniform(15, 18) for i in x]

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

# 2.绘制折线图
plt.plot(x, y_shanghai)

# 3.显示图像
plt.show()

1.1.1添加自定义x,y刻度

# 增加以下两行代码

# 构造x轴刻度标签
x_ticks_label = ["11点{}分".format(i) for i in x]
# 构造y轴刻度
y_ticks = range(40)

# 修改x,y轴坐标的刻度显示
plt.xticks(x[::5], x_ticks_label[::5])  # 利用.xticks 标注x轴,注意,第一个需要传入的是数字
plt.yticks(y_ticks[::5])


# 注意:需要提前下载文本字体,并且修改配置文件,然后删除缓存文件。最后在画图的时候添加如下两句:
plt.rcParams['font.sans-serif'] = ['simhei']
plt.rcParams['axes.unicode_minus'] = False 

1.1.2添加网格

plt.grid(True, linestyle='--', alpha=0.5)

1.1.3添加x轴和y轴的描述信息

plt.xlabel("时间")
plt.ylabel("温度")
plt.title("中午11点0分到12点之间的温度变化图示", fontsize=20)

1.1.4图片的保存

# 保存图片到指定路径
plt.savefig("test.png")

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

1.1.5完整的实例

import matplotlib.pyplot as plt
import random
from pylab import mpl

# 设置显示中文字体
# mpl.rcParams["font.sans-serif"] = ["SimHei"]
# # 设置正常显示符号
# mpl.rcParams["axes.unicode_minus"] = False

# 0.准备数据
x = range(60)
y_shanghai = [random.uniform(15, 18) for i in x]

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

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

# 2.1 添加x,y轴刻度
# 构造x,y轴刻度标签
x_ticks_label = ["11点{}分".format(i) for i in x]
y_ticks = range(40)

# 刻度显示
plt.xticks(x[::5], x_ticks_label[::5])
plt.yticks(y_ticks[::5])

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

# 2.3 添加描述信息
plt.xlabel("时间")
plt.ylabel("温度")
plt.title("中午11点--12点某城市温度变化图", fontsize=20)

# 2.4 图像保存
plt.savefig("./test.png")

# 3.图像显示
plt.show()

1.2.0一个图里面画多个图像

1.2.1多次plot(即画多个图像)

# 增加北京的温度数据
y_beijing = [random.uniform(1, 3) for i in x]

# 绘制折线图
plt.plot(x, y_shanghai)
# 使用多次plot可以画多个折线
plt.plot(x, y_beijing, color='r', linestyle='--')

1.2.2显示图例

注意:如果只在plt.plot()中设置label还不能最终显示出图例,还需要通过plt.legend()将图例显示出来。

# 绘制折线图
plt.plot(x, y_shanghai, label="上海")
# 使用多次plot可以画多个折线
plt.plot(x, y_beijing, color='r', linestyle='--', label="北京")

# 显示图例
plt.legend(loc="best")

1.2.3完整的示例

# 0.准备数据
x = range(60)
y_shanghai = [random.uniform(15, 18) for i in x]
y_beijing = [random.uniform(1,3) for i in x]

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

# 2.绘制图像
plt.plot(x, y_shanghai, label="上海")
plt.plot(x, y_beijing, color="r", linestyle="--", label="北京")

# 2.1 添加x,y轴刻度
# 构造x,y轴刻度标签
x_ticks_label = ["11点{}分".format(i) for i in x]
y_ticks = range(40)

# 刻度显示
plt.xticks(x[::5], x_ticks_label[::5])
plt.yticks(y_ticks[::5])

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

# 2.3 添加描述信息
plt.xlabel("时间")
plt.ylabel("温度")
plt.title("中午11点--12点某城市温度变化图", fontsize=20)

# 2.4 图像保存
plt.savefig("./test.png")

# 2.5 添加图例
plt.legend(loc=0)


# 3.图像显示
plt.show()

1.3.0多个坐标系显示— plt.subplots

  • matplotlib.pyplot.subplots(nrows=1, ncols=1, **fig_kw) 创建一个带有多个axes(坐标系/绘图区)的图

注意:plt.函数名()相当于面向过程的画图方法,axes.set_方法名()相当于面向对象的画图方法。

# 0.准备数据
x = range(60)
y_shanghai = [random.uniform(15, 18) for i in x]
y_beijing = [random.uniform(1, 5) for i in x]

# 1.创建画布
# plt.figure(figsize=(20, 8), dpi=100)
fig, axes = plt.subplots(nrows=1, ncols=2, figsize=(20, 8), dpi=100)


# 2.绘制图像
# plt.plot(x, y_shanghai, label="上海")
# plt.plot(x, y_beijing, color="r", linestyle="--", label="北京")
axes[0].plot(x, y_shanghai, label="上海")
axes[1].plot(x, y_beijing, color="r", linestyle="--", label="北京")

# 2.1 添加x,y轴刻度
# 构造x,y轴刻度标签
x_ticks_label = ["11点{}分".format(i) for i in x]
y_ticks = range(40)

# 刻度显示
# plt.xticks(x[::5], x_ticks_label[::5])
# plt.yticks(y_ticks[::5])
axes[0].set_xticks(x[::5])
axes[0].set_yticks(y_ticks[::5])
axes[0].set_xticklabels(x_ticks_label[::5])
axes[1].set_xticks(x[::5])
axes[1].set_yticks(y_ticks[::5])
axes[1].set_xticklabels(x_ticks_label[::5])

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

# 2.3 添加描述信息
# plt.xlabel("时间")
# plt.ylabel("温度")
# plt.title("中午11点--12点某城市温度变化图", fontsize=20)
axes[0].set_xlabel("时间")
axes[0].set_ylabel("温度")
axes[0].set_title("中午11点--12点某城市温度变化图", fontsize=20)
axes[1].set_xlabel("时间")
axes[1].set_ylabel("温度")
axes[1].set_title("中午11点--12点某城市温度变化图", fontsize=20)

# # 2.4 图像保存
plt.savefig("./test.png")

# # 2.5 添加图例
# plt.legend(loc=0)
axes[0].legend(loc=0)
axes[1].legend(loc=0)


# 3.图像显示
plt.show()

1.3.1画数学函数图像

import numpy as np
# 0.准备数据
# linspace生成均匀的从-10到10之间的1000个数
x = np.linspace(-10, 10, 1000)
y = np.sin(x)

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

# 2.绘制函数图像
plt.plot(x, y)
# 2.1 添加网格显示
plt.grid()

# 3.显示图像
plt.show()

1.3.2常见图形绘制

1.3.2.1折线图

折线图:以折线的上升或下降来表示统计数量的增减变化的统计图

特点:能够显示数据的变化趋势,反映事物的变化情况。(变化)

api:plt.plot(x, y)

1.3.2.2散点图

散点图:用两组数据构成多个坐标点,考察坐标点的分布,判断两变量之间是否存在某种关联或总结坐标点的分布模式。

特点:判断变量之间是否存在数量关联趋势,展示离群点(分布规律)

api:plt.scatter(x, y)

1.3.2.3柱状图

柱状图:排列在工作表的列或行中的数据可以绘制到柱状图中。

特点:绘制连离散的数据,能够一眼看出各个数据的大小,比较数据之间的差别。(统计/对比)

api:plt.bar(x, width, align=‘center’, **kwargs)

Parameters:    
x : 需要传递的数据

width : 柱状图的宽度

align : 每个柱状图的位置对齐方式
    {‘center’, ‘edge’}, optional, default: ‘center’

**kwargs :
color:选择柱状图的颜色

1.3.2.4直方图

直方图:由一系列高度不等的纵向条纹或线段表示数据分布的情况。 一般用横轴表示数据范围,纵轴表示分布情况。

特点:绘制连续性的数据展示一组或者多组数据的分布状况(统计)

api:matplotlib.pyplot.hist(x, bins=None) bins表示的数组距

Parameters:    
x : 需要传递的数据
bins : 组距

1.3.2.5饼图

饼图:用于表示不同分类的占比情况,通过弧度大小来对比各种分类。

特点:分类数据的占比情况(占比)

api:plt.pie(x, labels=,autopct=,colors)

Parameters:  
x:数量,自动算百分比
labels:每部分名称
autopct:占比显示指定%1.2f%%
colors:每部分颜色

1.3.2.6示例

# 0.准备数据
# 电影名字
movie_name = ['雷神3:诸神黄昏','正义联盟','东方快车谋杀案','寻梦环游记','全球风暴','降魔传','追捕','七十七天','密战','狂兽','其它']
# 横坐标
x = range(len(movie_name))
# 票房数据
y = [73853,57767,22354,15969,14839,8725,8716,8318,7916,6764,52222]

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

# 2.绘制柱状图
plt.bar(x, y, width=0.5, color=['b','r','g','y','c','m','y','k','c','g','b'])

# 2.1b修改x轴的刻度显示
plt.xticks(x, movie_name)

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

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

# 3.显示图像
plt.show()

2.Numpy的使用

Numpy支持常见的数组和矩阵操作。对于同样的数值计算任务,使用Numpy比直接使用Python要简洁的多。

Numpy使用ndarray对象来处理多维数组,该对象是一个快速而灵活的大数据容器。

2.1numpy使用的示例

import numpy as np

# 创建ndarray
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]])

2.2 N维数组-ndarray

2.2.1ndarray的属性

ndarray.shape 数组维度的元组
ndarray.size 数组中的元素数量
ndarray.dtype 数组元素的类型

import numpy as np

my_array = np.array([[1,2,3],
                    [4,5,6],
                    [7,8,9],
                    [10,11,12]])


my_array

print(my_array.shape)  # (4, 3)
print(my_array.shape[0])  # 4
print(my_array.shape[1])  # 3

print(my_array.dtype)    # int32
print(my_array.size)     # 12

2.2.2创建数组时指定类型

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

my_array = np.array(["a","b","c"],dtype=np.string_)
my_array.dtype  # dtype('S1')  字符串类型,简写为 "S1"
my_array   # array([b'a', b'b', b'c'], dtype='|S1')

2.3基本操作

2.3.1生成01数组

np.ones(shape, dtype)
np.ones_like(a, dtype)
np.zeros(shape, dtype)
np.zeros_like(a, dtype)

my_array = np.ones([3,4],dtype=np.int32)   # 生成一个3行4列的数组,全部的
元素都是1
'''
[[1 1 1 1]
 [1 1 1 1]
 [1 1 1 1]]
'''
my_array2 = np.zeros_like(my_array)   # 生成一个大小和my_array一样都是3行4列的数组,但是数组中的所有的元素的值都是0
'''
array([[0, 0, 0, 0],
       [0, 0, 0, 0],
       [0, 0, 0, 0]])
'''

2.3.2从现有的数组中生成

np.array(object, dtype)
np.asarray(a, dtype)

a = np.array([[1,2,3],[4,5,6]])
a
'''
array([[1, 2, 3],
       [4, 5, 6]])
'''
a1 = np.array(a)
a1
'''
array([[1, 2, 3],
       [4, 5, 6]])
'''


a1[0,0] = 3   # 修改数组中的元素 第0行第0列的元素修改为3
a1
'''
array([[3, 2, 3],
       [4, 5, 6]])
'''

a2 = np.asarray(a)
a2
'''
array([[1, 2, 3],
       [4, 5, 6]])
'''

a[0,1] = 10

a
'''
array([[ 1, 10,  3],
       [ 4,  5,  6]])
'''


a2
'''
array([[ 1, 10,  3],
       [ 4,  5,  6]])
'''


#即a的改变会影响a2的改变,a2相当于是a的一个引用,公用同一块内存的地址,
# a2是a的浅拷贝,与a公用的是同一块的内存地址,而a1是a1的深拷贝,是新开辟了一块内存地址


2.3.3.生成固定范围的数组

np.linspace (start, stop, num, endpoint)

创建等差数组 — 指定数量
参数:
start:序列的起始值
stop:序列的终止值
num:要生成的等间隔样例数量,默认为50
endpoint:序列中是否包含stop值,默认为ture

np.arange(start,stop, step, dtype)

创建等差数组 — 指定步长
参数
step:步长,默认值为1

# 生成等间隔的数组
my_array = np.linspace(0,10,6)  # 表示从0到10之间生成6个数,且6个数的间隔之间是相等的

my_array
'''
array([ 0.,  2.,  4.,  6.,  8., 10.])
'''

my_array = np.arange(0,10,2)  # 表示从0到12左闭右开 [0,12) 步长为2生成数,直到生成的数>10为止
my_array
'''
array([0, 2, 4, 6, 8])
'''
# 注意:np.arange(10) 如果只传入一个参数,则默认表示的是生成从[0,10),且步长默认为1
my_array = np.arange(0,11,2)
my_array
'''
array([ 0,  2,  4,  6,  8, 10])
'''

np.logspace(start,stop, num) 创建等比数列

参数:
num:要生成的等比数列数量,默认为50
my_array = np.logspace(0,2,3)   # 表示从10的0次方到 10的平方 [1,100]生成3个数,且3个数之间成等比数列的关系
my_array
'''
array([  1.,  10., 100.])
'''

2.4生成随机数组

np.random模块

np.random.rand() 函数: 通过本函数可以返回一个或一组服从“0~1”均匀分布的随机样本值。随机样本取值范围是[0,1),不包括1。

np.random.randn()函数: 通过本函数可以返回一个或一组服从标准正态分布的随机样本值。

2.4.1生成正太分布

np.random.normal(loc=0.0, scale=1.0, size=None)
loc:float
​此概率分布的均值(对应着整个分布的中心centre)
scale:float
此概率分布的标准差(对应于分布的宽度,scale越大越矮胖,scale越小,越瘦高)
size:int or tuple of ints
​输出的shape,默认为None,只输出一个值
np.random.standard_normal(size=None)
返回指定形状的标准正态分布的数组。
import matplotlib.pyplot as plt

my_array = np.random.normal(0,1,100000000)
my_array
'''
array([-0.53982921, -0.95975948, -0.33872566,  0.9559123 ,  1.30392173,
       -0.31023154,  1.35798755, -1.31230511, -1.07605753,  0.29419888....])
'''

plt.figure(figsize=(20,8),dpi=100)


plt.hist(my_array,1000)


plt.show()
# 创建符合正态分布的4只股票5天的涨跌幅数据
stock_change = np.random.normal(0, 1, (4, 5))
stock_change
'''
array([[ 1.22570421,  2.12485099,  0.6377609 ,  0.68485005, -0.04554383],
       [ 0.36445443,  0.21366998,  0.84673475,  2.26352745, -0.52602617],
       [ 2.98568559,  1.46727798, -1.40948731,  0.40721154,  0.96401699],
       [-0.40825055, -0.34283306, -0.97828756,  0.56453851,  0.35391846]])
'''

2.4.2生成均匀分布

np.random.uniform(low=0.0, high=1.0, size=None)

功能:从一个均匀分布[low,high)中随机采样,注意定义域是左闭右开,即包含low,不包含high.
参数介绍:
low: 采样下界,float类型,默认值为0;
high: 采样上界,float类型,默认值为1;
size: 输出样本数目,为int或元组(tuple)类型,例如,size=(m,n,k), 则输出mnk个样本,缺省时输出1个值。
返回值:ndarray类型,其形状和参数size中描述一致。

np.random.randint(low, high=None, size=None, dtype=‘l’)

从一个均匀分布中随机采样,生成一个整数或N维整数数组,
取数范围:若high不为None时,取[low,high)之间随机整数,否则取值[0,low)之间随机整数。
# 生成均匀分布的随机数
my_array = np.random.uniform(0,10,10)   # 从[0,10) 之间生成10个数,注意:因为是均匀分布,所以说每一个数出现的概率是等可能的!
my_array
'''
array([4.09707856, 9.27088647, 1.11083578, 6.56258234, 4.94165939,
       9.61762128, 0.07242636, 3.40775232, 5.75671768, 0.98428204])
'''
# 生成随机的整数!
my_array = np.random.randint(0,10,5)
my_array
'''
array([5, 6, 7, 7, 8])
'''

绘制均匀分布的直方图

import matplotlib.pyplot as plt

# 生成均匀分布的随机数
x2 = np.random.uniform(-1, 1, 100000000)

# 画图看分布状况
# 1)创建画布
plt.figure(figsize=(10, 10), dpi=100)

# 2)绘制直方图
plt.hist(x=x2, bins=1000)  # x代表要使用的数据,bins表示要划分区间数

# 3)显示图像
plt.show()

2.4.3数组的索引、切片

直接进行索引,切片
对象[:, :] – 先行后列

my_array = np.array([[1,2,3],[4,5,6]])
my_array[0,1]  # 输出2
my_array[0:1,0:2]   # 行方向只取第一行,列方向只取第一列和第二列
'''
array([[1, 2]])
'''


2.4.4形状修改

ndarray.reshape(shape, order)

返回一个具有相同数据域,但shape不一样的视图
行、列不进行互换

ndarray.resize(new_shape)

修改数组本身的形状(需要保持元素个数前后相同)
行、列不进行互换

ndarray.T

数组的转置
将数组的行、列进行互换


my_array = np.array([[1,2,3],[4,5,6]])  # 一个两行三列的数组
my_array.reshape([3,2])   # 将一个两行三列的数组转换为一个三行两列的数组
'''  注意:会按照行从左到右,从上到小从新排列
array([[1, 2],
       [3, 4],
       [5, 6]])
'''
my_array
'''
array([[1, 2, 3],
       [4, 5, 6]])
'''
my_array.resize([3,2])
my_array
'''
array([[1, 2],
       [3, 4],
       [5, 6]])
'''
# resize会对原来的数组进行改变,而reshape不会改变原数组!

# 对数组进行转置!
my_array.T
'''
array([[1, 3, 5],
       [2, 4, 6]])
'''

2.4.5类型的修改

ndarray.astype(type)

返回修改了类型之后的数组

ndarray.tostring([order])或者ndarray.tobytes([order])

构造包含数组中原始数据字节的Python字节
my_array = np.array([1,2,3,4])
my_array.dtype  # dtype('int32')

my_array.astype(np.float32)   # array([1., 2., 3., 4.], dtype=float32)

my_array.tobytes()  # b'\x01\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x04\x00\x00\x00'


2.4.6数组的去重

np.unique()

my_array = np.array([1,2,3,5,6,7,9,10,10])
my_array  # array([ 1,  2,  3,  5,  6,  7,  9, 10, 10])
np.unique(my_array)  # array([ 1,  2,  3,  5,  6,  7,  9, 10])

2.5ndarray运算

2.5.1逻辑运算



my_array = np.random.randint(40,100,(3,5))
my_array
'''
array([[58, 52, 87, 74, 86],
       [76, 74, 58, 55, 84],
       [92, 40, 44, 70, 79]])
'''
my_array > 60
'''
array([[ True,  True, False, False, False],
       [False,  True,  True,  True,  True],
       [ True,  True, False,  True,  True]])
'''
my_array[my_array > 60] = 1  # 数组中所有大于60的数全部变成1
my_array
'''
array([[ 1,  1,  1,  1,  1],
       [55,  1,  1,  1, 55],
       [45,  1, 54, 42,  1]])
'''


2.5.2通用判断函数

np.all()

np.any()

my_array = np.random.randint(50,100,(3,3))
my_array
'''
array([[74, 54, 58],
       [93, 81, 74],
       [62, 84, 85]])
'''

print(np.all(my_array > 60)) # 判断是否全部的数都是大于60
np.any((my_array <= 60))    # 判断是否存在一个数<=60

2.5.3 np.where(三元运算符)

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

np.where(my_array > 3,0,1)
'''
array([[1, 1, 1],
       [0, 0, 0]])
'''
my_array
'''
array([[1, 2, 3],
       [4, 5, 6]])
'''

np.where(np.logical_and(my_array > 1,my_array < 6),100,0)
'''
array([[  0, 100, 100],
       [100, 100,   0]])
'''
# 将数组中小于3或者大于5的数改成100,其他不满足条件的数改成0
np.where(np.logical_or(my_array < 3,my_array > 5),100,0)
'''
array([[100, 100,   0],
       [  0,   0, 100]])
'''

2.5.4统计运算

进行统计的时候,axis 轴的取值并不一定,Numpy中不同的API轴的值都不一样,在这里,axis 0代表列, axis 1代表行去进行统计

min(a, axis)   axis为0表示按照行进行统计,为1表示按照列进行统计   min返回最小值
	Return the minimum of an array or minimum along an axis.
max(a, axis)  返回最大值
	Return the maximum of an array or maximum along an axis.
median(a, axis)   返回中位数
	Compute the median along the specified axis.
mean(a, axis, dtype)   返回平均值
	Compute the arithmetic mean along the specified axis.
std(a, axis, dtype)   返回标准差
	Compute the standard deviation along the specified axis.
var(a, axis, dtype)  返回方差
	Compute the variance along the specified axis.

my_array = np.array([[1,2,3],[4,5,6],[7,8,9]])
my_array
'''
array([[1, 2, 3],
       [4, 5, 6],
       [7, 8, 9]])
'''

np.max(my_array,axis=0)  # 按照列来找到最大值,每一列找到一个最大值
'''
array([7, 8, 9])
'''
np.min(my_array,axis=0)   # 按照列来找到每一列的最小值
'''
array([1, 2, 3])
'''
np.median(my_array,axis=0)  # 按照列来找到每一列的中位数
'''
array([1, 2, 3])
'''
np.mean(my_array,axis=0)   # 找到列来找到每一列的平均值
'''
array([4., 5., 6.])
'''

np.argmax(my_array,axis=0)   # 按照列来找到每一列的最大值,返回其下标
'''
array([2, 2, 2], dtype=int64)
'''

np.argmin(my_array,axis=0)   # 按照列来找每一列的最小值,返回其下标
'''
array([0, 0, 0], dtype=int64)
'''

2.6数组间的运算

2.6.1数组和数进行运算

array([[0.5, 1. , 1.5],
       [2. , 2.5, 3. ]])

2.6.2 数组和数组进行运算

数组在进行矢量化运算时,要求数组的形状是相等的。当形状不相等的数组执行算术运算的时候,就会出现广播机制,该机制会对数组进行扩展,使数组的shape属性值一样,这样,就可以进行矢量化运算了。

arr1 = np.array([[0],[1],[2],[3]])
arr1.shape  
# (4, 1)  四行一列

arr2 = np.array([1,2,3])
arr2.shape
# (3,)   一行三列
  
# arr1+arr2
'''
array([[1, 2, 3],
       [2, 3, 4],
       [3, 4, 5],
       [4, 5, 6]])
'''

上述代码中,数组arr1是4行1列,arr2是1行3列。这两个数组要进行相加,按照广播机制会对数组arr1和arr2都进行扩展,使得数组arr1和arr2都变成4行3列。

广播机制实现了时两个或两个以上数组的运算,即使这些数组的shape不是完全相同的,只需要满足如下任意一个条件即可。

1.数组的某一维度等长。
2.其中一个数组的某一维度为1 。

如果是下面这样,则不匹配:

A  (1d array): 10
B  (1d array): 12
A  (2d array):      2 x 1
B  (3d array):  8 x 4 x 3

2.7矩阵

矩阵乘法遵循准则:

(M行, N列)*(N行, L列) = (M行, L列)

2.7.1矩阵乘法api:

my_array = np.array([[1,2,3],[4,5,6]])
my_array
'''
array([[1, 2, 3],
       [4, 5, 6]])
'''
my_array2 = np.array([[1,2],[3,4],[5,6]])
my_array2
'''
array([[1, 2],
       [3, 4],
       [5, 6]])
'''
np.matmul(my_array,my_array2)
'''
array([[22, 28],
       [49, 64]])
'''

np.dot(my_array,my_array2)
'''
array([[22, 28],
       [49, 64]])
'''

np.matmul和np.dot的区别:

二者都是矩阵乘法。 np.matmul中禁止矩阵与标量的乘法。 在矢量乘矢量的內积运算中,np.matmul与np.dot没有区别。

3.Pandas

3.1为什么使用Pandas

  • 增强图表可读性
  • 便捷的数据处理能力
  • 读取文件方便
  • 封装了Matplotlib、Numpy的画图和计算

3.2Pandas数据类型

Pandas中一共有三种数据结构,分别为:Series、DataFrame和MultiIndex(老版本中叫Panel )。

其中Series是一维数据结构,DataFrame是二维的表格型数据结构,MultiIndex是三维的数据结构。

3.2.1 Series

Series是一个类似于一维数组的数据结构,它能够保存任何类型的数据,比如整数、字符串、浮点数等,主要由一组数据和与之相关的索引两部分构成。

3.2.1.1 Series的创建
import pandas as pd
pd.Series(data=None,index=None,dtype=np.float32)
'''
Series([], dtype: float32)
'''

参数:

data:传入的数据,可以是ndarray、list等
index:索引,必须是唯一的,且与数据的长度相等。如果没有传入索引参数,则默认会			自动创建一个从0-N的整数索引。
dtype:数据的类型
pd.Series(np.arange(10))
'''
0    0
1    1
2    2
3    3
4    4
5    5
6    6
7    7
8    8
9    9
dtype: int32
'''
# 自定义索引
import random
pd.Series(np.arange(10),index=[random.randint(0,1) for i in range(10)])
'''
0    0
0    1
0    2
0    3
0    4
0    5
1    6
1    7
0    8
1    9
dtype: int32
'''


# 通过键值对来创建索引

pd.Series({"red":32,"blue":15,"black":33})
'''
red      32
blue     15
black    33
dtype: int64
'''
3.2.1.2 Series的属性

为了更方便地操作Series对象中的索引和数据,Series中提供了两个属性index和values

my_series = pd.Series({"red":32,"blue":15,"black":33})
my_series
'''
red      32
blue     15
black    33
dtype: int64
'''
my_series.index
'''
Index(['red', 'blue', 'black'], dtype='object')
'''
my_series.values
'''
array([32, 15, 33], dtype=int64)
'''

3.2.2DataFrame

DataFrame是一个类似于二维数组或表格(如excel)的对象,既有行索引,又有列索引

行索引,表明不同行,横向索引,叫index,0轴,axis=0
列索引,表名不同列,纵向索引,叫columns,1轴,axis=1
import pandas as pd
pd.DataFrame(data=None,index=None,columns=None)

参数:

index:行标签。如果没有传入索引参数,则默认会自动创建一个从0-N的整数索引。
columns:列标签。如果没有传入索引参数,则默认会自动创建一个从0-N的整数索引。
# 生成3行2列的正太分布的样本值
np.random.randn(3,2) 
'''
array([[ 0.32335499,  0.48748889],
       [-0.01632227,  0.69119366],
       [-0.99024604, -0.29383495]])
'''


score = np.random.randint(40,100,(2,3))  # 生成一个三行五列的数组
print(score)
'''
[[71 83 45]
 [52 91 87]]
'''
data =  pd.DataFrame(score)
data
'''
data显示成了一个表格的形式,更加好看了
'''
  • 增加行、列索引

score = np.random.randint(40,100,(2,3))
score
row_index = ["学生"+str(i) for i in range(score.shape[0])]
col_index = ["语文","数学","英语"]
data = pd.DataFrame(score,index=row_index,columns=col_index)
data
3.2.2.1 DataFrame的属性
  • shape 和 ndarray的一样 返回一个元组
  • index 返回行的索引
  • columns 返回列的索引
  • values 获取其中的array 相当于是说 从一个DataFrame对象转换为一个 ndarray的对象
  • T 进行转置
  • .head(行数) 显示前面的几行
  • .tail(行数) 显示后面的几行
3.2.2.2 DatatFrame索引的设置
score = np.random.randint(40,100,(2,3))
data = pd.DataFrame(score)
# 必须整体全部修改
row_index = ["学生" + str(i) for i in range(data.shape[0])]
data.index = row_index

注意:索引必须全部修改,不能只单单修改某一个或者某几个的索引

3.2.2.3 重设索引

reset_index(drop=False)

设置新的下标索引
drop:默认为False,不删除原来索引,如果为True,删除原来的索引值
data.reset_index(drop=False)
# 会将原来的索引进行保存,且重新添加一个索引
3.2.2.4 以某列值设置为新的索引

set_index(keys, drop=True)

keys : 列索引名成或者列索引名称的列表
drop : boolean, default True.当做新的索引,删除原来的列
data = pd.DataFrame({"month":[1,2,3],
                     "year":[2020,2021,2022],
                     "sales":[1000,10001,10002]})
data
'''
month	year	sales
0	1	2020	1000
1	2	2021	10001
2	3	2022	10002
'''
# 将月份设置为新的索引
data.set_index(["month"])

# 设置多个索引,以年和月份
data.set_index(["month","year"])

通过刚才的设置,这样DataFrame就变成了一个具有MultiIndex的DataFrame。

3.2.3 MultiIndex与Panel

3.2.3.1 MultiIndex

MultiIndex是三维的数据结构;

多级索引(也称层次化索引)是pandas的重要功能,可以在Series、DataFrame对象上拥有2个以及2个以上的索引。

score = np.random.randint(60,100,(6,2))
name = ["张三","李四","王五"]
times = ["期末","期中"]
col_index = ["语文","数学"]
row_index = pd.MultiIndex.from_product([name,times])
row_index
'''
MultiIndex([('张三', '期末'),
            ('张三', '期中'),
            ('李四', '期末'),
            ('李四', '期中'),
            ('王五', '期末'),
            ('王五', '期中')],
           )
'''
pd.DataFrame(score,index=row_index,columns=col_index)
'''
               语文	数学
张三	期末	89	62
        期中	81	78
李四	期末	90	62
        期中	67	95
王五	期末	77	67
        期中	78	68
'''
3.2.3.2 Panel

作用:存储3维数组的Panel结构
不常用!

3.3基本数据操作

3.3.1 索引操作

# 读取文件
data = pd.read_csv("./data/stock_day.csv")

# 删除一些列,让数据更简单些,再去做后面的操作
data = data.drop(["ma5","ma10","ma20","v_ma5","v_ma10","v_ma20"], axis=1)
3.3.1.1直接使用行列索引(先列后行)

获取’2018-02-27’这天的’close’的结果

# 直接使用行列索引名字的方式(先列后行)
data['open']['2018-02-27']
23.53

# 不支持的操作
# 错误
data['2018-02-27']['open']
# 错误
data[:1, :2]
3.3.1.2 结合loc或者iloc使用索引

获取从’2018-02-27’:‘2018-02-22’,'open’的结果

# 使用loc:只能指定行列索引的名字
# 从行索引 2018-02-27 一直查询到行索引为2018-02-22的所有的列为open的数据
data.loc['2018-02-27':'2018-02-22', 'open']

2018-02-27    23.53
2018-02-26    22.80
2018-02-23    22.88
Name: open, dtype: float64

# 使用iloc可以通过索引的下标去获取
# 获取前3天数据,前5列的结果
data.iloc[:3, :5]

               open    high    close    low
2018-02-27    23.53    25.88    24.16    23.53
2018-02-26    22.80    23.78    23.53    22.80
2018-02-23    22.88    23.37    22.82    22.71
3.3.1.3 使用ix组合索引

获取行第1天到第4天,[‘open’, ‘close’, ‘high’, ‘low’]这个四个指标的结果

# 使用ix进行下表和名称组合做引
data.ix[0:4, ['open', 'close', 'high', 'low']]

# 推荐使用loc和iloc来获取的方式
data.loc[data.index[0:4], ['open', 'close', 'high', 'low']]
data.iloc[0:4, data.columns.get_indexer(['open', 'close', 'high', 'low'])]

               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

3.3.2 赋值操作

对DataFrame当中的close列进行重新赋值为1

# 直接修改原来的值
data['close'] = 1
# 或者
data.close = 1

3.3.3 排序

3.3.3.1 DataFrame排序

使用DataFrame对象.sort_values(by=, ascending=)
单个键或者多个键进行排序,
参数:

by:指定排序参考的键
ascending:默认升序
ascending=False:降序
ascending=True:升序
# 按照开盘价大小进行排序 , 使用ascending指定按照大小排序
data.sort_values(by="open", ascending=True).head()
# 按照多个键进行排序
data.sort_values(by=['open', 'high'])

这个股票的日期索引原来是从大到小,现在重新排序,从小到大

# 对索引进行排序
data.sort_index()
3.3.3.2 Series排序

使用series.sort_values(ascending=True)进行排序

series排序时,只有一列,不需要参数
# data是一个DataFrame对象,取出了它其中的列,然后将那一列的数据按照升序进行排序
data['p_change'].sort_values(ascending=True).head()

2015-09-01   -10.03
2015-09-14   -10.02
2016-01-11   -10.02
2015-07-15   -10.02
2015-08-26   -10.01
Name: p_change, dtype: float64
  • 使用series.sort_index()进行排序
# 对索引进行排序
data['p_change'].sort_index().head()

2015-03-02    2.62
2015-03-03    1.44
2015-03-04    1.57
2015-03-05    2.02
2015-03-06    8.51
Name: p_change, dtype: float64

3.4 DataFrame运算

3.4.1 算术运算

  • add(other)
    比如进行数学运算加上具体的一个数字
data['open'].add(1)

2018-02-27    24.53
2018-02-26    23.80
2018-02-23    23.88
2018-02-22    23.25
2018-02-14    22.49
  • sub(other)

3.4.2 逻辑运算

3.4.2.1 逻辑运算符号

例如筛选data[“open”] > 23的日期数据
data[“open”] > 23返回逻辑结果

data["open"] > 23

2018-02-27     True
2018-02-26    False
2018-02-23    False
2018-02-22    False
2018-02-14    False
# 逻辑判断的结果可以作为筛选的依据
data[data["open"] > 23].head()
  • 完成多个逻辑判断
data[(data["open"] > 23) & (data["open"] < 24)].head()
3.4.2.2 逻辑运算函数
  • query(expr)
    expr:查询字符串
    通过query使得刚才的过程更加方便简单
data.query("open<24 & open>23").head()
  • isin(values)
    例如判断’open’是否为23.53和23.85
# 可以指定值进行一个判断,从而进行筛选操作
data[data["open"].isin([23.53, 23.85])]

3.4.3 统计运算

3.4.3.1 describe

综合分析: 能够直接得出很多统计结果,count, mean, std, min, max 等

# 计算平均值、标准差、最大值、最小值
data.describe()
3.4.3.2 统计函数

对于单个函数去进行统计的时候,坐标轴还是按照默认列“columns” (axis=0, default),如果要对行“index” 需要指定(axis=1)

  • max()、min()
# 使用统计函数:0 代表列求结果, 1 代表行求统计结果
data.max(0)

open                   34.99
high                   36.35
close                  35.21
low                    34.01
volume             501915.41
price_change            3.03
p_change               10.03
turnover               12.56
my_price_change         3.41
dtype: float64
  • std()、var()
# 方差
data.var(0)

open               1.545255e+01
high               1.662665e+01
close              1.554572e+01
low                1.437902e+01
volume             5.458124e+09
price_change       8.072595e-01
p_change           1.664394e+01
turnover           4.323800e+00
my_price_change    6.409037e-01
dtype: float64

# 标准差
data.std(0)

open                   3.930973
high                   4.077578
close                  3.942806
low                    3.791968
volume             73879.119354
price_change           0.898476
p_change               4.079698
turnover               2.079375
my_price_change        0.800565
dtype: float64
  • median():中位数
    中位数为将数据从小到大排列,在最中间的那个数为中位数。如果没有中间数,取中间两个数的平均值。
df = pd.DataFrame({'COL1' : [2,3,4,5,4,2],
                   'COL2' : [0,1,2,3,4,2]})

df.median()

COL1    3.5
COL2    2.0
dtype: float64
  • idxmax()、idxmin()
# 求出最大值的位置
# 对于每一列来说,找到最大的那个数随对应的行的横坐标索引。
data.idxmax(axis=0)

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
turnover           2017-10-26
my_price_change    2015-07-10
dtype: object


# 求出最小值的位置
data.idxmin(axis=0)

open               2015-03-02
high               2015-03-02
close              2015-09-02
low                2015-03-02
volume             2016-07-06
price_change       2015-06-15
p_change           2015-09-01
turnover           2016-07-06
my_price_change    2015-06-15
dtype: object
3.4.3.3 累计统计函数
cumsum    	计算前1/2/3/…/n个数的和
cummax    	计算前1/2/3/…/n个数的最大值
cummin    	计算前1/2/3/…/n个数的最小值
cumprod	    计算前1/2/3/…/n个数的积

以上这些函数可以对series和dataframe操作

这里我们按照时间的从前往后来进行累计

  • 排序
# 排序之后,进行累计求和
data = data.sort_index()
  • 对p_change进行求和
stock_rise = data['p_change']
# plot方法集成了前面直方图、条形图、饼图、折线图
stock_rise.cumsum()

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
2015-03-09     16.37
2015-03-10     18.75
2015-03-11     16.36
2015-03-12     15.03
2015-03-13     17.58
2015-03-16     20.34
2015-03-17     22.42
2015-03-18     23.28
2015-03-19     23.74
2015-03-20     23.48
2015-03-23     23.74

那么如何让这个连续求和的结果更好的显示呢?

如果要使用plot函数,需要导入matplotlib.

import matplotlib.pyplot as plt
# plot显示图形
stock_rise.cumsum().plot()
# 需要调用show,才能显示出结果
plt.show()
3.4.3.4 自定义运算

apply(func, axis=0)

func:自定义函数
axis=0:默认是列,axis=1为对行进行运算
定义一个对列,最大值-最小值的函数
# 找到 "open"和"close"那两列,然后运用自定义的函数,求出最大值减去最小值
data[['open', 'close']].apply(lambda x: x.max() - x.min(), axis=0)

open     22.74
close    22.85
dtype: float64

3.5 Pandas画图

3.5.1 pandas.DataFrame.plot

DataFrame.plot(kind=‘line’)

kind : str,需要绘制图形的种类
‘line’ : line plot (default)
‘bar’ : vertical bar plot
‘barh’ : horizontal bar plot
‘hist’ : histogram
‘pie’ : pie plot
‘scatter’ : scatter plot

3.5.2 pandas.Series.plot

3.6 文件读取与存储

3.6.1 read_csv

pandas.read_csv(filepath_or_buffer, sep =‘,’, usecols )

filepath_or_buffer:文件路径
sep :分隔符,默认用","隔开
usecols:指定读取的列名,列表形式
names:表示在读取的时候给数据添加列的属性,names传入列表

举例:读取之前的股票的数据

# 读取文件,并且指定只获取'open', 'close'指标
data = pd.read_csv("./data/stock_day.csv", usecols=['open', 'close'])

            open    close
2018-02-27    23.53    24.16
2018-02-26    22.80    23.53
2018-02-23    22.88    22.82
2018-02-22    22.25    22.28
2018-02-14    21.49    21.92

3.6.2 to_csv

DataFrame.to_csv(path_or_buf=None, sep=', ’, columns=None, header=True, index=True, mode=‘w’, encoding=None)

path_or_buf :文件路径
sep :分隔符,默认用","隔开
columns :选择需要的列索引
header :boolean or list of string, default True,是否写进列索引值
index:是否写进行索引
mode:'w':重写, 'a' 追加

举例:保存读取出来的股票数据
保存’open’列的数据,然后读取查看结果

# 选取10行数据保存,便于观察数据
data[:10].to_csv("./data/test.csv", columns=['open'])
# 读取,查看结果
pd.read_csv("./data/test.csv")

     Unnamed: 0    open
0    2018-02-27    23.53
1    2018-02-26    22.80
2    2018-02-23    22.88
3    2018-02-22    22.25
4    2018-02-14    21.49
5    2018-02-13    21.40
6    2018-02-12    20.70
7    2018-02-09    21.20
8    2018-02-08    21.79
9    2018-02-07    22.69

会发现将索引存入到文件当中,变成单独的一列数据。如果需要删除,可以指定index参数,删除原来的文件,重新保存一次。

# index:存储不会讲索引值变成一列数据
data[:10].to_csv("./data/test.csv", columns=['open'], index=False)

3.6.3 read_hdf与to_hdf

HDF5文件的读取和存储需要指定一个键,值为要存储的DataFrame

pandas.read_hdf(path_or_buf,key =None,** kwargs)

从h5文件当中读取数据

path_or_buffer:文件路径
key:读取的键
return:Theselected object
DataFrame.to_hdf(path_or_buf, key, *\kwargs*)
day_close = pd.read_hdf("./data/day_close.h5")
  • 存储文件
day_close.to_hdf("./data/test.h5", key="day_close")

再次读取的时候, 需要指定键的名字

new_close = pd.read_hdf("./data/test.h5", key="day_close")

注意:优先选择使用HDF5文件存储

HDF5在存储的时候支持压缩,使用的方式是blosc,这个是速度最快的也是pandas默认支持的
使用压缩可以提磁盘利用率,节省空间
HDF5还是跨平台的,可以轻松迁移到hadoop 上面

3.6.4 read_json

pandas.read_json(path_or_buf=None, orient=None, typ=‘frame’, lines=False)

这里使用一个新闻标题讽刺数据集,格式为json。is_sarcastic:1讽刺的,否则为0;headline:新闻报道的标题;article_link:链接到原始新闻文章。存储格式为:

{"article_link": "https://www.huffingtonpost.com/entry/versace-black-code_us_5861fbefe4b0de3a08f600d5", "headline": "former versace store clerk sues over secre 'xxx' for minority shoppers", "is_sarcastic": 0}
{"article_link": "https://www.huffingtonpost.com/entry/roseanne-revival-review_us_5ab3a497e4b054d118e04365", "headline": "the 'roseanne' revival catches up to our thorny political mood, for better and worse", "is_sarcastic": 0}
  • 读取
    orient指定存储的json格式,lines指定按照行去变成一个样本
json_read = pd.read_json("./data/Sarcasm_Headlines_Dataset.json", orient="records", lines=True)

3.6.5 to_json

DataFrame.to_json(path_or_buf=None, orient=None, lines=False)

将Pandas 对象存储为json格式
path_or_buf=None:文件地址
orient:存储的json形式,{‘split’,’records’,’index’,’columns’,’values’}
lines:一个对象存储为一行
  • 存储文件
json_read.to_json("./data/test.json", orient='records')

修改lines参数为True

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

3.7 高级处理-缺失值处理

3.7.1 处理NaN

3.7.1.1 判断缺失值是否存在
# 读取电影数据
movie = pd.read_csv("./data/IMDB-Movie-Data.csv")
pd.notnull(movie)
# 会将所有的非缺失值标记为True,将所有的缺失值标记为False

# 判断是否所有所有的数据都存在,即如果有缺失值的话,返回False,如果没有缺失值的话,返回Ture
np.all(pd.notnull(movie))
3.7.1.2 存在缺失值nan,并且是np.nan

1、删除
pandas删除缺失值,使用dropna的前提是,缺失值的类型必须是np.nan

# 不修改原数据
movie.dropna()

# 可以定义新的变量接受或者用原来的变量名
data = movie.dropna()

2、替换缺失值

# 替换存在缺失值的样本的两列
# 替换填充平均值
movie['Revenue (Millions)'].fillna(movie['Revenue (Millions)'].mean(), inplace=True)
# 拿到这一列的数据之后,将所有的na的地方替换成这一列的平均值。

替换所有缺失值:

for i in movie.columns:  # 枚举每一列
	# 如果说这一列所有的都非空为False,即存在空的值
    if np.all(pd.notnull(movie[i])) == False:
        print(i)
        # 将当前列的所有的空值都用这一列的平均值来替代
        movie[i].fillna(movie[i].mean(), inplace=True)
3.7.1.3 不是缺失值nan,有默认标记的

比如数据中是 ? 的情况

处理思路分析:

1、先替换‘?’为np.nan

df.replace(to_replace=, value=)
to_replace:替换前的值
value:替换后的值
wis = pd.read_csv("https://archive.ics.uci.edu/ml/machine-learning-databases/breast-cancer-wisconsin/breast-cancer-wisconsin.data")

# 把一些其它值标记的缺失值,替换成np.nan
wis = wis.replace(to_replace='?', value=np.nan)

2、在进行缺失值的处理

# 删除
wis = wis.dropna()

3.8 高级处理-数据离散化

3.8.1 为什么要离散化

连续属性离散化的目的是为了简化数据结构,数据离散化技术可以用来减少给定连续属性值的个数。离散化方法经常作为数据挖掘的工具。

3.8.2 什么是数据的离散化

连续属性的离散化就是在连续属性的值域上,将值域划分为若干个离散的区间,最后用不同的符号或整数 值代表落在每个子区间中的属性值。

离散化有很多种方法,这使用一种最简单的方式去操作

原始人的身高数据:165,174,160,180,159,163,192,184
假设按照身高分几个区间段:150~165, 165~180,180~195
这样我们将数据分到了三个区间段,我可以对应的标记为矮、中、高三个类别,最终要处理成一个"哑变量"矩阵

3.8.3股票的涨跌幅离散化

先读取股票的数据,筛选出p_change数据

data = pd.read_csv("./data/stock_day.csv")
p_change= data['p_change']

将股票涨跌幅数据进行分组

pd.qcut(data, q):

对数据进行分组将数据分组,一般会与value_counts搭配使用,统计每组的个数

series.value_counts():统计分组次数

# 自行分组  表示要将数据分成10个组,
qcut = pd.qcut(p_change, 10)
# 计算分到每个组数据个数
qcut.value_counts()

自定义区间分组:

pd.cut(data, bins)
# 自己指定分组区间
bins = [-100, -7, -5, -3, 0, 3, 5, 7, 100]
# 表示将数据按照 [-100,-7],[-7,-5]... 进行分组
p_counts = pd.cut(p_change, bins)

3.8.4 股票涨跌幅分组数据变成one-hot编码

什么是one-hot编码
把每个类别生成一个布尔列,这些列中只有一列可以为这个样本取值为1.其又被称为热编码。

pandas.get_dummies(data, prefix=None)

data:array-like, Series, or DataFrame
prefix:分组名字
# 得出one-hot编码矩阵
dummies = pd.get_dummies(p_counts, prefix="rise")

3.9 高级处理-合并

如果你的数据由多张表组成,那么有时候需要将不同的内容合并在一起分析

3.9.1 pd.concat实现数据合并

pd.concat([data1, data2], axis=1)

按照行或列进行合并,axis=0为列索引,axis=1为行索引

比如我们将刚才处理好的one-hot编码与原数据合并

# 按照行索引进行
pd.concat([data, dummies], axis=1)

3.9.2 pd.merge

pd.merge(left, right, how=‘inner’, on=None)

可以指定按照两组数据的共同键值对合并或者左右各自
left: DataFrame
right: 另一个DataFrame
on: 指定的共同键
how:按照什么方式连接
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']})
left
'''
	key1	key2	A	B
0	K0	    K0	  A0	B0
1	K0	    K1	  A1	B1
2	K1	    K0	  A2	B2
3	K2	    K1	  A3	B3
'''


right
'''
	key1	key2	C	D
0	K0	    K0	  C0	D0
1	K1	    K0	  C1	D1
2	K1	    K0	  C2	D2
3	K2	    K0	  C3	D3
'''

# 默认内连接,相当于是按照两个键key1和key2取交集来求解答案。
result = pd.merge(left, right, on=['key1', 'key2'])
result
'''
	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
'''
  • 左连接
# 保留左表的那些没有匹配到右边的那些行的数据
result = pd.merge(left, right, how='left', on=['key1', 'key2'])
  • 右连接
# 保留右表那些没有匹配到左边的那些行的数据
result = pd.merge(left, right, how='right', on=['key1', 'key2'])
  • 外链接
# 同时保留左表和右表那些没有匹配到的行的数据
result = pd.merge(left, right, how='outer', on=['key1', 'key2'])

3.10 高级处理-交叉表与透视表

应用crosstab和pivot_table实现交叉表与透视表

3.10.1 交叉表与透视表什么作用

探究股票的涨跌与星期几有关?

以下图当中表示,week代表星期几,1,0代表这一天股票的涨跌幅是好还是坏,里面的数据代表比例

可以理解为所有时间为星期一等等的数据当中涨跌幅好坏的比例

交叉表:交叉表用于计算一列数据对于另外一列数据的分组个数(用于统计分组频率的特殊透视表)

pd.crosstab(value1, value2)

透视表:透视表是将原有的DataFrame的列分别作为行索引和列索引,然后对指定的列应用聚集函数

data.pivot_table()
DataFrame.pivot_table([], index=[])

3.10.2 使用案例

  • 准备两列数据,星期数据以及涨跌幅是好是坏数据
  • 进行交叉表计算
# 寻找星期几跟股票的涨或者跌的关系
# 1、先把对应的日期找到星期几
date = pd.to_datetime(data.index).weekday  # date.index是数据的索引,已经提前保证了数据的索引就是日期
data['week'] = date  

# 2、假如把p_change按照大小去分个类0为界限
data['posi_neg'] = np.where(data['p_change'] > 0, 1, 0)

# 通过交叉表找寻两列数据的关系
count = pd.crosstab(data['week'], data['posi_neg'])

但是我们看到count只是每个星期日子的好坏天数,并没有得到比例,该怎么去做?

  • 对于每个星期一等的总天数求和,运用除法运算求出比例
# 算数运算,先求和
sum = count.sum(axis=1).astype(np.float32)

# 进行相除操作,得出比例
pro = count.div(sum, axis=0)
  • 画图来查看效果
    使用plot画出这个比例,使用stacked的柱状图(会将数据放到同一列上叠加起来)
pro.plot(kind='bar', stacked=True)
plt.show()

3.10.3 使用pivot_table(透视表)实现

使用透视表,刚才的过程更加简单

# 通过透视表,将整个过程变成更简单一些
data.pivot_table(['posi_neg'], index='week')

3.11 高级处理-分组与聚合

应用groupby和聚合函数实现数据的分组与聚合

分组与聚合通常是分析数据的一种方式,通常与一些统计函数一起使用,查看数据的分组情况

想一想其实刚才的交叉表与透视表也有分组的功能,所以算是分组的一种形式,只不过他们主要是计算次数或者计算比例!

3.11.1 分组API

DataFrame.groupby(key, as_index=False)
key:分组的列数据,可以多个
案例:不同颜色的不同笔的价格数据

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]})

     color    object    price1    price2
0    white    pen       5.56    4.75
1    red      pencil    4.20    4.12
2    green    pencil    1.30    1.60
3    red      ashtray   0.56    0.75
4    green    pen       2.75    3.15

进行分组,对颜色分组,price进行聚合

# 分组,求平均值
col.groupby(['color'])['price1'].mean()
col['price1'].groupby(col['color']).mean()
# 上面这两句话的效果一致!

color
green    2.025
red      2.380
white    5.560
Name: price1, dtype: float64

# 分组,数据的结构不变  as_index为False就不会帮我们将分类的那一列作为索引!
col.groupby(['color'], as_index=False)['price1'].mean()

     color    price1
0    green    2.025
1    red    2.380
2    white    5.560

3.11.2 星巴克案例

数据来源:星巴克数据

import pandas as pd
import matplotlib.pyplot as plt
# 导入星巴克店的数据
starbucks = pd.read_csv("./directory.csv")
starbucks.head()

'''
	Brand	Store Number	Store Name	Ownership Type	Street Address	City	State/Province	Country	Postcode	Phone Number	Timezone	Longitude	Latitude
0	Starbucks	47370-257954	Meritxell, 96	Licensed	Av. Meritxell, 96	Andorra la Vella	7	AD	AD500	376818720	GMT+1:00 Europe/Andorra	1.53	42.51
1	Starbucks	22331-212325	Ajman Drive Thru	Licensed	1 Street 69, Al Jarf	Ajman	AJ	AE	NaN	NaN	GMT+04:00 Asia/Dubai	55.47	25.42
2	Starbucks	47089-256771	Dana Mall	Licensed	Sheikh Khalifa Bin Zayed St.	Ajman	AJ	AE	NaN	NaN	GMT+04:00 Asia/Dubai	55.47	25.39
3	Starbucks	22126-218024	Twofour 54	Licensed	Al Salam Street	Abu Dhabi	AZ	AE	NaN	NaN	GMT+04:00 Asia/Dubai	54.38	24.48
4	Starbucks	17127-178586	Al Ain Tower	Licensed	Khaldiya Area, Abu Dhabi Island	Abu Dhabi	AZ	AE	NaN	NaN	GMT+04:00 Asia/Dubai	54.54	
'''

# 按照国家分组,求出每个国家的星巴克零售店数量,注意,会将所有国家相同的店的那些行进行合并,然后分组完了之后,原来的那些数据将会呈现数字的形式
count = starbucks.groupby(['Country']).count()
count.head()
'''
	Brand	Store Number	Store Name	Ownership Type	Street Address	City	State/Province	Postcode	Phone Number	Timezone	Longitude	Latitude
Country												
AD	1	1	1	1	1	1	1	1	1	1	1	1
AE	144	144	144	144	144	144	144	24	78	144	144	144
AR	108	108	108	108	108	108	108	100	29	108	108	108
AT	18	18	18	18	18	18	18	18	17	18	18	18
AU	22	22	22	22	22	22	22	22	0	22	22	22
'''

# 按照每一组中品牌的数量来画图,这样可以看出每一个国家星巴克店面的数量
count['Brand'].plot(kind='bar', figsize=(20, 8))
plt.show()



# # 假设我们加入省市一起进行分组

# # 设置多个索引,set_index()
starbucks.groupby(['Country', 'State/Province']).count()

3.12.3 电影案例

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

df = pd.read_csv("./IMDB-Movie-Data.csv")
df.head()
'''
	Rank	Title	Genre	Description	Director	Actors	Year	Runtime (Minutes)	Rating	Votes	Revenue (Millions)	Metascore
0	1	Guardians of the Galaxy	Action,Adventure,Sci-Fi	A group of intergalactic criminals are forced ...	James Gunn	Chris Pratt, Vin Diesel, Bradley Cooper, Zoe S...	2014	121	8.1	757074	333.13	76.0
1	2	Prometheus	Adventure,Mystery,Sci-Fi	Following clues to the origin of mankind, a te...	Ridley Scott	Noomi Rapace, Logan Marshall-Green, Michael Fa...	2012	124	7.0	485820	126.46	65.0
2	3	Split	Horror,Thriller	Three girls are kidnapped by a man with a diag...	M. Night Shyamalan	James McAvoy, Anya Taylor-Joy, Haley Lu Richar...	2016	117	7.3	157606	138.12	62.0
3	4	Sing	Animation,Comedy,Family	In a city of humanoid animals, a hustling thea...	Christophe Lourdelet	Matthew McConaughey,Reese Witherspoon, Seth Ma...	2016	108	7.2	60545	270.32	59.0
4	5	Suicide Squad	Action,Adventure,Fantasy	A secret government agency recruits some of th...	David Ayer	Will Smith, Jared Leto, Margot Robbie, Viola D...	2016	123	6.2	393727	325.02	40.0
'''

# 得出评分的平均分
df["Rating"].mean()
'''
6.723199999999999
'''

# 得出导演人数信息
df["Director"].unique().shape
'''
(644,)
'''
df["Director"].unique().shape[0]
'''
644
'''

# 对于这一组电影数据,如果我们想Rating,Runtime (Minutes)的分布情况,应该如何呈现数据?
# 直接呈现,以直方图的形式:选择分数列数据,进行plot
df["Rating"].plot(kind="hist",figsize=(20,8))  # 得到图像
# 为了让图像添加一些刻度等,使用plt进行绘图,功能更加全面一些

plt.figure(figsize=(20,8),dpi=100)
# bins=20表示分成20个条,即会有20个直的块
plt.hist(df["Rating"].values,bins=20)

# 接下来对刻度进行修改 
max_ = df["Rating"].max()
min_ = df["Rating"].min()

# 生成x轴的刻度表 , 因为要有20个条,因此需要有x轴的刻度要有21个
x_ticks = np.linspace(min_,max_,num=21)

# 添加x轴的刻度
plt.xticks(x_ticks)

# 添加网格
plt.grid()


# 对于这一组电影数据,如果我们希望统计电影分类(genre)的情况,应该如何处理数据?

# 进行字符串分割,因为对应每一步电影来说,有可能有多种类型,且类型之间使用逗号进行分割的
temp_list = [i.split(",") for i in df["Genre"]]  # 得到的temp_list列表是一个二维的列表,
'''
[['Action', 'Adventure', 'Sci-Fi'],
 ['Adventure', 'Mystery', 'Sci-Fi'],
 ['Horror', 'Thriller'],
 ['Animation', 'Comedy', 'Family'],
 ['Action', 'Adventure', 'Fantasy'],...]
'''
genre_list = np.unique([i for j in temp_list for i in j])
genre_list  # 得到所有电影的种类
'''
array(['Action', 'Adventure', 'Animation', 'Biography', 'Comedy', 'Crime',
       'Drama', 'Family', 'Fantasy', 'History', 'Horror', 'Music',
       'Musical', 'Mystery', 'Romance', 'Sci-Fi', 'Sport', 'Thriller',
       'War', 'Western'], dtype='<U9')
'''
 
# 增加新的列   将 genre_list电影的种类作为列,  np.zeros生成一个行数和列数确定的DataFrame,且元素的值全部为0
temp_df = pd.DataFrame(np.zeros([df.shape[0],genre_list.shape[0]]),columns=genre_list)
temp_df

# 遍历所有的电影,将类型出现的位置标记为1
for i in range(df.shape[0]):
    #  temp_list[i]['Action','Adventure','Animation']
    temp_df.iloc[i][temp_list[i]] = 1
# 对于每一列进行求和,就可以得到各种类型的电影的数量
temp_df.sum()
# 求和之后按照大小从小到大进行排序
temp_df.sum().sort_values()
'''
Musical        5.0
Western        7.0
War           13.0
Music         16.0
Sport         18.0
History       29.0
Animation     49.0
Family        51.0
Biography     81.0
Fantasy      101.0
Mystery      106.0
Horror       119.0
Sci-Fi       120.0
Romance      141.0
Crime        150.0
Thriller     195.0
Adventure    259.0
Comedy       279.0
Action       303.0
Drama        513.0
dtype: float64
'''

# 求和,绘图

# temp_df.sum().sort_values(ascending=False).plot(kind="bar",figsize=(20,8),fontsize=20,colormap="cool")

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值