暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

利用Python进行数据分析之Numpy

这是我的葱 2021-12-11
480

Numpy是Numerical Python的简称,是目前Python数值计算中最为重要的基础包。对于大多数的数据分析应用,主要关注的内容应为:

  • 数据处理、清洗、构造子集、过滤、变换以及其他计算中的快速向量化

  • 常见数组算法,比如sort、unique等

  • 数据排列和相关性操作,例如对异构数据进行merge和join

  • 使用数组表达式来表明条件逻辑,代替if-elif-else条件分支循环

  • 数据分组的操作(聚合、变换以及函数式操作)

安装Numpy库

查看conda中已有的的环境名称conda info -e
或者conda info --env
或者conda env list

创建新环境conda create --name Exercise python=3.9
或者conda create -n Exercise python=3.9

环境的激活与切换conda activate Exercise

导入Numpyconda install -n Exercise Numpy

环境的删除conda remove -n Exercise --all


Numpy ndarray:多维数组对象

ndarray 是一个通用的多维同类型数据容器,它包含的每个元素均为相同类型。

import numpy as np
data = np.random.randn(2,3)
print(data)
print(data.shape)
print(data.dtype)

生成ndarray

  1. 使用array函数

    # 一维数组
    data1 = [6,7.5,8,0,1]
    arr1 = np.array(data1)
    print(arr1)
    # 多维数组
    data2 = [[1,2,3,4],[5,6,7,8]]
    arr2 = np.array(data2)
    print(arr2)
  2. 使用其他函数

    函数名描述
    array将输入数据(列表、元组、数组及其他序列)转换为ndarray
    asarray将输入转换为ndarray,如果输入已经是ndarray则不再复制
    arange内建函数range的数据版本,返回一个数组
    ones根据给定形状和数据类型生成全1数组
    ones_like根据所给数组生成一个形状一样的全1数组
    zeros根据给定形状和数据类型生成全0数组
    zeros_like根据所给数组生成一个形状一样的全0数组
    empty根据给定形状生成一个没有初始化数值的空数组
    empty_like根据所给数组生成一个形状一样但没有初始化数值的空数组
    full根据给定形状和数据类型生成指定数值的数组
    full_like根据所给数组生成一个形状一样的指定数值的数组
    eye, identity生成一个N*N特征矩阵(对角线位置都是1,其余位置是0)
    print(np.zeros(10))
    print(np.ones((3,6)))
    print(empty((2,3,2)))

ndarray的数据类型

数据类型,即dtype,是一个特殊的对象,包含ndarray需要为某一种类型数值所申明的内存块信息(也称元数据,即表示数据的数据)

类型类型代码描述
int8/uint8i1/u1有符号/无符号的8数位整数
int16/uint16i2/u2有符号/无符号的16数位整数
int32/uint32i4/u4有符号/无符号的32数位整数
int64/uint64i8/u8有符号/无符号的64数位整数
float16f2半精度浮点数
float32f4/f标准单精度浮点数;兼容C语言float
float64f8/d标准双精度浮点数;兼容C语言double
float128f16/g拓展精度浮点数
complex64c8基于32位浮点数的复数
complex128c16基于64位浮点数的复数
complex256c32基于128位浮点数的复数
bool?布尔值,存储True或False
objectOPython object类型
string_S修正的ASCII字符串类型;
unicodeU修正的Unicode类型;

可以使用astype方法显示转换数组的数据类型:

arr = np.array([1,2,3,4,5])
float_arr = arr.astype(np.float64)
print(arr.dtaype)
print(float_arr.dtype)

Numpy的数组算术

任何两个等尺寸数组之间的算术操作都应用了逐元素操作的方式(向量化)

不同尺寸的数组间的操作,会用到广播特性。

import numpy as np
# 数组与数的计算 线性代数
# 想要对列表中的所有元素都加上一个数,要么采用map函数,要么循环整个列表
# 但是在Numpy中的数组可以直接在数组上进行操作
a1 = np.random.random((3,4))
print(a1)
a2 = a1*10 # a1的所有元素都乘以10
print(a2)
a3 = a2.round(2) # 使用round函数,让所有元素只保留2位小数
print(a3)

