深度学习 实验二 pytorch的基本使用

一、认识张量与算子

1.张量

张量是由以下三个关键属性来定义的。
轴的个数(阶)。例如,3D 张量有 3 个轴,矩阵有 2 个轴。这在 Numpy 等 Python 库中也叫张量的 ndim 。
形状。这是一个整数元组,表示张量沿每个轴的维度大小(元素个数)。例如,前面矩阵示例的形状为 (3, 5) ,3D 张量示例的形状为 (3, 3, 5) 。向量的形状只包含一个元素,比如 (5,) ,而标量的形状为空,即 () 。(张量的形状)
数据类型(在 Python 库中通常叫作 dtype )。这是张量中所包含数据的类型,例如,张量的类型可以是 float32 、 uint8 、 float64 等。在极少数情况下,你可能会遇到字符( char )张量。注意:Numpy(以及大多数其他库)中不存在字符串张量,因为张量存储在预先分配的连续内存段中,而字符串的长度是可变的,无法用这种方式存储。

2. 算子

算子(Operator):构建神经网络模型的基础组件。
在深度学习框架中,数据经常用张量(Tensor)的形式来存储。张量是矩阵的扩展与延伸,可以认为是高阶的矩阵。1阶张量为向量,2阶张量为矩阵。如果你对Numpy熟悉,那么张量是类似于Numpy的多维数组(ndarray)的概念,可以具有任意多的维度。
张量中元素的类型可以是布尔型数据、整数、浮点数或者复数,但同一张量中所有元素的数据类型均相同。因此我们可以给张量定义一个数据类型(dtype)来表示其元素的类型。

3. 差别

向量数据:2D 张量,形状为 (samples, features) 。
时间序列数据或序列数据:3D 张量,形状为 (samples, timesteps, features) 。
图像:4D张量,形状为 (samples, height, width, channels) 或 (samples, channels,
height, width) 。
视频:5D张量,形状为 (samples, frames, height, width, channels) 或 (samples,frames, channels, height, width) 。
函数属于泛函,泛函和变换都属于算子,算子属于映射

4. 理解

  1. 张量是矩阵的扩展与延伸。
  2. 算子是构建复杂机器学习模型的基础组件,是深度学习算法的基本单元

二、torch的基本使用

1. 创建张量

# 首先导入包
import torch
1.1 指定数据创建张量

1. 通过指定的Python列表数据[2.0, 3.0, 4.0],创建一个一维张量

t = torch.tensor([1.0,2.1,3.2])
print(t) # tensor([1.0000, 2.1000, 3.2000])

2. 通过指定的Python列表数据来创建类似矩阵(matrix)的二维张量。

t = torch.tensor([[1.0, 2.0, 3.0],
                  [4.0, 5.0, 6.0]])
print(t) # tensor([[1., 2., 3.],[4., 5., 6.]])

3. 同样地,还可以创建维度为3、4…N等更复杂的多维张量。

t = torch.tensor([[[1, 2, 3, 4, 5],
                    [6, 7, 8, 9, 10]],
                    [[11, 12, 13, 14, 15],
                    [16, 17, 18, 19, 20]]])
print(t) 

运行结果:

tensor([[[ 1,  2,  3,  4,  5],
         [ 6,  7,  8,  9, 10]],

        [[11, 12, 13, 14, 15],
         [16, 17, 18, 19, 20]]])

需要注意的是,张量在任何一个维度上的元素数量必须相等,否则会报错。

1.2 指定形状创建

如果要创建一个指定形状、元素数据相同的张量,可以使用torch.zeros、torch.ones、torch.full等API。

m, n = 2, 3

1. 使用torch.zeros创建数据全为0,形状为[m, n]的Tensor

zeros_Tensor = torch.zeros([m, n])

2. 使用torch.ones创建数据全为1,形状为[m, n]的Tensor

ones_Tensor = torch.ones([m, n])

3. 使用torch.full创建数据全为指定值,形状为[m, n]的Tensor,这里我们指定数据为10

full_Tensor = torch.full([m, n], 10)

输出一下:

print('zeros Tensor: ', zeros_Tensor) 
print('ones Tensor: ', ones_Tensor) 
print('full Tensor: ', full_Tensor)

运行结果:

zeros Tensor:  tensor([[0., 0., 0.],
        [0., 0., 0.]])
ones Tensor:  tensor([[1., 1., 1.],
        [1., 1., 1.]])
full Tensor:  tensor([[10, 10, 10],
        [10, 10, 10]])
1.3 指定区间创建

