利用pyton进行数据分析学习笔记(一):Numpy———ndarray

NumPy基础-数组和矢量计算

高效处理大量数据,速度是内置纯python的10到100倍
  • 使用连续的内存块存储数据,独立于其他python内置对象
  • Numpy中C语言编写的算法库可以操作内存,而不必进行类型检查或其他前期的工作
  • 占用的内存更少
  • 可以在整个数组上执行复杂的计算,而不需要python的for循环、列表推导式等
 import numpy as np

my_arr = np.arange(1000000)

my_list = list(range(1000000))
%time for _ in range(10): my_arr2 = my_arr * 2
%time for _ in range(10): my_list2 = [x * 2 for x in my_list]
Wall time: 27.9 ms
Wall time: 1.15 s

ndarray
  • 一种多维数组对象
  • 个人理解:可以直接对数据块进行数据运算,而不需要在for循环中写
  • list、tuple等与数字相乘是将元素的数量复制
  • 同构数据多维容器,内部元素数据类型必须一致
ll = list(range(1,11))
data = np.random.randn(2,3)
print(data)
# 列表元素复制3倍
print(ll * 3)
# ndarray内元素乘3
#乘法
print(data * 3)
# 加法
print(data + data)

#各维度大小
print(data.shape)

#数组类型
print(data.dtype)

#数组维度
print(data.ndim)
[[-0.45664989  0.24770378  0.29387936]
 [-1.04888287  0.21683247 -1.30767515]]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
[[-1.36994967  0.74311134  0.88163809]
 [-3.1466486   0.65049741 -3.92302545]]
[[-0.91329978  0.49540756  0.58775872]
 [-2.09776573  0.43366494 -2.6153503 ]]
(2, 3)
float64
2

要注意使用 import numpy as np,而不是使用from numpy import ,因为numpy中很多函数和方法,且有一些与python内置函数重名


创建ndarray
  • array方法创建,接受一切序列型的对象,包括其他数组
  • zeros、ones分别可以创建指定长度或形状全0或全1数组,empty可以创建一个没有任何具体值的数组
  • 通过arange方法创建方法创建
data1 = [1,2,3,4,5,6]
# 接受列表
arr = np.array(data1)
arr.shape
arr.ndim
arr
array([1, 2, 3, 4, 5, 6])
data2 = [[1,2,3],[4,5,6]]
# 接受嵌套序列
arr2 = np.array(data2)
arr2.shape
arr2.ndim
2
# 创建ndarray的方法
np.zeros(10)
np.ones((2,4))
np.empty((2,3,2))
np.arange(10)
np.arrange(0,10,0.1) # 起始 终点 步长
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

ndarray数据类型
  • 可以在创建时指定dtype,将这一块内存指定为特定数据类型
  • 要注意不同的数据类型所占的空间,尤其在处理大数据集时,就要控制存储类型,例如双精度浮点值就要占8个字节,即64位
arr1 = np.array([1,2.,3], dtype=np.float64)
arr1
array([1., 2., 3.])
  • 可以使用astype将已有的数组转为其他数据类型
  • 浮点数转为整数,小数部分会被截断
  • 可将已有数组的类型传入到另外一个数组中
  • 调用astype无论如何都会创建一个新的数组,原始数据会被拷贝
# 浮点数转为整数,小数部分被截断
arr = np.array([3.7,1.2,-2.6,10.1])
new_arr = arr.astype(np.int32)
# 传入arr数组的类型
arr1 = np.array([1,.2,.3])
arr1.astype(new_arr.dtype)
array([1, 0, 0])

数组与标量之间的运算
  • 不用编写循环即可以对数据执行批量运算,这通常叫做矢量化(vectorization)
  • 大小相同的数组之间的任何算数运算都会将运算应用到元素级上
  • 不同大小的数组之间的运算叫做广播(broadcasting)(后续更新)
arr * arr
1/arr
array([ 0.27027027,  0.83333333, -0.38461538,  0.0990099 ])

基本的索引
  • 在对数组一个切片进行赋值时,赋值会自动传播或称广播到整个选区
  • 视图上的任何修改都会直接反映到源数据组上
  • 若想得到ndarray切片的一份副本而非视图,就需要显式地进行复制操作 切片.copy()
  • numpy设计的目的是处理大数据,如果将数据来回复制,必然产生内存和性能的问题
  • 高维数组其实本质是一样的,需要注意的是索引和赋值时的维度
print(arr[3])
print(arr[1:3])
# 赋值&&传播
arr[1:3] = 5.5555
print(arr[1:3])
10.1
[66. 66.]
[5.5555 5.5555]
arr_slice = arr[1:4]
arr_slice[1:3] = 234
print(arr)
arr_slice[:] = 666
arr
[  3.7      5.5555 234.     234.    ]