# 数组与数组的计算
# 结构相同的数组之间的运算
a4 = np.arange(0,24).reshape((3,8))
a5 = np.random.randint(1,10,size = (3,8))
a6 = a4 + a5
print(a4)
print(a5)
print(a6)
# 与行数相同并且只有1列的数组之间的运算
a7 = np.random.randint(10,20,size=(3,8))
a8 = np.random.randint(1,10,size=(3,1))
a9 = a7 - a8 # 行数相同,且a8只有一列,能互相运算
print(a9)
# 与列数相同并且只有1行的数组之间的运算
a10 = np.random.randint(10,20,size=(3,8))
a11 = np.random.randint(1,10,size=(3,1))
a12 = a10 - a11

# 广播原则:
# 如果两个数组的后缘维度(trailing dimension,即从末尾开始算起的维度)
# 的轴长度相符合或其中一方的长度为1,则认为他们是广播兼容的
# 广播会在缺失和长度为1的维度上进行

索引与切片

简单来说,索引是指定数组中的某一个值或某一行/列值;切片可用于指定数组中多个值或某几行/列值

数组的切片索引

import numpy as np
# 一维数组的索引和切片
a1 = np.arange(10)
print(a1)
print(a1[4])        # 进行索引操作
print(a1[4:6])      # 进行切片操作
print(a1[::2])      # 使用步长
print(a1[-1])       #使用负数作为索引

# 多维数组的索引和切片 获取某一行某一列的数值 通过中括号来索引和切片
# 在中括号中使用逗号分隔,逗号前是行,逗号后是列,如果多维数组中只有一个值,那么这个值就是行
a2 = np.random.randint(0,10,size=(4,6))
print(a2)
print(a2[0]) #获取第0行的数组 - 索引
print(a2[1:3]) #获取第一行和第二行的数组 - 切片
print(a2[[0,2,3]]) #获取第0 第二 第三行的数组 - 不连续切片
print(a2[1,2]) # 获取第一行,第二列的值 - 索引
print(a2[[1,2],[4,5]]) # 获取第一行第四列和第二行第五列的数组 索引
print(a2[1:3,4:6]) # 获取第一第二行,且第四第五列的数组 - 连续切片
print(a2[:,1]) #获取第一列的全部数据 - 切片

布尔索引

布尔值数组的长度必须和数组轴索引长度一致,一般用原数组做逻辑判断后取出索引的值

import numpy as np
# 布尔运算也是矢量运算
a1 = np.arange(0,24).reshape((4,6))
print(a1)
print(a1<10)
# 返回一个新的数组,数组中的值都是布尔类型
print(a1[a1<10])
# 在a1中把True的元素对应的位置的值取出来
# 布尔运算可以有 !=、==、>、<、>=、<=、&、|

神奇索引

神奇索引是Numpy中的术语,用于描述使用整数数值进行数据索引。

import numpy as np

arr1 = np.empty((8,4))
for i in range(8):
 arr1[i] = i
print(arr1)
# 取出第4、3、0、6行
print(arr1[[4,3,0,6]])

arr2 = np.arange(32).reshape((8,4))
print(arr2)
# 取出(1,0)、(5,3)、(7,1)、(2,2)位置的元素
print(arr2[[1,5,7,2],[0,3,1,2]])

数组转置和换轴

转置是一种特殊的数据重组形式,可用于矩阵内积。

import numpy as np

# 一维二维数组常用T属性转置
arr1 = np.random.randn(6,3)
print(arr1)
print(np.dot(arr1.T,arr1))

# 高维数组使用transpose方法,拓展思维
arr2 = np.arange(16).reshape((2,2,4))
print(arr2)
print(arr2.transpose((1,0,2)))

# swapaxes方法,也可对轴进行调整用于重组数据
print(arr2.swapaxes(1,2))

数组的形状操作