如果要在指定区间内创建张量,可以使用torch.arange、torch.linspace等API。
1. 使用torch.arange创建以步长step均匀分隔数值区间[start, end)的一维Tensor

# arange_Tensor = torch.arange(start=1, end=5, step=1)
arange_Tensor = torch.arange(5,10,1) # (开始,结束,间隔),是一个左闭右开区间

2. 使用torch.linspace创建以元素个数num均匀分隔数值区间[start, stop]的Tensor

linspace_Tensor = torch.linspace(3,10,5,dtype=torch.int) # (开始,结束,个数,类型)

输出:

print('arange Tensor: ', arange_Tensor)
print('linspace Tensor: ', linspace_Tensor) 

运行结果:

arange Tensor:  tensor([5, 6, 7, 8, 9])
linspace Tensor:  tensor([ 3,  4,  6,  8, 10], dtype=torch.int32)

2. 张量的属性

2.1 张量的形状

张量具有如下形状属性:

  1. Tensor.ndim:张量的维度,例如向量的维度为1,矩阵的维度为2。
  2. Tensor.shape: 张量每个维度上元素的数量。
  3. Tensor.shape[n]:张量第nnn维的大小。第nnn维也称为轴(axis)。
  4. Tensor.size:张量中全部元素的个数。

创建一个四维张量,并打印出shape、ndim、shape[n]、size属性。

ndim_4_Tensor = torch.ones([2, 3, 4, 5])

print("Number of dimensions:", ndim_4_Tensor.ndim)
print("Shape of Tensor:", ndim_4_Tensor.shape)
print("Elements number along axis 0 of Tensor:", ndim_4_Tensor.shape[0])
print("Elements number along the last axis of Tensor:", ndim_4_Tensor.shape[-1])
print('Number of elements in Tensor: ', ndim_4_Tensor.size) # 表示数据真实大小
print('Number of elements in Tensor: ', ndim_4_Tensor.numel()) # 表示元素个数

运行结果:

Number of dimensions: 4
Shape of Tensor: torch.Size([2, 3, 4, 5])
Elements number along axis 0 of Tensor: 2
Elements number along the last axis of Tensor: 5
Number of elements in Tensor:  <built-in method size of Tensor object at 0x0000018DD8987AE0>
Number of elements in Tensor:  120
2.2 形状的改变

除了查看张量的形状外,重新设置张量的在实际编程中也具有重要意义,torch.reshape改变张量的形状。
1. 定义一个shape为[3,2,5]的三维Tensor

ndim_3_Tensor = torch.tensor([[[1, 2, 3, 4, 5],
                                   [6, 7, 8, 9, 10]],
                                  [[11, 12, 13, 14, 15],
                                   [16, 17, 18, 19, 20]],
                                  [[21, 22, 23, 24, 25],
                                   [26, 27, 28, 29, 30]]])
print("the shape of ndim_3_Tensor:", ndim_3_Tensor.shape) 

运行结果:

 the shape of ndim_3_Tensor: torch.Size([3, 2, 5])

2. torch.reshape 可以保持在输入数据不变的情况下,改变数据形状。这里我们设置reshape为[2,5,3]

reshape_Tensor = torch.reshape(ndim_3_Tensor, [2, 5, 3])
print("After reshape:", reshape_Tensor)

运行结果:

After reshape: tensor([[[ 1,  2,  3],
         [ 4,  5,  6],
         [ 7,  8,  9],
         [10, 11, 12],
         [13, 14, 15]],

        [[16, 17, 18],
         [19, 20, 21],
         [22, 23, 24],
         [25, 26, 27],
         [28, 29, 30]]])

将张量从[3, 2, 5]的形状reshape为[2, 5, 3]的形状时,张量内的数据不会发生改变,元素顺序也没有发生改变,只有数据形状发生了改变。

使用reshape时存在一些技巧,比如:

  1. -1表示这个维度的值是从张量的元素总数和剩余维度推断出来的。因此,有且只有一个维度可以被设置为-1。
  2. 0表示实际的维数是从张量的对应维数中复制出来的,因此shape中0所对应的索引值不能超过张量的总维度。
new_Tensor1 = ndim_3_Tensor.reshape([-1])
print('new Tensor 1 shape: ', new_Tensor1.shape)

运行结果:

new Tensor 1 shape:  torch.Size([30])

5. 还可以通过torch.unsqueeze将张量中的一个或多个维度中插入尺寸为1的维度。

ones_Tensor = torch.ones([5,6], dtype=torch.int)
new_Tensor1 = torch.unsqueeze(ones_Tensor, 0)
print('ones Tensor shape: ', ones_Tensor.shape)
print(ones_Tensor )
print('new Tensor 1 shape: ', new_Tensor1.shape)
print(new_Tensor1)

