2.2-2.6数据预处理、线性代数、微积分、自动微分、概率
2.2-2.6
数据预处理、线性代数、微积分、自动微分、概率
2.2.1读取数据集
import os
os.makedirs(os.path.join('..', 'data'), exist_ok=True)
data_file = os.path.join('..', 'data', 'house_tiny.csv')
with open(data_file, 'w') as f:
f.write('NumRooms,Alley,Price\n') # 列名
f.write('NA,Pave,127500\n')
f.write('2,NA,106000\n')
f.write('4,NA,178100\n')
f.write('NA,NA,140000\n')
import pandas as pd
data = pd.read_csv(data_file)
print(data)
"""
NumRooms Alley Price
0 NaN Pave 127500
1 2.0 NaN 106000
2 4.0 NaN 178100
3 NaN NaN 140000
"""
2.2.2处理缺失值
inputs, outputs = data.iloc[:, 0:2], data.iloc[:, 2]
inputs = inputs.fillna(inputs.mean(numeric_only=True))
print(inputs)
"""
NumRooms Alley
0 3.0 Pave
1 2.0 NaN
2 4.0 NaN
3 3.0 NaN
"""
inputs = pd.get_dummies(inputs, dummy_na=True)
print(inputs)
"""
NumRooms Alley_Pave Alley_nan
0 3.0 1 0
1 2.0 0 1
2 4.0 0 1
3 3.0 0 1
"""
2.2.3转换为张量格式
import tensorflow as tf
X, y = tf.constant(inputs.values), tf.constant(outputs.values)
X, y
"""
(<tf.Tensor: shape=(4, 3), dtype=float64, numpy=
array([[3., 1., 0.],
[2., 0., 1.],
[4., 0., 1.],
[3., 0., 1.]])>,
<tf.Tensor: shape=(4,), dtype=int64, numpy=array([127500, 106000, 178100, 140000], dtype=int64)>)
"""
2.3.1标量
import tensorflow as tf
x = tf.constant(3.0)
y = tf.constant(2.0)
x+y, x*y, x/y, x**y
"""
(<tf.Tensor: shape=(), dtype=float32, numpy=5.0>,
<tf.Tensor: shape=(), dtype=float32, numpy=6.0>,
<tf.Tensor: shape=(), dtype=float32, numpy=1.5>,
<tf.Tensor: shape=(), dtype=float32, numpy=9.0>)
"""
2.3.2向量
x = tf.range(4)
x
"""
<tf.Tensor: shape=(4,), dtype=int32, numpy=array([0, 1, 2, 3])>
"""
x[3]
"""
<tf.Tensor: shape=(), dtype=int32, numpy=3>
"""
len(x)
"""
4
"""
x.shape
"""
TensorShape([4])
"""
2.3.3矩阵
A = tf.reshape(tf.range(20), (5, -1))
A
"""
<tf.Tensor: shape=(5, 4), dtype=int32, numpy=
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11],
[12, 13, 14, 15],
[16, 17, 18, 19]])>
"""
tf.transpose(A)
"""
<tf.Tensor: shape=(4, 5), dtype=int32, numpy=
array([[ 0, 4, 8, 12, 16],
[ 1, 5, 9, 13, 17],
[ 2, 6, 10, 14, 18],
[ 3, 7, 11, 15, 19]])>
"""
B = tf.constant([[1, 2, 3], [2, 0, 4], [3, 4, 5]])
B
"""
<tf.Tensor: shape=(3, 3), dtype=int32, numpy=
array([[1, 2, 3],
[2, 0, 4],
[3, 4, 5]])>
"""
B == tf.transpose(B)
"""
<tf.Tensor: shape=(3, 3), dtype=bool, numpy=
array([[ True, True, True],
[ True, True, True],
[ True, True, True]])>
"""
2.3.4张量
X = tf.reshape(tf.range(24), (2, 3, 4))
X
"""
<tf.Tensor: shape=(2, 3, 4), dtype=int32, numpy=
array([[[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]],
[[12, 13, 14, 15],
[16, 17, 18, 19],
[20, 21, 22, 23]]])>
"""
2.3.5张量算法的基本性质
A = tf.reshape(tf.range(20, dtype=tf.float32), (5, 4))
B = A # 不能通过分配新内存将A克隆到B
A, A+B
"""
(<tf.Tensor: shape=(5, 4), dtype=float32, numpy=
array([[ 0., 1., 2., 3.],
[ 4., 5., 6., 7.],
[ 8., 9., 10., 11.],
[12., 13., 14., 15.],
[16., 17., 18., 19.]], dtype=float32)>,
<tf.Tensor: shape=(5, 4), dtype=float32, numpy=
array([[ 0., 2., 4., 6.],
[ 8., 10., 12., 14.],
[16., 18., 20., 22.],
[24., 26., 28., 30.],
[32., 34., 36., 38.]], dtype=float32)>)
"""
id(A), id(B)
"""
(1351416459856, 1351416459856)
"""
A * B
"""
<tf.Tensor: shape=(5, 4), dtype=float32, numpy=
array([[ 0., 1., 4., 9.],
[ 16., 25., 36., 49.],
[ 64., 81., 100., 121.],
[144., 169., 196., 225.],
[256., 289., 324., 361.]], dtype=float32)>
"""
a = 2
X = tf.reshape(tf.range(24), (2, 3, 4))
a + X, (a * X).shape
"""
(<tf.Tensor: shape=(2, 3, 4), dtype=int32, numpy=
array([[[ 2, 3, 4, 5],
[ 6, 7, 8, 9],
[10, 11, 12, 13]],
[[14, 15, 16, 17],
[18, 19, 20, 21],
[22, 23, 24, 25]]])>,
TensorShape([2, 3, 4]))
"""
2.3.6降维
x = tf.range(4, dtype=tf.float32)
x, tf.reduce_sum(x)
"""
(<tf.Tensor: shape=(4,), dtype=float32, numpy=array([0., 1., 2., 3.], dtype=float32)>,
<tf.Tensor: shape=(), dtype=float32, numpy=6.0>)
"""
A.shape, tf.reduce_sum(A)
"""
(TensorShape([5, 4]), <tf.Tensor: shape=(), dtype=float32, numpy=190.0>)
"""
A_sum_axis0 = tf.reduce_sum(A, axis=0)
A_sum_axis0, A_sum_axis0.shape
"""
(<tf.Tensor: shape=(4,), dtype=float32, numpy=array([40., 45., 50., 55.], dtype=float32)>,
TensorShape([4]))
"""
A_sum_axis1 = tf.reduce_sum(A, axis=1)
A_sum_axis1, A_sum_axis1.shape
"""
(<tf.Tensor: shape=(5,), dtype=float32, numpy=array([ 6., 22., 38., 54., 70.], dtype=float32)>,
TensorShape([5]))
"""
tf.reduce_sum(A, axis=[0, 1])
"""
<tf.Tensor: shape=(), dtype=float32, numpy=190.0>
"""
tf.reduce_mean(A), tf.reduce_sum(A) / tf.size(A).numpy()
"""
(<tf.Tensor: shape=(), dtype=float32, numpy=9.5>,
<tf.Tensor: shape=(), dtype=float32, numpy=9.5>)
"""
tf.size(A)
"""
<tf.Tensor: shape=(), dtype=int32, numpy=20>
"""
tf.reduce_mean(A, axis=0), tf.reduce_sum(A, axis=0) / A.shape[0]
"""
(<tf.Tensor: shape=(4,), dtype=float32, numpy=array([ 8., 9., 10., 11.], dtype=float32)>,
<tf.Tensor: shape=(4,), dtype=float32, numpy=array([ 8., 9., 10., 11.], dtype=float32)>)
"""
sum_A = tf.reduce_sum(A, axis=1, keepdims=True)
sum_A
"""
<tf.Tensor: shape=(5, 1), dtype=float32, numpy=
array([[ 6.],
[22.],
[38.],
[54.],
[70.]], dtype=float32)>
"""
A / sum_A
"""
<tf.Tensor: shape=(5, 4), dtype=float32, numpy=
array([[0. , 0.16666667, 0.33333334, 0.5 ],
[0.18181819, 0.22727273, 0.27272728, 0.3181818 ],
[0.21052632, 0.23684211, 0.2631579 , 0.28947368],
[0.22222222, 0.24074075, 0.25925925, 0.2777778 ],
[0.22857143, 0.24285714, 0.25714287, 0.27142859]], dtype=float32)>
"""
tf.cumsum(A, axis=0)
"""
<tf.Tensor: shape=(5, 4), dtype=float32, numpy=
array([[ 0., 1., 2., 3.],
[ 4., 6., 8., 10.],
[12., 15., 18., 21.],
[24., 28., 32., 36.],
[40., 45., 50., 55.]], dtype=float32)>
"""
2.3.7点积
y = tf.ones(4, dtype=tf.float32)
x, y, tf.tensordot(x, y, axes=1)
"""
(<tf.Tensor: shape=(4,), dtype=float32, numpy=array([0., 1., 2., 3.], dtype=float32)>,
<tf.Tensor: shape=(4,), dtype=float32, numpy=array([1., 1., 1., 1.], dtype=float32)>,
<tf.Tensor: shape=(), dtype=float32, numpy=6.0>)
"""
# 这里axes=1,说明取a的后1维即[3]和b的前1维即[3]进行矩阵相乘,其他维不变,那么根据矩阵乘法,自然得到c的大小为[2,3,2,6]
a = tf.ones(shape=(2, 3, 3))
b = tf.ones(shape=(3, 2, 6))
print(tf.tensordot(a, b, axes=1).shape)
"""
(2, 3, 2, 6)
"""
# 这里c的大小为[2,6],axes=2,即取a的后两维相乘后得到的2*3=6,与b的前两维相乘后得到的3*2=6,进行矩阵相乘运算,
# 即大小为[2,6]的矩阵与大小为[6,6]的矩阵进行矩阵相乘运算,得到的c的大小即为[2,6]
a = tf.ones(shape=(2, 2, 3))
b = tf.ones(shape=(3, 2, 6))
print(tf.tensordot(a, b, axes=2).shape)
"""
(2, 6)
"""
# 如果axes参数是一个元组,则元组的第一维指第一个乘数a要做运算的下标,第二维指第二个乘数要做运算的下标。
# 这里axes=(1,1),也就是说a的第1维与b的第一维进行矩阵相乘。相当于[2,3,2]*[2,3,6],结果c即为[2,3,3,6]
a = tf.ones(shape=(2, 2, 3))
b = tf.ones(shape=(3, 2, 6))
print(tf.tensordot(a, b, axes=(1, 1)).shape)
"""
(2, 3, 3, 6)
"""
# axes同样是元组,这里表明a的第1,2维和b的第0,1维进行矩阵乘法。即[2,2*3] * [3*2,6]= [2,6] * [6,6] = [2,6],c的大小即为[2,6]
a = tf.ones(shape=(2, 2, 3))
b = tf.ones(shape=(3, 2, 6))
print(tf.tensordot(a, b, axes=((1, 2), (0, 1))).shape)
"""
(2, 6)
"""
tf.reduce_sum(x * y)
"""
<tf.Tensor: shape=(), dtype=float32, numpy=6.0>
"""
2.3.8矩阵-向量积
A.shape, x.shape, tf.linalg.matvec(A, x)
"""
(TensorShape([5, 4]),
TensorShape([4]),
<tf.Tensor: shape=(5,), dtype=float32, numpy=array([ 14., 38., 62., 86., 110.], dtype=float32)>)
"""
2.3.9矩阵-矩阵乘法
B = tf.ones((4, 3), tf.float32)
tf.matmul(A, B)
"""
<tf.Tensor: shape=(5, 3), dtype=float32, numpy=
array([[ 6., 6., 6.],
[22., 22., 22.],
[38., 38., 38.],
[54., 54., 54.],
[70., 70., 70.]], dtype=float32)>
"""
2.3.10范数
u = tf.constant([-3.0, -4.0])
tf.norm(u)
"""
<tf.Tensor: shape=(), dtype=float32, numpy=5.0>
"""
tf.reduce_sum(tf.abs(u))
"""
<tf.Tensor: shape=(), dtype=float32, numpy=7.0>
"""
tf.norm(tf.ones((4, 9)))
"""
<tf.Tensor: shape=(), dtype=float32, numpy=6.0>
"""
2.4.1导数和微分
import numpy as np
from matplotlib_inline import backend_inline
import matplotlib.pyplot as plt
def f(x):
return 3 * x ** 2 - 4 * x
def numeric_lim(f, x, h):
return (f(x+h) - f(x)) / h
h = 0.1
for i in range(5):
print(f'h={h:.5f}, numerical limit={numeric_lim(f, 1, h):.5f}')
h *= 0.1
"""
h=0.10000, numerical limit=2.30000
h=0.01000, numerical limit=2.03000
h=0.00100, numerical limit=2.00300
h=0.00010, numerical limit=2.00030
h=0.00001, numerical limit=2.00003
"""
def use_svg_display():
backend_inline.set_matplotlib_formats('svg')
def set_figsize(figsize=(3.5, 2.5)):
use_svg_display()
plt.rcParams['figure.figsize'] = figsize
def set_axes(axes, xlabel, ylabel, xlim, ylim, xscale, yscale, legend):
"""设置matplotlib的轴"""
axes.set_xlabel(xlabel)
axes.set_ylabel(ylabel)
axes.set_xscale(xscale)
axes.set_yscale(yscale)
axes.set_xlim(xlim)
axes.set_ylim(ylim)
if legend:
axes.legend(legend)
axes.grid()
def plot(X, Y=None, xlabel=None, ylabel=None, legend=None, xlim=None,
ylim=None, xscale='linear', yscale='linear',
fmts=('-', 'm--', 'g-.', 'r:'), figsize=(3.5, 2.5), axes=None):
"""绘制数据点"""
if legend is None:
legend = []
set_figsize(figsize)
axes = axes if axes else plt.gca()
# 如果X有一个轴,输出True
def has_one_axis(X):
return (hasattr(X, "ndim") and X.ndim == 1 or isinstance(X, list)
and not hasattr(X[0], "__len__"))
if has_one_axis(X):
X = [X]
if Y is None:
X, Y = [[]] * len(X), X
elif has_one_axis(Y):
Y = [Y]
if len(X) != len(Y):
X = X * len(Y)
axes.cla()
for x, y, fmt in zip(X, Y, fmts):
if len(x):
axes.plot(x, y, fmt)
else:
axes.plot(y, fmt)
set_axes(axes, xlabel, ylabel, xlim, ylim, xscale, yscale, legend)
x = np.arange(0, 3, 0.1)
plot(x, [f(x), 2*x-3], 'x', 'f(x)', legend=['f(x)', 'Tangent line (x=1)'])
2.5.1自动微分简单示例
import tensorflow as tf
x = tf.range(4, dtype=tf.float32)
x
"""
<tf.Tensor: shape=(4,), dtype=float32, numpy=array([0., 1., 2., 3.], dtype=float32)>
"""
x = tf.Variable(x)
# 把所有计算记录在磁带上
with tf.GradientTape() as t:
y = 2 * tf.tensordot(x, x, axes=1)
y
"""
<tf.Tensor: shape=(), dtype=float32, numpy=28.0>
"""
x_grad = t.gradient(y, x)
x_grad
"""
<tf.Tensor: shape=(4,), dtype=float32, numpy=array([ 0., 4., 8., 12.], dtype=float32)>
"""
x_grad == 4 * x
"""
<tf.Tensor: shape=(4,), dtype=bool, numpy=array([ True, True, True, True])>
"""
with tf.GradientTape() as t:
y = tf.reduce_sum(x)
t.gradient(y, x) # 被新计算的梯度覆盖
"""
<tf.Tensor: shape=(4,), dtype=float32, numpy=array([1., 1., 1., 1.], dtype=float32)>
"""
2.5.2非标量变量的反向传播
with tf.GradientTape() as t:
y = x * x
t.gradient(y, x)
"""
<tf.Tensor: shape=(4,), dtype=float32, numpy=array([0., 2., 4., 6.], dtype=float32)>
"""
2.5.3分离计算
# 设置persistent=True来运行t.gradient多次
# 在调用gradient的时候,tf.GradientTape()的内容会被立即释放,如果要计算多组微分,则需要添加参数persistent=True
# 如果是常量的话需要添加watch来监控
with tf.GradientTape(persistent=True) as t:
y = x * x
u = tf.stop_gradient(y)
z = u * x
x_grad = t.gradient(z, x)
x_grad == u
"""
<tf.Tensor: shape=(4,), dtype=bool, numpy=array([ True, True, True, True])>
"""
t.gradient(y, x) == 2 * x
"""
<tf.Tensor: shape=(4,), dtype=bool, numpy=array([ True, True, True, True])>
"""
2.5.4Python控制流的梯度计算
def f(a):
b = a * 2
while tf.norm(b) < 1000:
b = b * 2
if tf.reduce_sum(b) > 0:
c = b
else:
c = 100 * b
return c
a = tf.Variable(tf.random.normal(shape=()))
with tf.GradientTape() as t:
d = f(a)
d_grad = t.gradient(d, a)
d_grad
"""
<tf.Tensor: shape=(), dtype=float32, numpy=512.0>
"""
d_grad == d / a
"""
<tf.Tensor: shape=(), dtype=bool, numpy=True>
"""
2.6.1 基本概率论
import numpy as np
import tensorflow as tf
import tensorflow_probability as tfp
fair_probs = tf.ones(6) / 6
tfp.distributions.Multinomial(1, fair_probs).sample()
"""
<tf.Tensor: shape=(6,), dtype=float32, numpy=array([0., 0., 0., 1., 0., 0.], dtype=float32)>
"""
tfp.distributions.Multinomial(10, fair_probs).sample()
"""
<tf.Tensor: shape=(6,), dtype=float32, numpy=array([3., 1., 1., 1., 2., 2.], dtype=float32)>
"""
counts = tfp.distributions.Multinomial(1000, fair_probs).sample()
counts / 1000
"""
<tf.Tensor: shape=(6,), dtype=float32, numpy=array([0.156, 0.185, 0.18 , 0.159, 0.173, 0.147], dtype=float32)>
"""
counts = tfp.distributions.Multinomial(10, fair_probs).sample(500)
cum_counts = tf.cumsum(counts, axis=0)
estimates = cum_counts / tf.reduce_sum(cum_counts, axis=1, keepdims=True)
plt.figure(figsize=(6, 4.5))
for i in range(6):
plt.plot(estimates[:, i].numpy(), label=('P(die=' + str(i+1) + ")"))
plt.axhline(y=0.167, color='k', linestyle='--')
plt.gca().set_xlabel('Groups of experiments')
plt.gca().set_ylabel('Estimated probability')
plt.show()