array([  3.7, 666. , 666. , 666. ])
# 高维数组操作
arr2d = np.array([[range(10)],[range(10)],[range(10)]])
arr2d
array([[[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]],

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

       [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]]])
arr2d[0] = 42
arr2d
array([[[42, 42, 42, 42, 42, 42, 42, 42, 42, 42]],

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

       [[ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9]]])
切片索引
  • ndarray一维切片与python列表这样的一维对象差不多
arr = np.array([1,2,3,4,5,6])
arr[1:5]
array([2, 3, 4, 5])
  • 高维切片的方式主要从轴向出发,沿轴切片,不指定轴,默认从第一个轴选取元素
arr2d = np.array([[1,2,3],[4,5,6],[7,8,9]])
arr2d[:2] #沿着竖轴切片
array([[1, 2, 3],
       [4, 5, 6]])
arr3d = np.array([[[1,2],[3,4]],[[5,6],[7,8]],[[9,10],[11,12]]])
print(arr3d)
arr3d[:2,:1]
[[[ 1  2]
  [ 3  4]]

 [[ 5  6]
  [ 7  8]]

 [[ 9 10]
  [11 12]]]





array([[[1, 2]],

       [[5, 6]]])
arr3d[:2,:1,:1]
array([[[1]],

       [[5]]])
  • 上面这种切片方式只能得到相同维度的数组视图,冒号代表选取整个轴
  • 通过将整数索引与切片混合的方式可以得到低维度的切片(整数代表选取的维度中的一维)
arr3d[0,:2]
array([[1, 2],
       [3, 4]])
arr3d[2,:1,:1]  #选取最后一个数组中,第一个列表的第一个元素
array([[9]])
  • 冒号与不添加冒号对比
arr3d[-1:,:,:1]  #整数-1代表最后一个,冒号代表整个轴
array([[[ 9],
        [11]]])
arr3d[-1:,:1]
array([[[ 9, 10]]])
  • 对切片表达式的赋值也会广播到整个选区
arr3d[:,:,-1:] = 0 #找到列表中最后一个元素,赋值为0
print(arr3d)
arr3d[:,-1:]
[[[ 1  0]
  [ 3  0]]

 [[ 5  0]
  [ 7  0]]

 [[ 9  0]
  [11  0]]]





array([[[ 3,  0]],

       [[ 7,  0]],

       [[11,  0]]])
布尔型索引
  • 数组的比较运算也是矢量化的
names = np.array(['Bob', 'Joe', 'Will', 'Bob', 'Will', 'Joe', 'Joe'])
data = np.random.randn(7, 4)
print(names)
print(data)
names == 'Bob' #矢量化产生数组
['Bob' 'Joe' 'Will' 'Bob' 'Will' 'Joe' 'Joe']
[[-0.63701615 -0.06376062  0.69585939  0.10945706]
 [-0.97944937 -0.30974647  1.24323123  1.19624871]
 [ 2.1017253  -0.29778746 -0.23660301  0.37227097]
 [ 2.22638506 -0.30476552  1.01003157 -0.6791929 ]
 [-0.1049328  -1.15896855  0.08494086  0.27167377]
 [ 1.80679737  0.39574461 -1.43315823  1.31850162]
 [-1.72153938  0.0493055   1.11043341  0.62209046]]





array([ True, False, False,  True, False, False, False])
  • 上面的布尔型数组可以用作数组索引
  • 还可将布尔型数组跟切片、整数混合使用
  • 除了使用等号,还可以使用(!=)(-)(|)(&)(> < )等多个布尔条件混合
  • 使用~符号反转布尔型
  • 与切片不同的是,使用布尔型索引选取数组中的数据,总是创建数据的副本,而不是修改数组的视图
print(data[names == 'Bob'])
print(data[names == 'Bob',:1])
print(data[~(names == 'Bob')])
[[-0.63701615 -0.06376062  0.69585939  0.10945706]
 [ 2.22638506 -0.30476552  1.01003157 -0.6791929 ]]
[[-0.63701615]
 [ 2.22638506]]
[[-0.97944937 -0.30974647  1.24323123  1.19624871]
 [ 2.1017253  -0.29778746 -0.23660301  0.37227097]
 [-0.1049328  -1.15896855  0.08494086  0.27167377]
 [ 1.80679737  0.39574461 -1.43315823  1.31850162]
 [-1.72153938  0.0493055   1.11043341  0.62209046]]
mask = (names == 'Bob') | (names == 'Will')
mask
array([ True, False,  True,  True,  True, False, False])
data[mask]
array([[-0.63701615, -0.06376062,  0.69585939,  0.10945706],
       [ 2.1017253 , -0.29778746, -0.23660301,  0.37227097],
       [ 2.22638506, -0.30476552,  1.01003157, -0.6791929 ],
       [-0.1049328 , -1.15896855,  0.08494086,  0.27167377]])
  • 通过布尔型数组设置值非常常见!!
  • 通过一维布尔数组设置整行或列的值也很简单
