其他分享
首页 > 其他分享> > Numpy的高级应用

Numpy的高级应用

作者:互联网

Numpy的高级应用

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

plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
import pandas as pd
import matplotlib.pyplot as plt

plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
%config InlineBackend.figure_format = 'svg'
# 常用函数
array1 = np.arange(1, 10).reshape(3, 3)
array1
array2 = np.array([[1, 1, 1], [2, 2, 2], [3, 3, 3]])
array2
# 水平方向拼接
np.hstack((array1, array2))
# 垂直方向拼接
np.vstack((array1, array2))
# 沿着指定的轴拼接
np.concatenate((array1, array2))
np.concatenate((array1, array2), axis=1)
# 垂直方向拆分
np.vsplit(array2, 3)
# 水平方向拆分
np.hsplit(array2, 3)
# 在末尾追加元素
np.append(array1, 10)
# 在指定位置插入元素
np.insert(array1, 0, 0)
array1[array1 % 3 == 0]
# 根据条件筛选数据
np.extract(array1 % 3 == 0, array1)
# 根据条件和公式获取数据
x = np.arange(10)
condlist = [x < 3, x > 5]
choicelist = [x, x ** 2]
np.select(condlist, choicelist, default=np.nan)
# 根据条件和公式获取数据
np.where(x < 5, x, 10 * x)
def fib(n):
    a, b = 0, 1
    for _ in range(n):
        a, b = b, a + b
        yield a

        
gen = fib(20)
# 通过迭代器(生成器)创建数组对象
array3 = np.fromiter(gen, dtype=np.int64, count=10)
array3
# 调整数组的大小
np.resize(array1, (4, 4))

向量

点积运算
A ⋅ B = a 1 b 1 + a 2 b 2 = ∣ A ∣ ∣ B ∣ c o s θ A \cdot B = a_1b_1 + a_2b_2 = \lvert A \rvert \lvert B \rvert cos \theta A⋅B=a1​b1​+a2​b2​=∣A∣∣B∣cosθ

A ⋅ B = ∑ i = 1 n a i b i = ∣ A ∣ ∣ B ∣ c o s θ A \cdot B = \sum_{i=1}^{n} a_ib_i = \lvert A \rvert \lvert B \rvert cos \theta A⋅B=i=1∑n​ai​bi​=∣A∣∣B∣cosθ

v1 = np.array([3, 5])
v2 = np.array([1, 3])
# inner_prod = np.dot(v1, v2)
inner_prod = np.inner(v1, v2)
print('向量点积:', inner_prod)
> 说明:在欧几里得几何中,两个笛卡尔坐标向量的点积也称为内积(inner product),但是内积的含义要高于点积,点积相当于是内积在欧几里得空间 $ \mathbb{R}^n $ 的特例,而内积可以推广到赋范向量空间。
v1_norm = np.linalg.norm(v1)
v2_norm = np.linalg.norm(v2)
print('v1的模:', np.round(v1_norm, 6))
print('v2的模:', np.round(v2_norm, 6))
cos_theta = inner_prod / (v1_norm * v2_norm)
print('向量夹角余弦值:', cos_theta)
print('夹角:', np.arccos(cos_theta) * 180 / np.pi)

行列式
d e t ( A ) = ∑ n ! ± a 1 α a 2 β a 3 γ ⋯ a n ω det(A) = \sum_{n!} \pm a_{1\alpha}a_{2\beta}a_{3\gamma} \cdots a_{n\omega} det(A)=n!∑​±a1α​a2β​a3γ​⋯anω​

array4 = np.stack((v1, v2))
array4

d e t ∣ 3 5 1 3 ∣ = 4 det \begin{vmatrix} 3 & 5 \\ 1 & 3 \end{vmatrix} = 4 det∣∣∣∣​31​53​∣∣∣∣​=4

d e t ∣ 3 5 1 3 ∣ = 4 det \begin{vmatrix} 3 & 5 \\ 1 & 3 \end{vmatrix} = 4 det∣∣∣∣​31​53​∣∣∣∣​=4

# 计算行列式的值
np.round(np.linalg.det(array4), 2)

d e t ∣ 1 2 3 4 5 6 7 8 9 ∣ = 0 det \begin{vmatrix} 1 & 2 & 3 \\ 4 & 5 & 6 \\ 7 & 8 & 9 \end{vmatrix} = 0 det∣∣∣∣∣∣​147​258​369​∣∣∣∣∣∣​=0