数组的变形

  1. reshape & resize

    import numpy as np
    from numpy.core.fromnumeric import resize

    # reshape是将数组转换成指定的形状,返回的结果对于原数组的形状是不会发生改变的
    # resize将数组转换成指定的形状,会直接修改数组本身,并不会返回任何值
    a1 = np.random.randint(1,10,size=(3,4))
    a2 = a1.reshape((2,6))
    print(a1)
    print(a2)

    a1.resize((2,6))
    print(a1)
  2. flatten & ravel

    import numpy as np

    # flatten是将数组转换为一维数组后,将这个拷贝返回回去,所以后续对这个返回值进行修改不会影响之前的数组
    # ravel是将数组转换为一维数组后,将这个视图返回回去,所以后续对这个返回值进行修改会影响之前的数组
    x = np.array([[1,2],[3,4]])
    x.flatten()[1] = 100
    print(x)
    print(x.flatten())

    x.ravel()[1] = 100
    print(x)
    print(x.ravel())

数组的叠加

import numpy as np

# 数组的叠加
# vstack:垂直方向叠加,列数相同,增加行
a1 = np.random.randint(1,10,size=(3,5))
a2 = np.random.randint(0,10,size=(1,5))
a3 = np.vstack([a1,a2])
a6 = np.concatenate([a1,a2],axis=0) # 中括号 小括号都可以?
print(a3)
print('='*30)
print(a6)
print('='*30)
# hstack:水平方向叠加,行数相同,增加列
a4 = np.random.randint(0,10,size=(3,1))
a5 = np.hstack([a1,a4])
a7 = np.concatenate((a4,a5),axis=1)
print(a5)
print('='*30)
print(a7)
print('='*30)
# concatenate(a,b,axis):参数axis控制叠加方向
   # axis=0,代表垂直叠加(行)叠加;
   # axis=1,代表水平叠加(列)叠加;
   # 如果axis=none,会将两个数组组合成一个一维数组。
a8 = np.concatenate((a1,a4),None) # None,不是none
print(a8)

数组的切割

import numpy as np

# 数组切割
# hsplit:按照水平方向进行切割。用于指定分割成几列,可以使用数字来代表分成几部分,也可以使用数组来代表分割的地方
a1 = np.arange(16).reshape(4,4)
a2 = np.hsplit(a1,2) # 平均分割成两部分
print(a1)
print('='*30)
print(a2)
a3 = np.hsplit(a1,(1,2)) # 在下标为1的地方切一刀,下标为2的地方切一刀,分成三个部分
print('='*30)
print(a3)
# vsplit:按照垂直方向进行切割,用于指定分割成几行,可以使用数字来代表分成几部分,也可以使用数组来代表分割的地方
# split/array_aplit(array,indicate_or_seciont,axis):用于制定切割方式,在切割的时候需要制定按照行还是按照列切割,axis=1代表列,axis=0代表行
a4 = np.array_split(a1,2,axis=0)
print('='*30)
print(a4)


通用函数:快速的逐元素数组函数

通用函数也称ufunc
,对某些标量计算结果进行向量化封装。

一元通用函数

函数名描述
abs/fabs逐元素计算整数/浮点数或复数的绝对值
sqrt计算每个元素的平方根(arr**0.5)
square计算每个元素的平方(arr ** 2)
exp计算每个元素的自然指数值e的x次方
log/log10/log2/log1p分别对应:自然对数(e为底)、10为底对数、2为底对数、log(1+x)
sign计算每个元素的符号值:1=正数 0=0 -1=负数
ceil计算每个元素的最高整数值(即大于等于给定数值的最小整数)
floor计算每个元素的最小整数值(即小于等于给定元素的最大整数)
rint将元素保留到整数位,并保持dtype
modf非别将数组的小数部分和整数部分按数组形式返回
isnan返回数组中的元素是否是一个NaN,返回值为布尔值数组
isfinite/isinf分别返回数组中的元素是否有限/无限,返回值为布尔值数组
cos/cosh/sin常规双曲三角函数
sinh/tan/tanh常规双曲三角函数
arcos/arccosh/arcsin反三角函数
arcsinh/arctan/arctanh反三角函数
logical_not对数组的元素按位取反(与~arr效果一致)

二元通用函数

函数名描述
add数组对应元素相加
subtract在第二个数组中,将第一个数组中包含的元素去除
multiply将数组的对应元素相乘
divide/floor_divide除或整除
power将第二个数组的元素作为第一个数组对应元素的幂次方
maximum/fmax逐个元素计算最大值,fmax忽略NaN
minimum/fmin逐个元素计算最小值,fmin忽略NaN
mod按元素的求模计算(即求除法的余数)
copysign将第一个数组的符号值改为第二个数组的符号值
greater/greater_equal/less进行逐个元素比较,返回布尔值数组(与数学操作符>/>=/<效果一致)
less_equal/equal/not_equal进行逐个元素比较,返回布尔值数组(与数学操作符<=/==/!=效果一致)
logical_and/logical_or/logical_xor进行逐个元素的逻辑操作(与逻辑操作符&/|/^效果一致)


