数据分析(一)--numpy入门

本文介绍了数据分析基础工具NumPy,详细讲解了如何从Python列表创建数组、数组的基本操作,包括属性、索引、切分、变形以及拼接和分裂。重点阐述了数组的创建、属性、索引方式以及在多维数据中的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Numpy入门

写在开始前,本系列将使用jupyter notebook作为工具,如果你是windows系统,为了方便请下载Anaconda3-5.1.0-Windows-x86_64,这集成了所有你可以用到或者用不到的各种工具。如果你是mac或者linux系统,可以下载Anaconda3-5.1.0的对应版本。

在计算机中,可以将图像(尤其是数字图像)简单地看作二维数字数组,这些数字数组代表各区域的像素值;声音片段可以看作时间和强度的一维数组;文本也可以通过各种方式转换成数值表示,一种可能的转换是用二进制数表示特定单词或单词对出现的频率。

不管数据是何种形式,第一步都是将这些数据转换成数值数组形式的可分析数据,正因如此,有效地存储和操作数值数组是数据科学中绝对的基础过程。 Python中专门用来处理这些数值数组的工具: NumPy 包和 Pandas 包,首先来介绍NumPy包。

一、NumPy数组

Python 中的数据操作几乎等同于 NumPy 数组操作,甚至新出现的 Pandas 工具也是构建在 NumPy 数组的基础之上的,因此这是最重要的也是要理解的。

1.1 从Python列表创建数组

首先,可以用 np.array 从 Python 列表创建数组:不同于 Python 列表, NumPy 要求数组必须包含同一类型的数据。如果类型不匹配, NumPy 将会向上转换(如果可行),优先级:str>float>int 。

In[1]:  import numpy as np

In[2]:  # 整型数组:
        np.array([1, 4, 2, 5, 3])

Out[2]: array([1, 4, 2, 5, 3])

如果希望明确设置数组的数据类型,可以用 dtype 关键字:

In[3]:  np.array([1, 2, 3, 4], dtype='float32')

Out[3]: array([ 1., 2., 3., 4.], dtype=float32)

最后,不同于 Python 列表, NumPy 数组可以被指定为多维的。以下是用列表的列表初始化多维数组的一种方法:

In[11]: # 嵌套列表构成的多维数组
        np.array([range(i, i + 3) for i in [2, 4, 6]])

Out[11]: array([[2, 3, 4],[4, 5, 6],[6, 7, 8]]

内层的列表被当作二维数组的行。

1.2 从头创建数组

面对大型数组的时候,用 NumPy 内置的方法从头创建数组是一种更高效的方法。以下是几个示例:

In[12]: # 创建一个长度为10的数组,数组的值都是0
        np.zeros(10, dtype=int)
Out[12]: array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0])

In[13]: # 创建一个3×5的浮点型数组,数组的值都是1
        np.ones((3, 5), dtype=float)
Out[13]: array([[ 1., 1., 1., 1., 1.],[ 1., 1., 1., 1., 1.],[ 1., 1., 1., 1., 1.]])

In[14]: # 创建一个3×5的浮点型数组,数组的值都是3.14
        np.full((3, 5), 3.14)
Out[14]: array([[ 3.14, 3.14, 3.14, 3.14, 3.14],[ 3.14, 3.14, 3.14, 3.14, 3.14],[ 3.14, 3.14, 3.14, 3.14, 3.14]])

1.3 NumPy数组基础

1.3.1 数组的属性

确定数组的大小、形状、存储大小、数据类型。

每个数组有 nidm(数组的维度)、 shape(数组每个维度的大小)和 size(数组的总大小)属性:

In[1]:  x3 = np.random.randint(10, size=(3, 4, 5)) # 三维数组
In[2]:  print("x3 ndim: ", x3.ndim)
        print("x3 shape:", x3.shape)
        print("x3 size: ", x3.size)
x3 ndim: 3
x3 shape: (3, 4, 5)
x3 size: 60

另外一个有用的属性是 dtype,它是数组的数据类型:

In[3]: print("dtype:", x3.dtype)
dtype: int32

其他的属性包括表示每个数组元素字节大小的 itemsize,以及表示数组总字节大小的属性nbytes:

In[4]:  print("itemsize:", x3.itemsize, "bytes")
        print("nbytes:", x3.nbytes, "bytes")
itemsize: 4 bytes
nbytes: 240 bytes

一般来说,可以认为 nbytes 跟 itemsize 和 size 的乘积大小相等。

1.3.2 数组的索引

获取和设置数组各个元素的值。

如果你熟悉 Python 的标准列表索引,那么你对 NumPy 的索引方式也不会陌生。和 Python列表一样,在一维数组中,你也可以通过中括号指定索引获取第 i 个值(从 0 开始计数):

x1 = np.random.randint(10, size=6)

In[5]: x1
Out[5]: array([5, 0, 3, 3, 7, 9])

In[6]: x1[0]
Out[6]: 5

为了获取数组的末尾索引,可以用负值索引:

In[8]: x1[-1]
Out[8]: 9

In[9]: x1[-2]
Out[9]: 7

在多维数组中,可以用逗号分隔的索引元组获取元素:

x2 = np.random.randint(10, size=(3, 4)) # 二维数组
In[10]: x2
Out[10]: array([[3, 5, 2, 4],[7, 6, 8, 8],[1, 6, 7, 7]])

In[11]: x2[0, 0]
Out[11]: 3

In[12]: x2[2, 0]
Out[12]: 1

In[13]: x2[2, -1]
Out[13]: 7

也可以用以上索引方式修改元素值,和 Python 列表不同, NumPy 数组是固定类型的。这意味着当你试图将一个浮点值插入一个整型数组时,浮点值会被截短成整型。并且这种截短是自动完成的,不会给你提示或警告,所以需要特别注意这一点!

In[15]: x1[0] = 3.14159 # 这将被截短
        x1

Out[15]: array([3, 0, 3, 3, 7, 9])
1.3.3 数组的切分: 获取子数组

在大的数组中获取或设置更小的子数组。

NumPy 切片语法和 Python 列表的标准切片语法相同。为了获取数组 x 的一个切片,可以用以下方式:
x[start:stop:step]

一维子数组:

In[16]: x = np.arange(10)
        x
Out[16]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

In[17]: x[:5] # 前五个元素
Out[17]: array([0, 1, 2, 3, 4])

In[18]: x[5:] # 索引五之后的元素
Out[18]: array([5, 6, 7, 8, 9])

In[19]: x[4:7] # 中间的子数组
Out[19]: array([4, 5, 6])

In[20]: x[::2] # 每隔一个元素 
Out[20]: array([0, 2, 4, 6, 8])

In[21]: x[1::2] # 每隔一个元素,从索引1开始
Out[21]: array([1, 3, 5, 7, 9])

多维子数组:多维切片也采用同样的方式处理,用冒号分隔。

In[24]: x2
Out[24]: array([[12, 5, 2, 4],[ 7, 6, 8, 8],[ 1, 6, 7, 7]])

In[25]: x2[:2, :3] # 两行,三列
Out[25]: array([[12, 5, 2],[ 7, 6, 8]])

In[26]: x2[:3, ::2] # 所有行,每隔一列
Out[26]: array([[12, 2],[ 7, 8],[ 1, 7]])


In[27]: x2[::-1, ::-1]  # 子数组维度也可以同时被逆序
Out[27]: array([[ 7, 7, 6, 1],[ 8, 8, 6, 7],[ 4, 2, 5, 12]])

获取数组的行和列:一种常见的需求是获取数组的单行和单列。你可以将索引与切片组合起来实现这个功能,用一个冒号(:)表示空切片:

In[28]: print(x2[:, 0]) # x2的第一列
[12 7 1]

In[29]: print(x2[0, :]) # x2的第一行
[12 5 2 4]


In[30]: print(x2[0])   # 等于x2[0, :]
[12 5 2 4]

关于数组切片有一点很重要也非常有用,那就是数组切片返回的是数组数据的视图,而不是数值数据的副本。这一点也是 NumPy 数组切片和 Python 列表切片的不同之处:在Python 列表中,切片是值的副本。