d e t ∣ 1 2 3 4 5 6 7 8 9 ∣ = 0 det \begin{vmatrix} 1 & 2 & 3 \\ 4 & 5 & 6 \\ 7 & 8 & 9 \end{vmatrix} = 0 det∣∣∣∣∣∣​147​258​369​∣∣∣∣∣∣​=0

np.linalg.det(array1)
# 矩阵
array1 = np.arange(1, 10).reshape((3, 3))
array1

对上面的array1做一组线性变换,就知道为什么它的秩是2了。

∣ 1 2 3 4 5 6 7 8 9 ∣ → ∣ 1 2 3 0 − 3 − 6 0 − 6 − 12 ∣ \begin{vmatrix} 1 & 2 & 3\\ 4 & 5 & 6\\ 7 & 8 & 9 \end{vmatrix} \quad \to \quad \begin{vmatrix} 1 & 2 & 3\\ 0 & -3 & -6\\ 0 & -6 & -12 \end{vmatrix} ∣∣∣∣∣∣​147​258​369​∣∣∣∣∣∣​→∣∣∣∣∣∣​100​2−3−6​3−6−12​∣∣∣∣∣∣​

# 求逆矩阵
# LinAlgError ---> Singluar matrix ---> 奇异矩阵不能求逆
# np.linalg.inv(array1)
array2 = np.array([[1, 2], [3, 4]])
array2
array3 = np.linalg.inv(array2)
array3

A ⋅ A − 1 = I A \cdot A^{-1} = I A⋅A−1=I

np.round(array2 @ array3, 2)
# 求矩阵的秩
np.linalg.matrix_rank(array1)
array1[2, 2] = 8
array1
np.linalg.matrix_rank(array1)
解线性方程:

$$ 
\begin{cases} 
3x + y = 9 \\ 
x + 2y = 8
\end{cases}
$$
A = np.array([[3, 1], [1, 2]])
b = np.array([9, 8]).reshape(-1, 1)
np.linalg.solve(A, b)
$$
Ax = b\\
A^{-1}Ax = A^{-1}b\\
Ix = A^{-1}b
$$
A_1 = np.linalg.inv(A)
A_1
A_1 @ b
#### 最小二乘解
!pip install scikit-learn
from sklearn.datasets import load_boston

# 获取波士顿房价数据
dataset = load_boston()
print(dataset.DESCR)
dataset.data.shape
dataset.feature_names
# 用波士顿房价数据创建DataFrame对象
df = pd.DataFrame(data=dataset.data, columns=dataset.feature_names)
df
# 计算协方差
df.cov()
# 计算皮尔逊相关系数
np.round(df.corr(), 2)
rooms = df['RM'].values
prices = df['PRICE'].values
history_data = {room: price for room, price in zip(rooms, prices)}
history_data
通过计算皮尔逊相关系数,发现房间数和房价存在正相关,接下来我们通过学习历史数据,最终实现用房间数预测房价的目标。
import heapq
nums = [35, 98, 76, 12, 55, 68, 47, 92]
print(heapq.nlargest(3, nums))
print(heapq.nsmallest(3, nums))
import heapq

# kNN算法
def predict_price_by_knn(history_data, room, k=5):
    # keys = sorted(history_data, key=lambda x: (x - room) ** 2)[:k]
    keys = heapq.nsmallest(k, history_data, key=lambda x: (x - room) ** 2)
    return np.mean([history_data[key] for key in keys])
# 预测房价
np.round(predict_price_by_knn(history_data, 6.25), 2)
np.round(predict_price_by_knn(history_data, 5.125), 2)
# 通过散点图研究变量的关系
plt.scatter(rooms, prices)
plt.show()
通过上面的图,我们发现房间数和房价呈现出线性关系,接下来我们尝试用一个线性函数来实现对房价的预测。

#### 损失函数

回归方程:$x$ 代表房间数,$y$ 就是要预测的房价。
$$
y = ax + b
$$

现在我们的问题是找到一组`a`和`b`,让预测达到最佳的效果(误差最小就是最佳)。

均方误差:让均方误差最小的 $a$ 和 $b$ 就是最佳拟合。
$$
MSE = \frac{1} {N} \sum (\hat{y_i} - y_i)^2
$$
def get_loss(x, y, a, b):
    """损失函数"""
    y_hat = a * x + b
    return np.mean((y_hat - y) ** 2)
# 通过蒙特卡罗模拟找到实现最佳拟合的a和b的值
import random

