首页 > 技术文章 > Day02 基础篇(三)用NumPy快速处理数据

MurasameLory-chenyulong 2021-01-15 21:49 原文

一、为什么使用numpy

  1、它是Python中使用最多的第三方库,它的数据结构比python自身的数据结构更加高效

  2、标准Python中用列表保存数组数值的方式其实是存放了指针与其对应的数据类型对象,对于Python来说浪费了内存和计算时间。

  3、标准Python中列表在系统内存中分散存储,NumPy数组存储在连续均匀内存块中,遍历元素时不需要对内存地址进行查找。

  4、NumPy直接利用现代CPU的矢量化指令计算,加载寄存器中的多个连续浮点数。

  5、NumPy的矩阵计算可以采用多线程模式充分利用多核CPU计算资源。

  注:使用Numpy时要注意使用规则提高内存利用率:避免采用隐式拷贝而采用就地操作,即采用x*=2而不要使用y= x*2

 

二、ndarray对象(处理多维数组问题)

  1、定义:

    (1)维数:指秩(rank),一维数组秩为1,二维数组秩为2

    (2)轴(axes):每一个线性数组称为一个轴,秩用以描述轴的数量

  2、ndarray对象

    ndarray是多维数组的含义,通常用其创建数组、处理结构数组。

    (1)创建数组

import numpy as np

a = np.array([1,2,3])
b = np.array([[1,2,3],[4,5,6],[7,8,9]])
#修改对应索引元素值
b[1,1] = 10
#shape表示a数组的大小(几行几列),dtype表示a数组元素的属性
print(a.shape)
print(b.shape)
print(a.dtype)
print(b)

 

 

 

    (2)结构数组

      与C语言中的结构体类似,存储包含不同数据类型的字段。

import numpy as np
# 用dtype定义结构类型
persontype = np.dtype({'names':['name','age','chinese','math','english'],
                       'formats':['S32','i','i','i','f']})
peoples = np.array([('ZhangFei',32,75,100,90),('GuanYu',24,85,96,88.5)
                      ,('ZhaoYun',28,85,92,96.5),('HuangZhong',29,65,85,100)],
                  dtype=persontype)
ages = peoples[:]['age']
chineses = peoples[:]['chinese']
maths = peoples[:]['math']
englishs= peoples[:]['english']
print(np.mean(ages))
print(np.mean(chineses))
print(np.mean(maths))
print(np.mean(englishs))

 

 

 

  3、ufunc运算

    ufunc能够对数组中每个元素进行函数操作,用unfunc计算速度快的原因是运算都是采用C语言实现的。

    (1)连续数组创建

      arange和linspace的作用都是创建等差数组,arange()是通过初始值、终值和步长来创建等差数列的一维数组,左闭右开。

      linspace是通过初始值、终值和元素个数来创建等差数列的一维数组的,左闭右闭。

 

import numpy as np

x1 = np.arange(1,11,2)
x2 = np.linspace(1,9,5)
print(x1)
print(x2)

 

   

  (2)算数运算

      解决两数组之间加、减、乘、除以及n次方和取余操作

import numpy as np

x1 = np.arange(1,11,2)
x2 = np.linspace(1,9,5)
print(x1)
print(x2)
print("=====================")
print(np.add(x1,x2))
print(np.subtract(x1,x2))
print(np.multiply(x1,x2))
print(np.divide(x1,x2))
#n次方操作,其中x1为基数,x2为次方
print(np.power(x1,x2))
#取余也可用mod表示
print(np.remainder(x1,x2))

 

 

  4、统计函数中自己关于axis的心得体会

    在刚开始看axis的时候, 翻了很多资料,看了很多人的解释,最后我想用自己算是比较笨的方法掌握axis,我将它称为坐标法,网上有个大佬说的很精辟:设axis=i,则numpy沿着第i个下标变化的方向进行操作。

    对以上这句话我自己的理解是将维数转化成坐标来表示,将数组转化为坐标来表示,你就能很清晰的理解这句话,有几个坐标位就要看对应有几个维度。比如是二维,那么坐标的开头就为D00,如果有三个就是D000,依次类推。

    (1)对于二维数组我的做法(看代码注释你一定明白了,关键要注意把下标标好,最好每一行都标出来)

import numpy as np

#创建二维数组
np_data = np.array([[1,2,3],    #D00~D02
                    [4,5,6]])   #D10~D12
#如果axis为0,则是沿下标0(就是D后的第一个0)的变化(只能产生一个变化),例如:D00->D10,D01->D11,D02->D12
print(np.sum(np_data,axis=0))

    (2)对于三维数组我的做法

import numpy as np

