2

发布时间 2023-06-02 10:44:11作者: 晏雷雨

#!/usr/bin/env python
# coding: utf-8

# # Python数据分析之Numpy

# Python有着大量功能强大的第三方库。这些第三方库可以大大地扩充Python的功能,我们在实际使用中往往也离不开这些第三方库。

# NumPy是Python的一种开源的数值计算扩展。这种工具可用来存储和处理大型矩阵,比Python自身的嵌套列表(nested list structure)结构要高效的多。NumPy(Numeric Python)提供了许多高级的数值编程工具。Numpy的一个重要特性是它的数组计算,是我们做数据分析必不可少的一个包。

# 导入python库使用关键字import,后面可以自定义库的简称,但是一般都将Numpy命名为np,pandas命名为pd。

# 使用前一定要先导入Numpy包,导入的方法有以下几种:
import numpy
import numpy as np #推荐写法
from numpy import * #不是很建议这种写法,因为不用加前缀的话有可能会与其他函数名称起冲突,因而报错
# In[1]:


import numpy as np


# ## 1.Numpy的数组对象及其索引

# ### 数组上的数学操作

# 假设我们想将列表中的每个元素增加1,但列表不支持这样的操作:

# In[5]:


a = [1,2,3,4]
#a+1 #报错


# In[6]:


[x+1 for x in a]


# In[7]:


b = [2,3,4,5]


# 与另一个数组相加,得到对应元素相加的结果:

# In[8]:


a+b #并不是我们想要的结果


# In[9]:


[x+y for(x,y) in zip(a,b)] #都需要利用到列表生成式


# 这样的操作比较麻烦,而且在数据量特别大的时候会非常耗时间。

# 如果我们使用Numpy,就会变得特别简单

# In[11]:


a = np.array([1,2,3,4])
a


# In[12]:


a+1


# In[13]:


a*2


# In[17]:


b = np.array([2,3,4,5])
a + b


# ### 产生数组

# 从列表产生数组:

# In[18]:


l = [0,1,2,3]
a = np.array(l)
a


# 从列表传入:

# In[19]:


a = np.array([1,2,3,4])
a


# 生成全0数组:

# In[20]:


np.zeros(5) #括号内传个数,默认浮点数


# 生成全1的数组:

# In[21]:


np.ones(5) #括号内传个数,默认浮点数


# In[24]:


np.ones(5,dtype="bool") #可以自己指定类型,np.zeros函数同理


# 可以使用 fill 方法将数组设为指定值

# In[25]:


a = np.array([1,2,3,4])
a


# In[27]:


a.fill(5) #让数组中的每一个元素都等于5
a


# 与列表不同,数组中要求所有元素的 dtype 是一样的,如果传入参数的类型与数组类型不一样,需要按照已有的类型进行转换。

# In[29]:


a.fill(2.5) #自动进行取整
a


# In[34]:


a = a.astype("float") #强制类型转换
a.fill(2.5)
a


# 还可以使用一些特定的方法生成特殊的数组

# 生成整数序列:

# In[41]:


a = np.arange(1,10) #左闭右开区间,和range的使用方式同理
a


# 生成等差数列:

# In[43]:


a = np.linspace(1,10,21) #右边是包括在里面的,从a-b一共c个数的等差数列,其实np.arange好像也可以做...
a


# 生成随机数

# In[45]:


np.random.rand(10)


# In[46]:


np.random.randn(10) #标准正态分布


# In[49]:


np.random.randint(1,20,10) #生成随机整数,从1-20中随机10个


# ### 数组属性

# 查看类型:

# In[52]:


a


# In[54]:


type(a)


# 查看数组中的数据类型:

# In[61]:


a.dtype


# 查看形状,会返回一个元组,每个元素代表这一维的元素数目:

# In[62]:


a.shape


# 或者使用:

# In[67]:


np.shape(a)


# 要看数组里面元素的个数:

# In[70]:


a.size


# 查看数组的维度:

# In[71]:


a.ndim


# ### 索引和切片

# 和列表相似,数组也支持索引和切片操作。

# 索引第一个元素:

# In[5]:


a = np.array([0,1,2,3])
a[0]


# 修改第一个元素的值

# In[6]:


a[0] = 10
a


# `切片,支持负索引:

# In[15]:


a = np.array([11,12,13,14,15])
a[1:3] #左闭右开,从0开始算


# In[10]:


a[1:-2] #等价于a[1:3]