使用数组进行面向数组编程

利用数组表达式来替代显式循环的方法,成为向量化
,通常向量化的数组操作会比纯Python的等价实现在速度上快一到两个数量级(甚至更多)。

条件逻辑的数组操作

np.where
函数是三元表达式x if condition else y
的向量化版本

import numpy as np

xarr = np.array([1.1,1.2,1.3,1.4,1.5])
yarr = np.array([2.1,2.2,2.3,2.4,2.5])
cond = np.array([True,False,True,True,False])

# 使用三元表达式
result1 = [(x if c else y)
        for x,y,c in zip(xarr,yarr,cond)]
print(result1)

# 使用np.where
result2 = np.where(cond,xarr,yarr)
print(result2)

数学和统计方法

方法描述
sum沿着轴向计算所有元素的累和
mean数学平均
std/var标准差/方差
min/max最小值/最大值
argmin/argmax最小值的位置/最大值的位置
cumsum从0开始元素累积和
cumprod从1开始元素累积积

布尔值数组的方法

import numpy as np

# 结合sum函数计算数组中True的个数
arr = np.random.randn(100)
(arr > 0).sum() # 正值的个数

# any函数:检查数组中是否至少有一个True
# all函数:检查是否每个值都是True

排序

import numpy as np

# sort函数
arr = np.random.randn(5,3)
print(arr)
print(arr.sort()) # 默认按照axis=0,即按行进行升序排序
print(arr.sort(1)) # 指定axis=1,即按列进行升序排序

唯一值与其他集合逻辑

方法描述
unique(x)计算x的唯一值,并排序
intersect1d(x,y)计算x和y的交集,并排序
union1d(x,y)计算x和y的并集,并排序
in1d(x,y)计算x中的元素是否包含在y中,返回一个布尔值数组
setdiff1d(x,y)差集,在x中但不在y中的x的元素
setxor1d(x,y)异或集,在x或y中,但不属于x/y交集的元素

文件输入和输出

import numpy as np
# 文件保存
# np.savetxt(frame,array,fmt='%.18e',delimiter=None)
# frame:文件、字符串或产生器,可以是.gz .bz2的压缩文件
# array:存入文件的数组
# fmt:写入文件的格式,例如%d %.2f %.18e
# delimiter:分割字符串,默认是任何空格
a = np.arange(100).reshape(5,20)
np.savetxt("a.csv",a,fmt="%d",delimiter=",")

# 读取文件
# np.loadtxt(frame,dtype=np.float,delimiter=None,unpack=False)
# frame:文件、字符串或产生器,可以是.gz .bz2的压缩文件
# dtype:数据类型,可选
# delimiter:分割字符串,默认是空格
# skiprows:跳过前面x行
# usecols:读取指定的列,用元组组合
# unpack:如果是True,读取出来的数组是转置之后的
b = np.loadtxt("a.csv",dtype=np.int8,delimiter=",")
print(b)

# np独有的存储解决方案
# numpy中有一种独有的存储解决方案,文件名是以.npy或者.npz结尾的,以下是存储和加载的函数
# 存储:np.save(fname,array)或者np.savez(fname,array)。后者是经过压缩的
# 加载:np.load(fname)
a = np.random.randint(0,10,size=(3,4))
np.save("b",a)                     # 可以存储多维数组
np.savez("c",a)
b = np.load("b.npy")
c = np.load("c.npz")
print(b)
print('='*30)
print(c.files)
c1 = c['arr_0']
print('='*30)
print(c1)

# 导入csv模块,快速读写文件
import csv
# 读文件
def read_csv_demo1():
   with open('a.csv','r') as fp: # fp是一个指针
   # reader是一个迭代器
       reader = csv.reader(fp)
   # titiles = next(reader)
       for x in reader:
           name = x[3]
           volumn = x[-1]
           print({'name':name,'volumn':volumn})

