今天看一个通过逻辑回归解决手写数字识别任务的案例,有个之前没有注意到的点,记录一下。
import numpy as np
import pandas as pd
data = pd.read_csv('../data/mnist-demo.csv') # 导入数据集
pd_train_data = data.sample(frac=0.8) # 训练集划分
train_data = pd_train_data.values # Ndarray数组格式
num_training_examples = 6000 # 数据量
y_train = train_data[:num_training_examples, [0]] # label
print(y_train[:10])
print(np.unique(y_train))
输出如下
[[1]
[4]
[5]
[6]
[9]]
[0 1 2 3 4 5 6 7 8 9]
那么问题来了current_lables输出是什么?
current_lables = (y_train[:5] == np.unique(y_train)).astype(float)
print(current_lables)
输出结果如下
[[0. 1. 0. 0. 0. 0. 0. 0. 0. 0.]
[0. 0. 0. 0. 1. 0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0. 1. 0. 0. 0. 0.]
[0. 0. 0. 0. 0. 0. 1. 0. 0. 0.]
[0. 0. 0. 0. 0. 0. 0. 0. 0. 1.]]
这个我们就要从NumPy广播开始说起了
广播(Broadcast)
广播(Broadcast)是 numpy 对不同形状(shape)的数组进行数值计算的方式, 对数组的算术运算通常在相应的元素上进行。
最简单的例子如下:
a = np.array([[ 0, 0, 0],
[10,10,10],
[20,20,20],
[30,30,30]])
b = np.array([0,1,2])
print(a + b)
[[ 0 1 2]
[10 11 12]
[20 21 22]
[30 31 32]]
下面的图片展示了数组 b 如何通过广播来与数组 a 兼容。 感谢菜鸟教程
广播的规则:
- 让所有输入数组都向其中形状最长的数组看齐,形状中不足的部分都通过在前面加 1 补齐。
- 输出数组的形状是输入数组形状的各个维度上的最大值。
- 如果输入数组的某个维度和输出数组的对应维度的长度相同或者其长度为 1 时,这个数组能够用来计算,否则出错。
- 当输入数组的某个维度的长度为 1 时,沿着此维度运算时都用此维度上的第一组值。
简单理解:对两个数组,分别比较他们的每一个维度(若其中一个数组没有当前维度则忽略),满足:
- 数组拥有相同形状。
- 当前维度的值相等。
- 当前维度的值有一个是 1。
若条件不满足,抛出 "ValueError: frames are not aligned" 异常。
知道这些之后,我们来看看
数组比较
1.数组与数字进行比较
这个比较容易理解,就是数据比较之后会产生boolean值,感谢华章科技
matrix = np.array([
[5, 10, 15],
[20, 25, 30],
[35, 40, 45]
])
m = (matrix == 25)
print(m)
[[False False False]
[False True False]
[False False False]]
2.数组与数组进行比较
这个就要注意 如果输入数组的某个维度和输出数组的对应维度的长度相同或者其长度为 1 时,这个数组能够用来计算,否则出错。这句话了
- 正例1,一维数组和一维数组之间比较,一定要长度相同
a = np.linspace(0,10,3)
d = np.linspace(2,4,3)
print(a)
print(d)
e = a > d
print(e)
[ 0. 5. 10.]
[2. 3. 4.]
[False True True]
- 正例2,二维数组和一维数组之间比较,相同维度长度要相同或者为1
a = np.linspace(0,10,5)
d = np.array([[5],[4]])
print(a)
print(d)
e = a > d
print(e)
[ 0. 2.5 5. 7.5 10. ]
[[5]
[4]]
[[False False False True True]
[False False True True True]]
注意这里 当输入数组的某个维度的长度为 1 时,沿着此维度运算时都用此维度上的第一组值
实际上简单理解就是通过广播,会扩展长度为1的维度。
这也是我们之前案例中结果的由来
但是需要注意反例,即当相同维度上的长度不相同且不为1时,就会出现问题
- 反例1
a = np.linspace(0,10,5)
d = np.array([[5,6],[4]])
print(a)
print(d)
e = a > d
print(e)
D:/pythonProject/MultinomialLogisticRegression/logistic_regression/tmp_unique.py:80:
VisibleDeprecationWarning: Creating an ndarray from ragged nested sequences
(which is a list-or-tuple of lists-or-tuples-or ndarrays with different lengths or shapes) is deprecated.
If you meant to do this, you must specify 'dtype=object' when creating the ndarray.
d = np.array([[5,6],[4]])
Traceback (most recent call last):
File "D:/pythonProject/MultinomialLogisticRegression/logistic_regression/tmp_unique.py", line 83, in <module>
e = a > d
ValueError: operands could not be broadcast together with shapes (5,) (2,)
[ 0. 2.5 5. 7.5 10. ]
[list([5, 6]) list([4])]
这里的错误就是在于相同维度,不同长度(5,)->[ 0. 2.5 5. 7.5 10. ]与 (2,)->[5,6]进行了比较。