我们在上一章了解了线性代数的发展历程,解析几何学中的“数形结合”,提供了一个很好的思维工具。本章我们将使用“数形结合”的思想,更加直观地认识二维向量。
我们生活中经常会使用到“维度”这个词,不同场景下所表达的具体含义有所不同:
1)“对这个问题从三个维度作出解释”,这里的“维度”侧重于描述思维角度;
2)“FC射击类游戏《魂斗罗》是2D游戏,射击类手游《和平精英》是3D游戏”,这里的“维度”侧重于描述物体所处空间位置;
3)“某气象台为了监测天气变化,需要记录温度、湿度等多维度的天气数据。”,这里的“维度”侧重于描述天气相关属性。
透过不同场景下“维度”的具体含义,其所表达的抽象含义为:事物“有联系”的抽象概念数量。我们之所以选择从不同“维度”关注同一个事物,目的在于期望了解事物本身和跟其他事物所存在的联系。
一页纸或者手机、平板和电脑屏幕上的图像,这些是二维(2D)对象,具有长和宽;我们生活在三维世界,加上时间这一维度,可以描述某一事件发生的时间和地点。三维(3D)对象不仅有长度和宽度,还有高度。物理世界的仿真模拟、游戏和动画会把三维数据映射到二维屏幕上。
我们天生对于处理二维或者三维空间中的数据感到自然,但现实场景下的数据往往具有更多维度。
比如:某购物网站为了分析用户的消费习惯,需要跟踪记录性别、年龄、出生年月、喜欢的商品种类等上百个用户相关属性。
这就需要一个能够处理高维数据的数学工具,即向量数学。二维空间中的点,使用有序数对来表示,而三维空间中点,使用三元数对来表示。以此类推,可以推广到多维空间。我们把向量(vector)看作多维空间中的一个点。
向量不仅可以描述二维或者三维空间,还可以扩展到多维空间。我们先从最简单的二维向量开始,了解二维向量的基本概念。
二维向量
二维向量(two-dimensional vector)可以看作平面上从A点指向B点的有向线段。有向线段的长度表示向量的大小,有向线段的方向表示向量的方向。
可以使用黑体字母a,w,v,F表示向量,也可以使用如下方式表示向量:
为了方便处理和观察,我们会把作为原点,建立坐标系。二维向量可以使用有序对表示:
多个二维向量可以组成有意思的形状。比如:我们使用Python绘制一个正方形。
1.绘制散点图
#定义一组二维向量
two_dim_vectors=[(-2,2),(0,2),(2,2),(2,0),(2,-2),(0,-2),(-2,-2),(-2,0)]
#绘制散点图
draw_objects(Points(two_dim_vectors))
绘制效果图:
2.绘制线段
#定义一组二维向量
two_dim_vectors=[(-2,2),(0,2),(2,2),(2,0),(2,-2),(0,-2),(-2,-2),(-2,0)]
#绘制(-2,2)到(0,2)的线段
start_point=(-2,2)
end_point=(0,2)
draw_objects(Points(two_dim_vectors),Line(start_point,end_point))
绘制效果图:
3.绘制正方形
我们将散点图中的所有点,通过直线连接,可以得到二维平面下的正方形:
#定义一组二维向量
two_dim_vectors=[(-2,2),(0,2),(2,2),(2,0),(2,-2),(0,-2),(-2,-2),(-2,0)]
#绘制正方形
draw_objects(Points(two_dim_vectors),Lines(two_dim_vectors))
绘制效果图:
绘制函数定义
#draw_objects.py
#绘制一个或者多个对象
from math import ceil, floor
import numpy as np
import matplotlib.pyplot as plt
#颜色定义
blue = 'b'
black = 'k'
red = 'r'
green = 'g'
#定义一组点:二维向量列表和默认颜色
class Points:
def __init__(self,vectors,color=black):
self.vectors=vectors
self.color=color
#定义一条线段:起点 终点和默认颜色
class Line:
def __init__(self,start_point,end_point,color=black):
self.start_point=start_point
self.end_point=end_point
self.color=color
#绘制多条线段
class Lines:
def __init__(self, vectors, color=blue):
self.vectors = vectors
self.color = color
#收集所有二维向量(a,b)到all_vectors列表[(a,b)]中
def collect_data(*objects):
all_vectors = []
for draw_object in objects:
if type(draw_object) == Points:
for v in draw_object.vectors:
all_vectors.append(v)
elif type(draw_object) == Line:
all_vectors.append(draw_object.start_point)
all_vectors.append(draw_object.end_point)
elif type(draw_object) == Lines:
for v in draw_object.vectors:
all_vectors.append(v)
else:
raise TypeError("type is not defined: {}".format(draw_object))
return all_vectors
#绘制数据前的准备
def draw_data_prepare(max_x, max_y, min_x, min_y,origin, axes, grid):
# 设置坐标范围
if grid:
# ceil() 向上取整 ceil(2.3)=3
# 网格间距
x_padding = max(ceil(0.05 * (max_x - min_x)), grid[0])
y_padding = max(ceil(0.05 * (max_y - min_y)), grid[1])
# floor() 向下取整 floor(2.3)=2
# 计算x轴范围(left,right)
x_limit = floor((min_x - x_padding) / grid[0]) * grid[0], ceil((max_x + x_padding) / grid[0]) * grid[0]
# 计算y轴范围(bottom, top)
y_limit = floor((min_y - y_padding) / grid[1]) * grid[1], ceil((max_y + y_padding) / grid[1]) * grid[1]
plt.xlim(x_limit)
plt.ylim(y_limit)
# 画出原点
if origin:
plt.scatter([0], [0], color='k', marker='x')
# 展示网格
if grid:
# 设置网格刻度
plt.gca().set_xticks(np.arange(plt.xlim()[0], plt.xlim()[1], grid[0]))
plt.gca().set_yticks(np.arange(plt.ylim()[0], plt.ylim()[1], grid[1]))
plt.grid(True)
plt.gca().set_axisbelow(True)
# 绘制坐标轴
if axes:
plt.gca().axhline(linewidth=2, color='k')
plt.gca().axvline(linewidth=2, color='k')
"""
绘制一个或者多个对象
objects:绘制对象
origin:是否显示原点
axes:是否显示坐标轴
grid:坐标轴单元刻度
"""
def draw_objects(*objects, origin=True, axes=True, grid=(1,1)):
#收集数据
all_vectors=collect_data(*objects)
#print(all_vectors)
#使用zip将包含多个元组(a,b)的列表,拆分为(a...)和(b....)两个元组
#*表示对传入的列表拆包,函数参数带*,会将每个元素重新组装成一个元组
xs, ys = zip(*all_vectors)
#print(xs)
#print(ys)
#寻找x和y的最小值和最大值
max_x, max_y, min_x, min_y = max(0, *xs), max(0, *ys), min(0, *xs), min(0, *ys)
#绘制数据前的准备
draw_data_prepare(max_x, max_y, min_x, min_y, origin, axes, grid)
#开始绘制
for draw_object in objects:
if type(draw_object)==Points:
points_x = [vector[0] for vector in draw_object.vectors]
points_y = [vector[1] for vector in draw_object.vectors]
#绘制散点图
plt.scatter(points_x,points_y,color=draw_object.color)
elif type(draw_object) == Line:
x1,y1=draw_object.start_point
x2,y2=draw_object.end_point
# 绘制单条折线
plt.plot([x1,x2], [y1,y2], color=object.color)
elif type(draw_object) == Lines:
for i in range(0,len(draw_object.vectors)):
#当前点
x1, y1 = draw_object.vectors[i]
#相邻点
#注意最后一个点(下标):len(list)-1,相邻点:len(list),
#需要取模len,得到第一个点(下标):0
x2, y2 = draw_object.vectors[(i+1)%len(draw_object.vectors)]
# 绘制单条折线
plt.plot([x1, x2], [y1, y2], color=draw_object.color)
#展示
plt.show()
#定义一组二维向量
two_dim_vectors=[(-2,2),(0,2),(2,2),(2,0),(2,-2),(0,-2),(-2,-2),(-2,0)]
#绘制正方形
draw_objects(Points(two_dim_vectors),Lines(two_dim_vectors))