best_a, best_b = None, None
min_loss = np.inf

for _ in range(1000):
    # 随机产生a和b的值
    a = random.random() * 200 - 100
    b = random.random() * 200 - 100
    # 计算损失(MSE)
    curr_loss = get_loss(rooms, prices, a, b)
    # 让损失更小的a和b就是更好的拟合
    if curr_loss < min_loss:
        min_loss = curr_loss
        best_a, best_b = a, b
print(best_a, best_b)
print(min_loss)
#### 梯度下降

损失函数是凹函数,找到使函数最小的`a`和`b`的值,可以用下面的方法:

$$ a^\prime = a + (-1) \times \frac {\partial loss(a, b)} {\partial a} \times \Delta $$
$$ b^\prime = b + (-1) \times \frac {\partial loss(a, b)} {\partial b} \times \Delta $$

对于求MSE的损失函数来说,可以用下面的公式计算偏导数:

$$ f(a, b) = \frac {1} {N} \sum_{i=1}^{N}(y_i - (ax_i + b))^2 $$
$$ \frac {\partial {f(a, b)}} {\partial {a}} = \frac {2} {N} \sum_{i=1}^{N}(-x_iy_i + x_i^2a + x_ib) $$ 
$$ \frac {\partial {f(a, b)}} {\partial {b}} = \frac {2} {N} \sum_{i=1}^{N}(-y_i + x_ia + b) $$
# 求a的偏导数
def partial_a(x, y, a, b):
    return 2 * np.mean((y - a * x - b) * (-x))


# 求b的偏导数
def partial_b(x, y, a, b):
    return 2 * np.mean(-y + a * x + b)
# 通过梯度下降的方式向拐点逼近
# 这种方式能够更快的找到最佳拟合的a和b
# a和b的初始值可以随意设定,delta的值要足够小
a, b = 35, -35
delta = 0.01

for _ in range(100):
    a = a - partial_a(rooms, prices, a, b) * delta
    b = b - partial_b(rooms, prices, a, b) * delta
print(a, b)
print(get_loss(rooms, prices, a, b))
# 通过线性回归方程预测房价
def predict_price_by_regression(a, b, x):
    return a * x + b
# 预测房价
print(np.round(predict_price_by_regression(best_a, best_b, 6.25), 2))
print(np.round(predict_price_by_regression(a, b, 6.25), 2))
print(np.round(predict_price_by_regression(best_a, best_b, 5.12), 2))
print(np.round(predict_price_by_regression(a, b, 5.12), 2))
# 比较两条拟合曲线
y_hat1 = best_a * rooms + best_b
y_hat2 = a * rooms + b
plt.scatter(rooms, prices)
plt.plot(rooms, y_hat1, color='red', linewidth=4)
plt.plot(rooms, y_hat2, color='green', linewidth=4)
plt.show()
最小二乘解就是用已经得到的历史数据(`x`和`y`的值)找到能够最佳拟合这些历史数据的`a`和`b`。

$$
y = ax + b
$$

对于上面的方程,相当于`x`是变量`a`的系数,`1`是变量`b`的系数。

#### `lstsq`函数参数说明

`lstsq`函数的第一个参数是$ \begin{bmatrix} x \\ 1 \\ \end{bmatrix} ^T $,第二个参数就是`y`,`rcond`参数暂时不管,直接设置为`None`。
# lstsq函数的第一个参数
param1 = np.vstack([rooms, np.ones(rooms.size)]).T
param1
# lstsq函数的第二个参数
param2 = prices
param2
#### `lstsq`函数返回值说明

`lstsq`函数返回的是一个四元组,四元组中的第一个元素就是要求解的方程的系数,四元组中的第二个元素是误差平方和。
# rcond参数直接设置为None(暂不解释)
result = np.linalg.lstsq(param1, param2, rcond=None)
result
a, b = result[0]
mse = result[1][0] / rooms.size
print(a, b)
print(mse)
# 比较两条拟合曲线
plt.scatter(rooms, prices)
# 梯度下降法给出的a和b预测出的房价
plt.plot(rooms, y_hat2, color='red', linewidth=4)
# lstsq函数给出的a和b预测出的房价
y_hat3 = a * rooms + b
plt.plot(rooms, y_hat3, color='green', linewidth=4)
plt.show()

标签:plt,partial,array1,高级,print,rooms,应用,np,Numpy
来源: https://blog.csdn.net/weixin_48423550/article/details/120832716