data[data>0.1] = 0 #将data中大于0.1的数值都设为0
print(data)
data[names == 'Bob'] = 7
print(data)
[[-0.63701615 -0.06376062  0.          0.        ]
 [-0.97944937 -0.30974647  0.          0.        ]
 [ 0.         -0.29778746 -0.23660301  0.        ]
 [ 0.         -0.30476552  0.         -0.6791929 ]
 [-0.1049328  -1.15896855  0.08494086  0.        ]
 [ 0.          0.         -1.43315823  0.        ]
 [-1.72153938  0.0493055   0.          0.        ]]
[[ 7.          7.          7.          7.        ]
 [-0.97944937 -0.30974647  0.          0.        ]
 [ 0.         -0.29778746 -0.23660301  0.        ]
 [ 7.          7.          7.          7.        ]
 [-0.1049328  -1.15896855  0.08494086  0.        ]
 [ 0.          0.         -1.43315823  0.        ]
 [-1.72153938  0.0493055   0.          0.        ]]
花式索引(Fancy indexing)
  • 利用整数数组进行索引
  • 花式索引也是返回新数组,与切片不同
arr = np.empty((8, 4))
for i in range(8):
    arr[i] = i
print(arr)
[[0. 0. 0. 0.]
 [1. 1. 1. 1.]
 [2. 2. 2. 2.]
 [3. 3. 3. 3.]
 [4. 4. 4. 4.]
 [5. 5. 5. 5.]
 [6. 6. 6. 6.]
 [7. 7. 7. 7.]]
arr[[4,3,2,1]] #传入一个指定顺序的整数序列即可返回指定行
array([[4., 4., 4., 4.],
       [3., 3., 3., 3.],
       [2., 2., 2., 2.],
       [1., 1., 1., 1.]])
  • 一次传入多个索引数组返回的是一个一维数组,其中的元素对应各个索引元组
  • 若想返回行的子集,需要用冒号或np.ix_
arr = np.arange(32).reshape((8,4))
print(arr)
[[ 0  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 31]]
print(arr[[4,3,2,1],[0,1,2,3]])  #返回的是选取的那行的对应的元素
print(arr[[4,3,2,1]][:,[0,1,2]]) #返回选取行的前3个数
print(arr[np.ix_([4,3,2,1],[0,1,2])]) #返回选取行的前3个数
[16 13 10  7]
[[16 17 18]
 [12 13 14]
 [ 8  9 10]
 [ 4  5  6]]
[[16 17 18]
 [12 13 14]
 [ 8  9 10]
 [ 4  5  6]]
数据转置和轴对换
  • 转置返回的是源数据的视图,不会进行复制操作
  • 高维数组,转置需要得到一个由轴编号组成的元组才能对这些轴进行转置
  • ndarray还有一个swapaxes方法,它需要接受一对轴编号,返回源数据的视图
arr = np.arange(15).reshape((3, 5))
arr
array([[ 0,  1,  2,  3,  4],
       [ 5,  6,  7,  8,  9],
       [10, 11, 12, 13, 14]])
arr.T
array([[ 0,  5, 10],
       [ 1,  6, 11],
       [ 2,  7, 12],
       [ 3,  8, 13],
       [ 4,  9, 14]])
np.dot(arr.T, arr) #计算矩阵内积
array([[125, 140, 155, 170, 185],
       [140, 158, 176, 194, 212],
       [155, 176, 197, 218, 239],
       [170, 194, 218, 242, 266],
       [185, 212, 239, 266, 293]])
  • Transpose与swapaxes的转置内涵就是将shape索引置换,例如其中元素8的索引是(1,0,0),通过transpose(1,0,2)的转换,意思为一维与二维之间的索引互换,三维不变,那么元素8的新位置为(0,1,0)
arr = np.arange(16).reshape((2, 2, 4))
print(arr)
print(arr[1,0,0])
print(arr[0,1,0])
print(arr[0,0,0])  #置换后仍为(0,0,0)
print(arr[0,0,1])  #置换后仍为(0,0,1)
[[[ 0  1  2  3]
  [ 4  5  6  7]]

 [[ 8  9 10 11]
  [12 13 14 15]]]
8
4
0
1
 arr.transpose((1, 0, 2))
array([[[ 0,  1,  2,  3],
        [ 8,  9, 10, 11]],

       [[ 4,  5,  6,  7],
        [12, 13, 14, 15]]])
arr.swapaxes(1, 2) #将索引(0,1,2)对换为(0,2,1)
array([[[ 0,  4],
        [ 1,  5],
        [ 2,  6],
        [ 3,  7]],

       [[ 8, 12],
        [ 9, 13],
        [10, 14],
        [11, 15]]])
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

苏啊苏

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值