# In[16]:


a[-4:3] #仍然等价a[1:3]


# 省略参数:

# In[17]:


a[-2:] #从倒数第2个取到底


# In[19]:


a[::2] #从头取到尾,间隔2


# 假设我们记录一部电影的累计票房:

# In[2]:


ob = np.array([21000,21800,22240,23450,25000])
ob


# 可以这样计算每天的票房:

# In[4]:


ob2 = ob[1:]-ob[:-1]
ob2


# ### 多维数组及其属性

# array还可以用来生成多维数组:

# In[6]:


a = np.array([[0,1,2,3],[10,11,12,13]])
a


# 事实上我们传入的是一个以列表为元素的列表,最终得到一个二维数组。
#
# 查看形状:

# In[7]:


a.shape


# 查看总的元素个数:

# In[9]:


a.size


# 查看维数:

# In[10]:


a.ndim


# ### 多维数组索引

# 对于二维数组,可以传入两个数字来索引:

# In[11]:


a


# In[14]:


a[1,3]


# 其中,1是行索引,3是列索引,中间用逗号隔开。事实上,Python会将它们看成一个元组(1,3),然后按照顺序进行对应。
#
# 可以利用索引给它赋值:

# In[15]:


a[1,3] = -1
a


# 事实上,我们还可以使用单个索引来索引一整行内容:

# In[16]:


a[1]


# Python会将这单个元组当成对第一维的索引,然后返回对应的内容。

# In[17]:


a[:,1]


# ### 多维数组切片

# 多维数组,也支持切片操作:

# In[19]:


a = np.array([[0,1,2,3,4,5],[10,11,12,13,14,15],[20,21,22,23,24,25],[30,31,32,33,34,35],[40,41,42,43,44,45],[50,51,52,53,54,55]])
a


# 想得到第一行的第4和第5两个元素:

# In[20]:


a[0,3:5]


# 得到最后两行的最后两列:

# In[21]:


a[4:,4:]


# 得到第三列:

# In[22]:


a[:,2]


# 每一维都支持切片的规则,包括负索引,省略
#
# [lower:upper:step]

# 例如,取出3,5行的奇数列:

# In[25]:


a[2::2,::2]


# ### 切片是引用

# 切片在内存中使用的是引用机制

# In[40]:


a = np.array([0,1,2,3,4])
b = a[2:4]
print(b)


# 引用机制意味着,Python并没有为b分配新的空间来存储它的值,而是让b指向了a所分配的内存空间,因此,改变b会改变a的值:

# In[27]:


b[0] = 10
a


# 而这种现象在列表中并不会出现:

# In[28]:


a = [1,2,3,4,5]
b = a[2:4]
b[0] = 10
print(a)


# 这样做的好处在于,对于很大的数组,不用大量复制多余的值,节约了空间。
#
# 缺点在于,可能出现改变一个值改变另一个值的情况。
#
# 一个解决方法是使用copy()方法产生一个复制,这个复制会申请新的内存:

# In[30]:


a = np.array([0,1,2,3,4])
b = a[2:4].copy()
b[0] = 10
a


# ### 花式索引

# 切片只能支持连续或者等间隔的切片操作,要想实现任意位置的操作。需要使用花式索引 fancy slicing。

# ### 一维花式索引

# 与range函数类似,我们可以使用arange函数来产生等差数组。

# In[31]:


a = np.arange(0,100,10)
a


# 花式索引需要指定索引位置:

# In[33]:


index = [1,2,-3]
y = a[index]
print(y)


# 还可以使用布尔数组来花式索引:

# In[36]:


mask = np.array([0,2,2,0,0,1,0,0,1,0],dtype = bool)
mask


# mask必须是布尔数组,长度必须和数组长度相等。

# In[37]:


a[mask]


# ### 二维花式索引

# 对于二维花式索引,我们需要给定行和列的值:

# In[43]:


a = np.array([[0,1,2,3,4,5],[10,11,12,13,14,15],[20,21,22,23,24,25],[30,31,32,33,34,35],[40,41,42,43,44,45],[50,51,52,53,54,55]])
a


# 返回的是一条次对角线上的5个值。

# In[39]:


a[(0,1,2,3,4),(1,2,3,4,5)]


# 返回的是最后三行的1,3,5列。

# In[44]:


a[3:,[0,2,4]]


# 也可以使用mask进行索引:

# In[51]:


mask = np.array([1,0,1,0,0,1],dtype = bool)
a[mask,2]


# 与切片不同,花式索引返回的是原对象的一个复制而不是引用。

# ### “不完全”索引

# 只给定行索引的时候,返回整行:

# In[56]:


y = a[:3]
y


# 这时候也可以使用花式索引取出第2,3,5行:

# In[61]:


con = np.array([0,1,1,0,1,0],dtype = bool)
a[con]


# ### where语句
#
# ```python
# where(array)
# ```
# where函数会返回所有非零元素的索引。

# ### 一维数组
# 先看一维的例子:

# In[62]:


a = np.array([0,12,5,20])


# 判断数组中的元素是不是大于10:

# In[63]:


a>10


# 数组中所有大于10的元素的索引位置:

# In[64]:


np.where(a>10)


# 注意到where的返回值是一个元组。返回的是索引位置,索引[1,3]大于10的数
#
# 也可以直接用数组操作。

# In[65]:


a[a>10]


# In[66]:


a[np.where(a>10)]


# ## 2.数组类型

# 具体如下:
#
# |**基本类型**|**可用的Numpy类型**|**备注**|
# |-:|-:|-:|
# |布尔型|bool|占一个字节|
# |整型|int8,int16,int32,int64,int128,int|int跟C语言中long一样大|
# |无符号整型|uint8,uint16,uint32,uint64,uint128,uint|uint跟C语言中的unsigned long一样大|
# |浮点数|float16,float32,float|默认为双精度float64,longfloat精度大小与系统有关|
# |复数|complex64,complex128,complex,longcomplex|默认为complex128,即实部虚部都为双精度|
# |字符串|string,unicode|可以使用dtype=S4表示一个4字节字符串的数组|
# |对象|object|数组中可以使用任意值|
# |时间|datetime64,timedelta64||

# ### 类型转换

# In[71]:


a = np.array([1.5,-3],dtype = float)
a


# ### asarray 函数

# In[73]:


a = np.array([1,2,3])
np.asarray(a,dtype = float)


# ### astype方法
#
# astype 方法返回一个新数组:

# In[74]:


a = np.array([1,2,3])
a.astype(float)


# In[77]:


a #a本身并没有发生变化--拷贝


# ## 3.数组操作

# ### 我们以豆瓣10部高分电影为例

# In[2]:


##电影名称
mv_name = ["肖申克的救赎","控方证人","美丽人生","阿甘正传","霸王别姬","泰坦尼克号","辛德勒的名单","这个杀手不太冷","疯狂动物城","海豚湾"]


# In[3]:


##评分人数
mv_num = np.array([692795,42995,327855,580897,478523,157074,306904,662552,284652,159302])


# In[4]:


##评分
mv_score = np.array([9.6,9.5,9.5,9.4,9.4,9.4,9.4,9.3,9.3,9.3])


# In[5]:


##电影时长(分钟)
mv_length = np.array([142,116,116,142,171,194,195,133,109,92])


# ### 数组排序

# #### sort函数

# In[82]:


np.sort(mv_num)


# In[83]:


mv_num #sort不改变原来数组


# #### argsort函数
#
# argsort返回从小到大的排列在数组中的索引位置:

# In[84]:


order = np.argsort(mv_num)
order


# In[86]:


mv_name[order[0]]


# In[89]:


mv_name[order[-1]]


# ### 求和

# In[6]:


np.sum(mv_num)


# In[7]:


mv_num.sum()


# #### 最大值

# In[8]:


np.max(mv_length)


# In[10]:


mv_length.max()


# #### 最小值

# In[11]:


np.min(mv_score)


# In[12]:


mv_score.min()


# ### 均值

# In[13]:


np.mean(mv_length)


# In[14]:


mv_length.mean()


# ### 标准差

# In[15]:


np.std(mv_length)


# In[16]:


mv_length.std()


# ### 相关系数矩阵

# In[17]:


np.cov(mv_score,mv_length)


# ## 4.多维数组操作

# ### 数组形状

# In[18]:


a = np.arange(6)
a


# In[21]:


a.shape=(2,3)
a


# In[22]:


a.shape


# 与之对应的方法是reshape,但它不会修改原来数组的值,而是返回一个新的数组:

# In[23]:


a = np.arange(6)
a


# In[25]:


a.reshape(2,3)


# In[27]:


a #没变


# ### 转置

# In[29]:


a = a.reshape(2,3)
a


# In[30]:


a.T


# In[32]:


a.transpose() #只要没赋值给本身,a的数值不会变换


# ### 数组连接

# 有时候我们需要将不同的数组按照一定的顺序连接起来:
# concatenate((a0,a1,...,aN),axis = 0)

# 注意,这些数组要用()包括到一个元组中去。
# 除了给定的轴外,这些数组其他轴的长度必须是一样的。

# In[33]:


x = np.array([[0,1,2],[10,11,12]])
y = np.array([[50,51,52],[60,61,62]])
print(x.shape)
print(y.shape)


# 默认沿着第一维进行连接:

# In[37]:


z = np.concatenate((x,y))
z


# 沿着第二维进行连接:

# In[38]:


z = np.concatenate((x,y),axis = 1)
z


# 注意到这里x和y的形状是一样的,还可以将它们连接成三维的数组,但是concatenate不能提供这样的功能,不过可以这样:

# In[40]:


z = np.array((x,y))
z


# 事实上,Numpy提供了分别对应这三种情况的函数:
# * vstack
# * hstack
# * dstack

# In[41]:


np.vstack((x,y))


# In[42]:


np.dstack((x,y))


# ## 5.Numpy内置函数

# In[43]:


a = np.array([-1,2,3,-2])


# In[46]:


np.abs(a) #绝对值


# In[45]:


np.exp(a) #指数


# In[48]:


np.median(a) #中值


# In[49]:


np.cumsum(a) #累积和


# numpy的内置函数非常多,不需要死记,懂得查资料。
#
# https://blog.csdn.net/nihaoxiaocui/article/details/51992860?locationNum=5&fps=1

# ## 6.数组属性方法总结
#
# 课上只讲了一些常见的,其余感兴趣的同学可以自行学习。

# |**调用方法**|**作用**|
# |-:|-:|
# |**1**|**基本属性**|
# |a.dtype|数组元素类型float32,uint8,...|
# |a.shape|数组形状(m,n,o,...)|
# |a.size|数组元素数|
# |a.itemsize|每个元素占字节数|
# |a.nbytes|所有元素占的字节|
# |a.ndim|数组维度|
# |-|-|
# |**2**|**形状相关**|
# |a.flat|所有元素的迭代器|
# |a.flatten()|返回一个1维数组的复制|
# |a.ravel()|返回一个一维数组,高效|
# |a.resize(new_size)|改变形状|
# |a.swapaxes(axis1,axis2)|交换两个维度的位置|
# |a.transpose(* axex)|交换所有维度的位置|
# |a.T|转置,a.transpose()|
# |a.squeeze()|去除所有长度为1的维度|
# |-|-|
# |**3**|**填充复制**|
# |a.copy()|返回数组的一个复制|
# |a.fill(value)|将数组的元组设置为特定值|
# |-|-|
# |**4**|**转化**|
# |a.tolist()|将数组转化为列表|
# |a.tostring()|转换为字符串|
# |a.astype(dtype)|转换为指定类型|
# |a.byteswap(False)|转换大小字节序|
# |a.view(type_or_dtype)|生成一个使用相同内存,但使用不同的表示方法的数组|
# |-|-|
# |**5**|**查找排序**|
# |a.nonzero()|返回所有非零元素的索引|
# |a.sort(axis=-1)|沿某个轴排序|
# |a.argsort(axis=-1)|沿某个轴,返回按排序的索引|
# |a.searchsorted(b)|返回将b中元素插入a后能保持有序的索引值|
# |-|-|
# |**6**|**元素数学操作**|
# |a.clip(low,high)|将数值限制在一定范围内|
# |a.round(decimals=0)|近似到指定精度|
# |a.cumsum(axis=None)|累加和|
# |a.cumprod(axis=None)|累乘积|
# |-|-|
# |**7**|**约简操作**|
# |a.sum(axis=None)|求和|
# |a.prod(axis=None)|求积|
# |a.min(axis=None)|最小值|
# |a.max(axis=None)|最大值|
# |a.argmin(axis=None)|最小值索引|
# |a.argmax(axis=None)|最大值索引|
# |a.ptp(axis=None)|最大值减最小值|
# |a.mean(axis=None)|平均值|
# |a.std(axis=None)|标准差|
# |a.var(axis=None)|方差|
# |a.any(axis=None)|只要有一个不为0,返回真,逻辑或|
# |a.all(axis=None)|所有都不为0,返回真,逻辑与|