def read_csv_demo2():
   with open('a.csv','r') as fp:
       reader = csv.DictReader(fp)
       for x in reader:
           value = {'name':x['3'],'volumn':x['19']}
           print(value)
           print(x['3'])

if __name__=='__main__':
   read_csv_demo1()
   print('='*30)
   read_csv_demo2()

# 写文件
headers = ['name','age','classroom']
values1 = [
  ('Bob',18,'111'),
  ('Tom',20,'222'),
  ('Jerry',21,'111')
]
values2 = [
  {'name':'Bob','age':18,'classroom':'111'},
  {'name':'Tom','age':20,'classroom':'222'}
]
def write_csv_demo1():
   with open('test1.csv','w',newline='',encoding = 'utf-8') as fp:
       writer = csv.writer(fp)
       writer.writerow(headers)
       writer.writerows(values1)

def write_csv_demo2():
   with open('test2.csv','w',newline='') as fp:
       writer = csv.DictWriter(fp,headers)
       writer.writeheader()
       writer.writerow({'name':'Simon','age':25,'classroom':'111'})
       writer.writerows(values2)

if __name__ == '__main__':
   write_csv_demo1()
   write_csv_demo2()
   print(headers)
   print(values1)


线性代数

线性代数,比如矩阵乘法、分解、行列式等方阵数学,是所有数组类库的重要组成部分。需要注意的是,Numpy中的*
是矩阵的逐元素乘积,而不是矩阵的点乘积,点乘积需使用dot函数

函数描述
diag将一个方阵的对角元素作为一维数组返回
dot矩阵点乘积
trace计算对角元素和
det计算矩阵的行列式
eig计算方阵的特征值和特征向量
inv计算方阵的逆矩阵
pinv计算矩阵的Moore-Penrose伪逆
qr计算QR分解
svd计算奇异值分解(SVD)
solve求解x的线性系数Ax=b,其中A是方阵
lstsq计算Ax=b的最小二乘解

伪随机数生成

np.random
模块可以高效地生成多种概率分布下的完整样本值数组。np.random
模块生成的随机数称为伪随机数
,它们是由具有确定行为的算法根据随机数生成器中的随机数种子生成的,可以通过np.random.seed
更改随机数种子。np.random
生成函数使用的是一个全局随机种子,为避免全局状态,可以使用np.random.RandomState
创建一个随机数生成器,使数据独立于其他随机数。

函数描述
seed向随机数生成器传递随机状态种子
permutation返回一个序列的随机排列,即乱序整数序列
shuffle随机排列一个序列
rand从均匀分布中抽取样本
randint根据给定的由低到高的范围抽取随机整数
randn从均值0,方差1的正太分布中抽取样本
binomial从二项分布中抽取样本
normal从正太(高斯)分布中抽取样本
beta从beta分布中抽取样本
chisquare从卡方分布中抽取样本
gamma从伽马分布中抽取样本
uniform从均匀[0,1)分布中抽取样本


补充知识点

方差
:各个数据与其算术平均数的离均差平方和再求平均数,用于表示数据的离散程度

标准差
:方差是数据的平方,与检测值本身相差太大,难以直观的衡量,所以常用方差开根号换算回来,这就是标准差。

累积和
:每个元素与之前元素的和,例如array([1,2,3,4,5])求累积和为array([1,3,6,10,15])

累积积
:每个元素与之前元素的积,例如array([1,2,3,4,5])求累积积为array([1,2,6,24,120])

特征值
:设 A 是n阶方阵,如果存在数m和非零n维列向量 x,使得 Ax=mx 成立,则称 m 是矩阵A的一个特征值

特征向量
:设 A 是n阶方阵,如果存在数m和非零n维列向量 x,使得 Ax=mx 成立,则称 x 是矩阵A的一个特征向量

行列式
:是由排成n阶方阵形式的n²个数aij(i,j=1,2,...,n)确定的一个数,其值为n!项之和

奇异矩阵
:若矩阵A相应的行列式D=0,称A为奇异矩阵,否则称为非奇异矩阵


“温故而知新,可以为师也”

最近顾着快速推进学习进度,复习也不能落下~


文章转载自这是我的葱,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论