运行结果:

ones Tensor shape:  torch.Size([5, 6])
tensor([[1, 1, 1, 1, 1, 1],
        [1, 1, 1, 1, 1, 1],
        [1, 1, 1, 1, 1, 1],
        [1, 1, 1, 1, 1, 1],
        [1, 1, 1, 1, 1, 1]], dtype=torch.int32)
new Tensor 1 shape:  torch.Size([1, 5, 6])
tensor([[[1, 1, 1, 1, 1, 1],
         [1, 1, 1, 1, 1, 1],
         [1, 1, 1, 1, 1, 1],
         [1, 1, 1, 1, 1, 1],
         [1, 1, 1, 1, 1, 1]]], dtype=torch.int32)
2.3 张量的数据类型

可以通过Tensor.dtype来查看张量的数据类型,
类型支持bool、float16、float32、float64、uint8、int8、int16、int32、int64和复数类型数据。

  1. 通过Python元素创建的张量,可以通过dtype来指定数据类型,如果未指定:
    对于Python整型数据,则会创建int64型张量。
    对于Python浮点型数据,默认会创建float32型张量。
  2. 通过Numpy数组创建的张量,则与其原来的数据类型保持相同。通过torch.tensor()函数可以将Numpy数组转化为张量。
    1. 使用torch.tensor通过已知数据来创建一个Tensor
print(torch.tensor(1).dtype)
print(torch.tensor(1.0).dtype)

运行结果:

torch.int64
torch.float32

2. 定义dtype为float32的Tensor

float32_Tensor = torch.tensor(1.0)

3. Tensor后加.to()可以将输入数据的数据类型转换为指定的dtype并输出,也可以是.long(), .int(), .float(), .double()等

int64_Tensor = float32_Tensor.to(dtype=torch.int64) # 可以这样用
print(int64_Tensor.dtype) 

运行结果:

torch.int64
2.4 张量的设备位置

初始化张量时可以通过place来指定其分配的设备位置,可支持的设备位置有三种:CPU、GPU和固定内存。固定内存也称为不可分页内存或锁页内存,它与GPU之间具有更高的读写效率,并且支持异步传输,这对网络整体性能会有进一步提升,但它的缺点是分配空间过多时可能会降低主机系统的性能,因为它减少了用于存储虚拟内存数据的可分页内存。当未指定设备位置时,张量默认设备位置和安装的pytorch版本一致,如安装了GPU版本的pytorch,则设备位置默认为GPU。
如下代码分别创建了CPU、GPU和固定内存上的张量,并通过Tensor.device查看张量所在的设备位置。
1. 创建CPU上的Tensor

cpu_Tensor = torch.tensor(1, device=torch.device('cpu'))

2. 通过Tensor.device查看张量所在设备位置

print('cpu Tensor: ', cpu_Tensor.device)

运行结果:

cpu Tensor:  cpu

3. 张量与Numpy数组转换

将Numpy数组转化为张量,也可以通过Tensor.numpy()函数将张量转化为Numpy数组。

ndim_1_Tensor = torch.tensor([1., 2.])
# 将当前 Tensor 转化为 numpy.ndarray
print('Tensor to convert: ', ndim_1_Tensor.numpy())

运行结果:

Tensor to convert:  [1. 2.]

4. 张量的访问

4.1 索引和切片

我们可以通过索引或切片方便地访问或修改张量,具有以下特点:

  • 基于0−n的下标进行索引,如果下标为负数,则从尾部开始计算。
  • 通过冒号“:”分隔切片参数start:stop:step来进行切片操作,也就是访问start到stop范围内的部分元素并生成一个新的序列。其中start为切片的起始位置,stop为切片的截止位置,step是切片的步长,这三个参数均可缺省。
4.2 访问张量

针对一维张量,对单个轴进行索引和切片。

ndim_1_Tensor = torch.tensor([0, 1, 2, 3, 4, 5, 6, 7, 8])

print("Origin Tensor:", ndim_1_Tensor) # 所有元素
print("First element:", ndim_1_Tensor[0]) # 第一个
print("Last element:", ndim_1_Tensor[-1]) # 最后一个
print("All element:", ndim_1_Tensor[:]) # 所有
print("Before 3:", ndim_1_Tensor[:3]) # 前三个
print("Interval of 3:", ndim_1_Tensor[::3]) # 步长为3
# print("Reverse:", ndim_1_Tensor[::-1]) # 报错:ValueError: step must be greater than zero

运行结果:

Origin Tensor: tensor([0, 1, 2, 3, 4, 5, 6, 7, 8])
First element: tensor(0)
Last element: tensor(8)
All element: tensor([0, 1, 2, 3, 4, 5, 6, 7, 8])
Before 3: tensor([0, 1, 2])
Interval of 3: tensor([0, 3, 6])

(注:Pytorch不支持负数步长)

针对二维及以上维度的张量,在多个维度上进行索引或切片。
索引或切片的第一个值对应第0维,第二个值对应第1维,
以此类推,如果某个维度上未指定索引,则默认为“:”。

ndim_2_Tensor = torch.tensor([[0, 1, 2, 3],
                                  [4, 5, 6, 7],
                                  [8, 9, 10, 11]]) # 先创建一个torch
print("Origin Tensor:", ndim_2_Tensor) # 所有
print("First row:", ndim_2_Tensor[0]) # 第一个
print("First row:", ndim_2_Tensor[0, :]) # 第一个的所有
print("First column:", ndim_2_Tensor[:, 0]) # 第一列
print("Last column:", ndim_2_Tensor[:, -1]) # 最后一列
print("All element:", ndim_2_Tensor[:]) # 所有
print("First row and second column:", ndim_2_Tensor[0, 1]) # 第一行的第二列的元素

运行结果:

Origin Tensor: tensor([[ 0,  1,  2,  3],
        [ 4,  5,  6,  7],
        [ 8,  9, 10, 11]])
First row: tensor([0, 1, 2, 3])
First row: tensor([0, 1, 2, 3])
First column: tensor([0, 4, 8])
Last column: tensor([ 3,  7, 11])
All element: tensor([[ 0,  1,  2,  3],
        [ 4,  5,  6,  7],
        [ 8,  9, 10, 11]])
First row and second column: tensor(1)
4.3 修改张量

提醒

  • 慎重通过索引或切片操作来修改张量,此操作仅会原地修改该张量的数值,且原值不会被保存。
  • 如果被修改的张量参与梯度计算,将仅会使用修改后的数值,这可能会给梯度计算引入风险。
# 定义1个二维Tensor
ndim_2_Tensor = torch.ones([2, 3], dtype=torch.float32)
print('Origin Tensor: ', ndim_2_Tensor)
# 修改第1维为0
ndim_2_Tensor[0] = 0
print('change Tensor: ', ndim_2_Tensor)
# 修改第1维为2.1
ndim_2_Tensor[0:1] = 2.1
print('change Tensor: ', ndim_2_Tensor)
# 修改全部Tensor
ndim_2_Tensor[...] = 3
print('change Tensor: ', ndim_2_Tensor)
Origin Tensor:  tensor([[1., 1., 1.],
        [1., 1., 1.]])
change Tensor:  tensor([[0., 0., 0.],
        [1., 1., 1.]])
change Tensor:  tensor([[2.1000, 2.1000, 2.1000],
        [1.0000, 1.0000, 1.0000]])
change Tensor:  tensor([[3., 3., 3.],
        [3., 3., 3.]])

5. 张量的运算

张量支持包括基础数学运算、逻辑运算、矩阵运算等100余种运算操作,以加法为例,有如下两种实现方式:

  • torch.add(x,y)。
  • 使用张量类成员函数x.add(y)。
# 定义两个Tensor
x = torch.tensor([[1.1, 2.2], [3.3, 4.4]], dtype=torch.float64)
y = torch.tensor([[5.5, 6.6], [7.7, 8.8]], dtype=torch.float64)
# 第一种调用方法,paddle.add逐元素相加算子,并将各个位置的输出元素保存到返回结果中
print('Method 1: ', torch.add(x, y))
# 第二种调用方法
print('Method 2: ', x.add(y))

运行结果:

Method 1:  tensor([[ 6.6000,  8.8000],
        [11.0000, 13.2000]], dtype=torch.float64)
Method 2:  tensor([[ 6.6000,  8.8000],
        [11.0000, 13.2000]], dtype=torch.float64)

笔记
由于张量类成员函数操作更为方便,以下均从张量类成员函数的角度,对常用张量操作进行介绍。

5.1 数学运算

张量类的基础数学函数如下:

x.abs()                       # 逐元素取绝对值
x.ceil()                      # 逐元素向上取整
x.floor()                     # 逐元素向下取整
x.round()                     # 逐元素四舍五入
x.exp()                       # 逐元素计算自然常数为底的指数
x.log()                       # 逐元素计算x的自然对数
x.reciprocal()                # 逐元素求倒数
x.square()                    # 逐元素计算平方
x.sqrt()                      # 逐元素计算平方根
x.sin()                       # 逐元素计算正弦
x.cos()                       # 逐元素计算余弦
x.add(y)                      # 逐元素加
x.subtract(y)                 # 逐元素减
x.multiply(y)                 # 逐元素乘(积)
x.divide(y)                   # 逐元素除
x.mod(y)                      # 逐元素除并取余
x.pow(y)                      # 逐元素幂
x.max()                       # 指定维度上元素最大值,默认为全部维度
x.min()                       # 指定维度上元素最小值,默认为全部维度
x.prod()                      # 指定维度上元素累乘,默认为全部维度
x.sum()                       # 指定维度上元素的和,默认为全部维度

同时,为了更方便地使用张量,飞桨对Python数学运算相关的魔法函数进行了重写,以下操作与上述结果相同。

x + y  -> x.add(y)            # 逐元素加
x - y  -> x.subtract(y)       # 逐元素减
x * y  -> x.multiply(y)       # 逐元素乘(积)
x / y  -> x.divide(y)         # 逐元素除
x % y  -> x.mod(y)            # 逐元素除并取余
x ** y -> x.pow(y)            # 逐元素幂
5.2 逻辑运算

张量类的逻辑运算函数如下:

x.isfinite()                  # 判断Tensor中元素是否是有限的数字,即不包括inf与nan
x.equal_all(y)                # 判断两个Tensor的全部元素是否相等,并返回形状为[1]的布尔类Tensor
x.equal(y)                    # 判断两个Tensor的每个元素是否相等,并返回形状相同的布尔类Tensor
x.not_equal(y)                # 判断两个Tensor的每个元素是否不相等
x.less_than(y)                # 判断Tensor x的元素是否小于Tensor y的对应元素
x.less_equal(y)               # 判断Tensor x的元素是否小于或等于Tensor y的对应元素
x.greater_than(y)             # 判断Tensor x的元素是否大于Tensor y的对应元素
x.greater_equal(y)            # 判断Tensor x的元素是否大于或等于Tensor y的对应元素
x.allclose(y)                 # 判断两个Tensor的全部元素是否接近
5.3 矩阵运算

张量类还包含了矩阵运算相关的函数,如矩阵的转置、范数计算和乘法等。

x.t()                         # 矩阵转置
x.transpose([1, 0])           # 交换第 0 维与第 1 维的顺序
x.norm('fro')                 # 矩阵的弗罗贝尼乌斯范数
x.dist(y, p=2)                # 矩阵(x-y)的2范数
x.matmul(y)                   # 矩阵乘法

有些矩阵运算中也支持大于两维的张量,比如matmul函数,对最后两个维度进行矩阵乘。
比如x是形状为[j,k,n,m]的张量,另一个y是[j,k,m,p]的张量,则x.matmul(y)输出的张量形状为[j,k,n,p]。

5.4 广播机制

pytorch的一些API在计算时支持广播(Broadcasting)机制,允许在一些运算时使用不同形状的张量。
通常来讲,如果有一个形状较小和一个形状较大的张量,会希望多次使用较小的张量来对较大的张量执行某些操作,看起来像是形状较小的张量首先被扩展到和较大的张量形状一致,然后再做运算。

飞桨的广播机制主要遵循如下规则(参考Numpy广播机制):

  1. 每个张量至少为一维张量。
  2. 从后往前比较张量的形状,当前维度的大小要么相等,要么其中一个等于1,要么其中一个不存在。当两个Tensor的形状一致时,可以广播
x = torch.ones((2, 3, 4))
y = torch.ones((2, 3, 4))
z = x + y
print('broadcasting with two same shape tensor: ', z.shape)

运行结果:

broadcasting with two same shape tensor:  torch.Size([2, 3, 4])
x = torch.ones((2, 3, 1, 5))
y = torch.ones((3, 4, 1))

从后往前依次比较:
第一次:y的维度大小是1
第二次:x的维度大小是1
第三次:x和y的维度大小相等,都为3
第四次:y的维度不存在
所以x和y是可以广播的

z = x + y
print('broadcasting with two different shape tensor:', z.shape)

运行结果:

broadcasting with two different shape tensor: torch.Size([2, 3, 4, 5])

从输出结果看,x与y在上述两种情况中均遵循广播规则,因此在张量相加时可以广播。

我们再定义两个shape分别为[2, 3, 4]和[2, 3, 6]的张量,观察这两个张量是否能够通过广播操作相加。

try:
    x = torch.ones((2, 3, 4))
    y = torch.ones((2, 3, 6))
    z = x + y
except:
    print("报错了") # 出现错误

从输出结果看,此时x和y是不能广播的,因为在第一次从后往前的比较中,4和6不相等,不符合广播规则。