它意味着在处理非常大的数据集时,可以获取或处理这些数据集的片段,而不用复制底层的数据缓存。如果需要创建数组的副本,可以使用copy(),如果修改这个子数组,原始的数组不会被改变。

1.3.4 数组的变形

改变给定数组的形状。

数组变形最灵活的实现方式是通过 reshape() 函数来实现。

In[38]: grid = np.arange(1, 10).reshape((3, 3))
        print(grid)

[[1 2 3]
[4 5 6]
[7 8 9]]

原始数组的大小必须和变形后数组的大小一致。你也可以在切片操作中使用 newaxis 关键字。

In[39]: x = np.array([1, 2, 3])# 通过变形获得的行向量
        x.reshape((1, 3))
Out[39]: array([[1, 2, 3]])

In[40]: # 通过newaxis获得的行向量
        x[np.newaxis, :]
Out[40]: array([[1, 2, 3]])
1.3.5 数组的拼接和分裂

以上所有的操作都是针对单一数组的,但有时也需要将多个数组合并为一个,或将一个数组分裂成多个。

数组的拼接

拼接或连接 NumPy 中的两个数组主要由 np.concatenate、 np.vstack 和 np.hstack 例程实现。 np.concatenate 将数组元组或数组列表作为第一个参数,如下所示:

In[43]: x = np.array([1, 2, 3])
        y = np.array([3, 2, 1])
        np.concatenate([x, y])

Out[43]: array([1, 2, 3, 3, 2, 1])

也可以一次性拼接两个以上数组:

In[44]: z = [99, 99, 99]
        print(np.concatenate([x, y, z]))

[ 1 2 3 3 2 1 99 99 99]     

np.concatenate 也可以用于二维数组的拼接:

In[45]: grid = np.array([[1, 2, 3],[4, 5, 6]])

In[46]: # 沿着第一个轴拼接
        np.concatenate([grid, grid])
Out[46]: array([[1, 2, 3],[4, 5, 6],[1, 2, 3],[4, 5, 6]])

In[47]: # 沿着第二个轴拼接(从0开始索引)
        np.concatenate([grid, grid], axis=1)
Out[47]: array([[1, 2, 3, 1, 2, 3],[4, 5, 6, 4, 5, 6]])

沿着固定维度处理数组时,使用 np.vstack(垂直栈)和 np.hstack(水平栈)函数会更简洁:

In[48]: x = np.array([1, 2, 3])
        grid = np.array([[9, 8, 7],[6, 5, 4]])
        # 垂直栈数组
        np.vstack([x, grid])

Out[48]: array([[1, 2, 3],[9, 8, 7],[6, 5, 4]])

In[49]: # 水平栈数组
        y = np.array([[99],[99]])
        np.hstack([grid, y])

Out[49]: array([[ 9, 8, 7, 99],[ 6, 5, 4, 99]])     

与之类似, np.dstack 将沿着第三个维度拼接数组。

数组的分裂

与拼接相反的过程是分裂。分裂可以通过 np.split、 np.hsplit 和 np.vsplit 函数来实现。可以向以上函数传递一个索引列表作为参数,索引列表记录的是分裂点位置:

In[50]: x = [1, 2, 3, 99, 99, 3, 2, 1]
        x1, x2, x3 = np.split(x, [3, 5])
        print(x1, x2, x3)

[1 2 3] [99 99] [3 2 1]

值得注意的是, N 分裂点会得到 N + 1 个子数组。相关的 np.hsplit 和 np.vsplit 的用法也类似:

In[51]: grid = np.arange(16).reshape((4, 4))
        grid
Out[51]: array([[ 0, 1, 2, 3],[ 4, 5, 6, 7],[ 8, 9, 10, 11],[12, 13, 14, 15]])

In[52]: upper, lower = np.vsplit(grid, [2])
        print(upper)
        print(lower)
[[0 1 2 3]
[4 5 6 7]]
[[ 8 9 10 11]
[12 13 14 15]]

In[53]: left, right = np.hsplit(grid, [2])
        print(left)
        print(right)
[[ 0 1]
[ 4 5]
[ 8 9]
[12 13]]
[[ 2 3]
[ 6 7]
[10 11]
[14 15]]

同样, np.dsplit 将数组沿着第三个维度分裂。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值