#创建二维数组
np_data = np.array([[[[3, 5, 5, 0],  # D0000  ->   D0003
         [0, 1, 2, 4],     # D0010  ->   D0013
         [0, 5, 0, 5]],    # D0020  ->   D0023

         [[5, 5, 0, 0],    # D0100  ->   D0103
          [2, 1, 5, 0],    # D0110  ->   D0113
          [1, 0, 0, 1]]],  # D0120  ->   D0123

       [[[0, 5, 1, 2],     # D1000  ->   D1003
         [4, 4, 2, 2],     # D1010  ->   D1013
         [3, 5, 0, 1]],    # D1020  ->   D1023

        [[5, 1, 2, 1],     # D1100  ->   D1103
         [2, 2, 3, 5],     # D1110  ->   D1113
         [5, 3, 3, 3]]],   # D1120  ->   D1123

       [[[2, 4, 1, 4],     # D2000  ->   D2003
         [1, 4, 1, 4],     # D2010  ->   D2013
         [4, 5, 0, 2]],    # D2020  ->   D2023

        [[2, 5, 5, 1],     # D2100  ->   D2103
         [5, 3, 0, 2],     # D2110  ->   D2113
         [4, 0, 1, 3]]],   # D2120  ->   D2123

       [[[1, 3, 4, 5],     # D3000  ->   D3003
         [0, 2, 5, 4],     # D3010  ->   D3013
         [2, 3, 5, 3]],    # D3020  ->   D3023

        [[2, 2, 2, 2],     # D3100  ->   D3103
         [3, 2, 1, 3],     # D3110  ->   D3113
         [0, 3, 0, 1]]]])  # D3120  ->   D3123
#如果axis为0,则是沿下标0(就是D后的第一个0,维度最高位)的变化(只能产生一个变化),例如:D0000->D1000、D2000、D3000、D4000
print(np.sum(np_data,axis=0))

 

 

  5、统计函数总结

    (1)最大值函数amax(arrary,axis=)和最小值函数amin(arrary,axis=)

import numpy as np

a = np.array([[1,2,3],[4,5,6],[7,8,9]])
#求数组中的最小元素
print(np.amin(a))
#按axis为0求数组中的最小元素
print(np.amin(a,0))
#按axis为1求数组中的最小元素
print(np.amin(a,1))
#amax同理
print(np.amax(a))
print(np.amax(a,0))
print(np.amax(a,1))

 

 

    (2)统计最大值与最小值之差ptp()

import numpy as np

a = np.array([[1,2,3],[4,5,6],[7,8,9]])
#求数组中的最小元素和最大元素之差
print(np.ptp(a))
#按axis为0求数组中的最小元素和最大元素之差
print(np.ptp(a,0))
#按axis为1求数组中的最小元素和最大元素之差
print(np.ptp(a,1))

 

 

    (3)百分位数

import numpy as np

a = np.array([[1,2,3],[4,5,6],[7,8,9]])
#寻找中位数
print(np.percentile(a,50))
print(np.percentile(a,50,axis = 0))
print(np.percentile(a,50,axis = 1))

 

 

    (4)中位数median()和平均数mean()

import numpy as np

a = np.array([[1,2,3],[4,5,6],[7,8,9]])
#寻找中位数
print(np.median(a))
print(np.median(a,axis = 0))
print(np.median(a,axis = 1))
#寻找平均数
print(np.mean(a))
print(np.mean(a,axis = 0))
print(np.mean(a,axis = 1))

 

 

    (5)加权平均值average()

        通过weights来设置元素的权值(用另外一个数组来对应不同元素的权值),加权平均就是元素数值乘以对应的权重之和再除以权重之和所得就是加权平均值,默认每个元素的权重都是相同的都是1。

import numpy as np
a = np.array([1,2,3,4])
wts = np.array([1,2,3,4])
print(np.average(a))
print(np.average(a,weights=wts))

 

 

    (6)标准差std(),方差var()

import numpy as np
a = np.array([1,2,3,4])
print(np.std(a))
print(np.var(a))

 

 

    (7)numpy中的排序

      排序算法需要使用到sort函数,标准格式为sort(a,axis=x,kind = 'xxx',order=x),kind中可以制定排序的种类,比如:quicksort、mergesort、heapsort分别表示快速排序、合并排序和推排序,axis默认为-1,就是沿着最后一个坐标进行排序,axis=None代表采用扁平化的方式作为一个向量进行排序(就是变成一维数组进行排序),order对于结构化的数组可以制定按照某个字段进行排序。

import numpy as np
a = np.array([[4,3,2],[2,4,1]])
print (np.sort(a))
print (np.sort(a, axis=None))
print (np.sort(a, axis=0))
print (np.sort(a, axis=1))

 

三、补充

  1、关于shape()的补充,简单理解:shape生成元组中有几个数,shape对应的numpy的数组对象就是几维。Shape[]常用于来输出数据某一维度的元素个数方便创建同维度的数组。

 

  2、将数组转化为1维数组可以采用flatten()函数

 

  3、numpy中加减乘除的值被应用到所有元素上