广播机制的计算规则:
现在我们知道在什么情况下两个张量是可以广播的。两个张量进行广播后的结果张量的形状计算规则如下:

  1. 如果两个张量shape的长度不一致,那么需要在较小长度的shape前添加1,直到两个张量的形状长度相等。
  2. 保证两个张量形状相等之后,每个维度上的结果维度就是当前维度上较大的那个。

以张量x和y进行广播为例,x的shape为[2, 3, 1,5],张量y的shape为[3,4,1]。
首先张量y的形状长度较小,因此要将该张量形状补齐为[1, 3, 4, 1],再对两个张量的每一维进行比较。
从第一维看,x在一维上的大小为2,y为1,因此,结果张量在第一维的大小为2。
以此类推,对每一维进行比较,得到结果张量的形状为[2, 3, 4, 5]。

由于矩阵乘法函数torch.matmul在深度学习中使用非常多,这里需要特别说明一下它的广播规则:

  1. 如果两个张量均为一维,则获得点积结果。
  2. 如果两个张量都是二维的,则获得矩阵与矩阵的乘积。
  3. 如果张量x是一维,y是二维,则将x的shape转换为[1, D],与y进行矩阵相乘后再删除前置尺寸。
  4. 如果张量x是二维,y是一维,则获得矩阵与向量的乘积。
  5. 如果两个张量都是N维张量(N > 2),则根据广播规则广播非矩阵维度(除最后两个维度外其余维度)。
    比如:如果输入x是形状为[j,1,n,m]的张量,另一个y是[k,m,p]的张量,则输出张量的形状为[j,k,n,p]。
x = torch.ones([10, 1, 5, 2])
y = torch.ones([3, 2, 5])
z = torch.matmul(x, y) # 矩阵乘法
print('After matmul: ', z.shape)

运行结果:

After matmul:  torch.Size([10, 3, 5, 5])

从输出结果看,计算张量乘积时会使用到广播机制。

三. 使用pytorch实现数据预处理

1.1 读取数据集 house_tiny.csv

导入包,并读取数据

# 导入包
import pandas as pd
import torch
# 读取数据
data = pd.read_csv('house_tiny.csv')
print(data)

运行结果:

   NumRooms Alley   Price
0       NaN  Pave  127500
1       2.0   NaN  106000
2       4.0   NaN  178100
3       NaN   NaN  140000

1.2 处理缺失值

注意:

  • NaN项表示缺失值 典型方法是插值法和删除法,其中插值法用一个替代值弥补缺失值,而删除法则直接忽略缺失值。
  • 通过位置索引iloc,我们将data分成inputs和outputs, 其中前者为data的前两列,而后者为data的最后一列。 对于inputs中缺少的数值,我们用同一列的均值替换“NaN”项。
inputs,outputs = data.iloc[:,0:2],data.iloc[:,2] # 截取数据,左闭右开
print('inputs:\n',inputs)
print('outputs:\n',outputs)
inputs = inputs.fillna(inputs.mean())  # mean()用来求均值
print('inputs:\n',inputs)

运行结果:

inputs:
    NumRooms Alley
0       NaN  Pave
1       2.0   NaN
2       4.0   NaN
3       NaN   NaN
outputs:
 0    127500
1    106000
2    178100
3    140000
Name: Price, dtype: int64
inputs:
    NumRooms Alley
0       3.0  Pave
1       2.0   NaN
2       4.0   NaN
3       3.0   NaN

对于inputs中的类别值或离散值,我们将“NaN”视为一个类别。 由于“巷子类型”(“Alley”)列只接受两种类型的类别值“Pave”和“NaN”, pandas可以自动将此列转换为两列“Alley_Pave”和“Alley_nan”。 巷子类型为“Pave”的行会将“Alley_Pave”的值设置为1,“Alley_nan”的值设置为0。 缺少巷子类型的行会将“Alley_Pave”和“Alley_nan”分别设置为0和1。

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

1.3 转换为张量格式

现在inputs和outputs中的所有条目都是数值类型,它们可以转换为张量格式。
当数据采用张量格式后,可以通过在 2.1节中引入的那些张量函数来进一步操作。

X,y = torch.tensor(inputs.values),torch.tensor(outputs.values)
print(X)
print(y)

运行结果:

tensor([[3., 1., 0.],
        [2., 0., 1.],
        [4., 0., 1.],
        [3., 0., 1.]], dtype=torch.float64)
tensor([127500, 106000, 178100, 140000])

2.1 处理boston_house_prices.csv数据集

读取数据

import pandas as pd
import torch
data2 = pd.read_csv('boston_house_prices.csv')
print(data2)

运行结果:

        CRIM    ZN  INDUS  CHAS    NOX     RM   AGE     DIS  RAD  TAX  PTRATIO  LSTAT  MEDV
0    0.00632  18.0   2.31     0  0.538  6.575  65.2  4.0900    1  296     15.3   4.98  24.0
1    0.02731   0.0   7.07     0  0.469  6.421  78.9  4.9671    2  242     17.8   9.14  21.6
2    0.02729   0.0   7.07     0  0.469  7.185  61.1  4.9671    2  242     17.8   4.03  34.7
3    0.03237   0.0   2.18     0  0.458  6.998  45.8  6.0622    3  222     18.7   2.94  33.4
4    0.06905   0.0   2.18     0  0.458  7.147  54.2  6.0622    3  222     18.7   5.33  36.2
..       ...   ...    ...   ...    ...    ...   ...     ...  ...  ...      ...    ...   ...
501  0.06263   0.0  11.93     0  0.573  6.593  69.1  2.4786    1  273     21.0   9.67  22.4
502  0.04527   0.0  11.93     0  0.573  6.120  76.7  2.2875    1  273     21.0   9.08  20.6
503  0.06076   0.0  11.93     0  0.573  6.976  91.0  2.1675    1  273     21.0   5.64  23.9
504  0.10959   0.0  11.93     0  0.573  6.794  89.3  2.3889    1  273     21.0   6.48  22.0
505  0.04741   0.0  11.93     0  0.573  6.030  80.8  2.5050    1  273     21.0   7.88  11.9

[506 rows x 13 columns]

2.2 无缺失值

无缺失值,不做处理

2.3 转换为张量格式

inputs = pd.get_dummies(data2)
X = torch.tensor(inputs.values)
print(X)

运行结果:

tensor([[6.3200e-03, 1.8000e+01, 2.3100e+00,  ..., 1.5300e+01, 4.9800e+00,
         2.4000e+01],
        [2.7310e-02, 0.0000e+00, 7.0700e+00,  ..., 1.7800e+01, 9.1400e+00,
         2.1600e+01],
        [2.7290e-02, 0.0000e+00, 7.0700e+00,  ..., 1.7800e+01, 4.0300e+00,
         3.4700e+01],
        ...,
        [6.0760e-02, 0.0000e+00, 1.1930e+01,  ..., 2.1000e+01, 5.6400e+00,
         2.3900e+01],
        [1.0959e-01, 0.0000e+00, 1.1930e+01,  ..., 2.1000e+01, 6.4800e+00,
         2.2000e+01],
        [4.7410e-02, 0.0000e+00, 1.1930e+01,  ..., 2.1000e+01, 7.8800e+00,
         1.1900e+01]], dtype=torch.float64)

3.1 处理Iris.csv数据集

data3 = pd.read_csv('Iris.csv')

3.2 无缺失值

无缺失值,不做处理

3.3 转换为张量格式

inputs = pd.get_dummies(data3)
X = torch.tensor(inputs.values)
print(X)

运行结果:

tensor([[  1.0000,   5.1000,   3.5000,  ...,   1.0000,   0.0000,   0.0000],
        [  2.0000,   4.9000,   3.0000,  ...,   1.0000,   0.0000,   0.0000],
        [  3.0000,   4.7000,   3.2000,  ...,   1.0000,   0.0000,   0.0000],
        ...,
        [148.0000,   6.5000,   3.0000,  ...,   0.0000,   0.0000,   1.0000],
        [149.0000,   6.2000,   3.4000,  ...,   0.0000,   0.0000,   1.0000],
        [150.0000,   5.9000,   3.0000,  ...,   0.0000,   0.0000,   1.0000]],
       dtype=torch.float64)

四、这里加一些pandas的相关知识

1. 导入包

import pandas as pd

2. 创建一个数据,提取特征

data = pd.DataFrame({"学号":[1001,1002,1003,1004],
                    "性别":["男","女","女","男"],
                    "学历":["本科","硕士","专科","本科"]})
print(data)
print(pd.get_dummies(data)) # 特征提取
print(pd.get_dummies(data,prefix="A")) # 前缀全部改为A
print(pd.get_dummies(data,prefix=["A","B"],prefix_sep="+")) # 前缀改为A和B,"_"改为"+"

运行结果:

     学号 性别  学历
0  1001  男  本科
1  1002  女  硕士
2  1003  女  专科
3  1004  男  本科
     学号  性别_女  性别_男  学历_专科  学历_本科  学历_硕士