t5 = np.array([1,2,3,4,5])
#调整数据类型
t6 = t5.astype("int8")
print(t5)
print(t5.dtype)
print(t6)
print(t6.dtype)
#取小数
t7 = np.array([random.random() for i in range(10)])
t8 = np.round(t7,2)
print(t8)

 

 

  4、广播原则:

    (1)两个数组各维度大小从后往前比对均一致

    (2)两个数组存在一些维度大小不相等时,有一个数组的该不相等维度大小为1

 

  5、numpy读取数据

    (1)csv(逗号分隔值文件)

        以表格形式显示,源文件为换行和逗号分隔行列的格式化文本,每一行的数据表示一条记录。

    (2)np.loadtxt(frame,dtype = np.float,delimiter = None,skiprotws = 0,usecos = None,unpack =False)

 

 

 

  6、numpy中的转置:

    (1)数组名.transpose()     直接转置

    (2)数组名.swapaxes()     交换轴

 

  7、numpy的索引和切片

#索引和切片
t1  = np.array([[1,2,3,4,5],[6,7,8,9,10],[1,4,6,7,8],[4,6,8,9,3]])
#取行
print(t1[2])
print('*'*100)
#取连续的多行
print(t1[2:])
print('*'*100)
#取不连续的多行
print(t1[[0,2,3]])
#取列
print('*'*100)
print(t1[:,1])
#取不连续多列
print('*'*100)
print(t1[:,[0,1]])
#取多行多列(切片索引范围为左闭右开区间)
print('*'*100)
print(t1[1:3,0:3])

 

 

  8、numpy中布尔索引(整体替换)

#整体替换
t1  = np.array([[1,2,3,4,5],[6,7,8,9,10],[1,4,6,7,8],[4,6,8,9,3]])
t1[t1>5] = 3
print(t1)

 

 

  9、numpy中的三元运算符(对原数组没有影响)

           对于要使用两次布尔索引且恰好相互对立的现象,我们直接采用三元运算符进行解决。

#三元运算符
t1  = np.array([[1,2,3,4,5],[6,7,8,9,10],[1,4,6,7,8],[4,6,8,9,3]])
t =np.where(t1<=5,0,1)
print(t)

 

 

  10、numpy中的裁剪(对原数组没有影响)

#裁剪
t1  = np.array([[1,2,3,4,5],[6,7,8,9,10],[1,4,6,7,8],[4,6,8,9,3]])
print(t1.clip(5,7))

 

 

  11、数组的拼接

#拼接
t1 = ([[1,2,3,4,5],[6,7,8,9,10]])
t2 = ([[1,4,6,7,8],[4,6,8,9,3]])
#竖直拼接
print(np.vstack((t1,t2)))
#水平拼接
print(np.hstack((t1,t2)))

 

 

  12、获取最大值最小值的位置

           np.argmax(t,axis = 0)

           np.argmin(t,axis = 1)

 

  13、创建一个全为0的数组:np.zero((3,4))

 

  14、创建一个全为1的数组:np.ones((3,4))

 

  15、创建一个对角线为1的正方形数组:np.eye(3)

 

  16、numpy生成随机数

 

 

  17、numpy关于赋值和视图的注意点

    (1)a=b完全不复制,a和b相互影响

    (2)a=b[:]视图操作,一种切片,会创建新的对象a,但是a的数据完全由b保管,他们两个的数据变化是一致的。

    (3)a=b.copy()复制,a和b互不影响

  18、numpy中nan和inf

    (1)出现nan的情况:读取文件数据有所缺失,不合适的计算

    (2)nan的特殊属性:两个nan不相等。np.nan!=np.nan 。利用以上特性可以判断数组中nan的个数(np.count_nonzero(t!=t))。通过np.isnan(a)俩判断,返回bool类型。Nan与任何值计算都为nan。

  19、将数组中的nan替换为均值

#替换nan
t1 = np.arange(12).reshape((3,4)).astype("float")

t1[1,2:] = np.nan
print(t1)
print('*'*100)

for i in range(t1.shape[1]) : #遍历每一列
    temp_col = t1[:,i] #当前的一列
    nan_num = np.count_nonzero(temp_col!= temp_col)
    if nan_num !=0: #不为零,说明当前这一列有nan
        temp_not_nan_col = temp_col[temp_col==temp_col]#当前列不为nan的array
        temp_col[np.isnan(temp_col)] = temp_not_nan_col.mean()

print(t1)

 

 

  20、行列交换

#交换
t = np.array([[1,2,3,4,5],[6,7,8,9,10]])
print(t)
print("*"*100)
t[:,[0,1]]=t[:,[1,0]]
print(t)

 

推荐阅读