0  1001     0     1      0      1      0
1  1002     1     0      0      0      1
2  1003     1     0      1      0      0
3  1004     0     1      0      1      0
     学号  A_女  A_男  A_专科  A_本科  A_硕士
0  1001    0    1     0     1     0
1  1002    1    0     0     0     1
2  1003    1    0     1     0     0
3  1004    0    1     0     1     0
     学号  A+女  A+男  B+专科  B+本科  B+硕士
0  1001    0    1     0     1     0
1  1002    1    0     0     0     1
2  1003    1    0     1     0     0
3  1004    0    1     0     1     0
pandas.get_dummies(data, 
                   prefix=None, 
                   prefix_sep='_', 
                   dummy_na=False, 
                   columns=None, 
                   sparse=False, 
                   drop_first=False, 
                   dtype=None)
代码参数作用
prefixstr, list of str, 或 dict of str, 默认为 None用于追加DataFrame列名称的字符串。
prefix_sepstr, 默认为 ‘_’如果附加前缀,则使用分隔符/分隔符。或者像这样传递列表或字典prefix。
dummy_nabool, 默认为 False如果忽略False NaN。
columnslist-like, 默认为 None要编码的DataFrame中的列名。如果columns为None,则所有具有的列object或者categorydtype将被转换。
sparsebool, 默认为 Falsedummy-encoded列是否应由a支持SparseArray(True)或常规NumPy数组(False)。
drop_firstbool, 默认为 False是否通过删除第一个级别从k个分类级别中获取k-1个虚拟对象。

五、其他

1. 关于张量转numpy,numpy转张量

1.1 numpy转张量
import numpy as np
import torch
# 创建一个numpy
np_data = np.array([1,2,3,4])
np2torch = torch.from_numpy(np_data)
print("numpy数据转torch数据:", np2torch)

运行结果:

numpy数据转torch数据: tensor([1, 2, 3, 4], dtype=torch.int32)
1.2 张量转numpy
# 创建一个torch
torch_data = torch.tensor([1,2,3,4,5])
torch2np = torch_data.numpy()
print("torch数据转numpy数据:", torch2np)

运行结果:

torch数据转numpy数据: [1 2 3 4 5]

2. 求绝对值

import torch
import numpy as np

data = [-1,2,-3,4]
np_abs = np.abs(np.array(data))
print("numpy的abs:", np_abs)

torch_abs = torch.abs(torch.tensor(data))
print("torch的abs:", torch_abs)

运行结果:

numpy的abs: [1 2 3 4]
torch的abs: tensor([1, 2, 3, 4])

3. 抛出异常

如果try中代码报错,就输出except中的代码

try:
	可能异常代码
except:
	代码

这里补充一下上一篇的遗漏

第15题:利用13题目中的x,y 输出 x*y ,和 np.multiply(x, y) 还有 np.dot(x,y),比较差异。然后自己换一个不是方阵的试试。

x = np.array([[1, 2, 3], [3, 4, 5]], dtype=np.float64)
y = np.array([[5, 6, 7], [7, 8, 9]], dtype=np.float64)
print("x:",x)
print("y:",y)
print("x*y:",x*y) # 对应乘 
print("np.multiply(x,y):",np.multiply(x,y)) # 对应相乘
try:
    print("np.dot(x,y):",np.dot(x,y)) # 矩阵相乘
except:
    print("报错了!!!")

运行结果:

x: [[1. 2. 3.]
 [3. 4. 5.]]
y: [[5. 6. 7.]
 [7. 8. 9.]]
x*y: [[ 5. 12. 21.]
 [21. 32. 45.]]
np.multiply(x,y): [[ 5. 12. 21.]
 [21. 32. 45.]]
报错了!!!

np.dot(x,y) 报错了!!!
如果换一个

x = np.array([[1, 2, 3], [3, 4, 5]], dtype=np.float64)
y = np.array([[5, 6], [7, 8],[9,10]], dtype=np.float64)
print("x:",x)
print("y:",y)
try:
    print("np.dot(x,y):",np.dot(x,y)) # 矩阵相乘
except:
    print("报错了!!!")

运行结果:

x: [[1. 2. 3.]
 [3. 4. 5.]]
y: [[ 5.  6.]
 [ 7.  8.]
 [ 9. 10.]]
np.dot(x,y): [[ 46.  52.]
 [ 88. 100.]]

np.dot(x,y) 没有报错!(这里联系一下线性代数)


给个三连
点赞 + 收藏 + 关注!!!
如有错误与建议,望告知!!!(将于下篇文章更正)
请多多关注我!!!谢谢!!



上一篇:深度学习 实验一 numpy的使用

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值