2.4.数组:array的应用
2.4.1.模块array
array
模块是python内置模块,直接导入即可.
import array as ar
array
译名为数组.顾名思义,array模块提供了一种新的数据类型array
,其特点是具有比列表更小的内存空间占用以及更高的运行速度,其他特征基本与list
相近.同样有index
remove
pop
insert
append
等方法,这里不再展开叙述.
但是! array数组中只能存储同一类型的数字,例如均为int
或均为str
等.在定义array时可以自定义其类型,又称d-type
,该数组中的所有元素都必须为该type,否则报错.d-type
可以是:
d-type | 数组内类型 |
---|---|
‘b’/‘B’/‘h’/‘H’/‘i’/‘I’/‘l’/‘L’/‘q’/‘Q’ | int |
‘f’/‘d’ | float |
‘u’ | unicode-character(str) |
一般其实int
和float
可以混用,但是需要进行一次解析化来改变类型.现在给出实例:
mylist1=[1,2,3]
myarray=ar.array('i',mylist1)
输出为
myarray: array(1,2,3)
这说明array数组可以直接通过array类创建,只需传入数组类型和原列表/元组即可.
2.4.2.数组维度、形状和大小
2.4.2.1.数组维度
先来看看列表维度.现在有列表:
l1=[[1,2,3],[2,4,6]]
arr1=ar.array('i',[1,2,3])
arr2=ar.array('i',[2,4,6])
如果画出来,那么应该是
∣
1
2
3
∣
|1\ \ \ \ \ \ \ \ 2\ \ \ \ \ \ \ \ 3|
∣1 2 3∣
∣
2
4
6
∣
|2\ \ \ \ \ \ \ \ 4\ \ \ \ \ \ \ \ 6|
∣2 4 6∣
一一对应.一共 两组.因此称它为二维列表.而数组的维度将在下一节(2.4.3)中提到.
2.4.2.2.数组形状
想要查看一个数组的形状,只需要使用shape()
函数.当然啦,因为纯array只能提供一维数组,因此只需要len()
函数就可以查看其长度.至于形状嘛…那还得是numpy!
2.4.3.数组的批量处理
2.4.3.1.numpy包的使用
首先,也是最重要的,先安装:(本教程基于新版1.21.6)
pip install numpy==1.21.6
然后引入import numpy as np
.
2.4.3.1.2.多维数组
在2.4.2.中,我们讲了普通的内置数组维度及大小.在numpy中则允许创建多重(即多维)数组,名称为ndarray
.在上一例中, 我们有了arr1和arr2,现在将它们重合:
arr3=np.numpy([arr1,arr2])
打印其大小:print(arr3.shape)
,为(2,3)
.这说明shape
值格式为tup(行数,列数)
.
2.4.3.1.3.自动数组
在2.2.3.中,我们提到了用迭代器创建一个列表[1,2,3,…30]:
lists=[i for i in range(1,31)]
如果希望将其转换为数组,那么需要:
new=np.array(lists)
而现在,numpy提供了linspace
函数来直接创建该数组:
arr=np.linspace(1,30,30,endpoint=True)
注意,endpoint实参默认为真.该参数为真时所创建的列表包含末位置,而为假时就同range
一样不包含末位置.它始终包含起始值.
第一个参数为起始值 , 第二个参数为末尾值. 第三个参数可不选,为 共计数量.起末值差除以共计数量等于两个相邻数之差.例如1-20取40个数,即1,1.5,2,2,5…
2.4.3.1.4.数组的批量操作
对于一个列表[1,2,3],如果我们希望每个数取平方成为[1,4,9],那么显然我们可以这样做:
result=[]
start=[1,2,3]
for i in start:
result.append(i**2)
但这无疑徒增了代码量.更有甚者,数组可不是直接按索引就能输出的.这又双叒叕增加了工作量!
因此numpy提供了一个可以直接对数组进行批量操作的方法,传入的第一个参数必须为ndarray,即数组.用法见下表:
方法名 | 用途 |
---|---|
np.power(array,n) | 对每一个数组中的数变为n次方 |
np.cos(array) | 对每一个数组中的数取余弦.sin/cos/tan/cot均同理. |
np.log(array) | 对每一个数组中的数取自然对数 |
np.log2(array) | 对每一个数组中的数取以2为底的对数 |
np.log10(array) | 对每一个数组中的数取以10为底的对数 |
np.sqrt(array) | 对每一个数组中的数开平方根 |
np.exp(array) | 对每一个数组中的数 n n n变为 e n e^n en |
对于非2/
e
e
e/10的底数的对数,可以利用换底公式
log
a
b
=
log
x
b
log
x
a
\log_{a}b=\dfrac{\log_{x}b}{\log_{x}a}
logab=logxalogxb
进行计算.而
N
A
N
\mathrm{NAN}
NAN表示null(不存在),
i
n
f
\mathrm{inf}
inf表示无穷大(
−
i
n
f
-\mathrm{inf}
−inf同理为负无穷大).
2.4.3.1.5 其他数组
由于numpy还有很多类型的数组,这里不再一一详细讲解.贴上一些常用的方法(部分复制自原文):
import numpy as np
a=np.arange(10,22) # 以10和21为起点和终点,创建一维连续整数数组
"""
[10 11 12 13 14 15 16 17 18 19 20 21]
"""
b=np.arange(10,22).reshape(3,4) # 以10和21为起点和终点,创建二维连续整数数组
"""
[[10 11 12 13]
[14 15 16 17]
[18 19 20 21]]
"""
c=np.arange(10,70).reshape(3,4,5) # 以10和69为起点和终点,创建三维连续整数数组
"""
[[[10 11 12 13 14]
[15 16 17 18 19]
[20 21 22 23 24]
[25 26 27 28 29]]
[[30 31 32 33 34]
[35 36 37 38 39]
[40 41 42 43 44]
[45 46 47 48 49]]
[[50 51 52 53 54]
[55 56 57 58 59]
[60 61 62 63 64]
[65 66 67 68 69]]]
"""
import numpy as np
a=np.random.randint(10,100,6) # 在10到100范围内,创建一维随机整数数组
"""
[93 37 42 70 70 49]
"""
b=np.random.randint(10,100,(3,4)) # 在10到100范围内,创建二维随机整数数组
"""
[[99 31 58 89]
[73 30 13 70]
[58 86 85 27]]
"""
c=np.random.randint(10,100,(3,4,5)) # 在10到100范围内,创建三维随机整数数组
"""
[[[42 62 27 61 71]
[64 35 27 52 67]
[33 21 93 70 98]
[74 40 93 32 74]]
[[76 71 94 86 87]
[18 55 50 53 35]
[31 34 38 82 15]
[83 85 75 66 25]]
[[48 29 43 43 29]
[99 30 87 28 71]
[12 91 63 52 85]
[13 15 68 39 34]]]
"""
2.5.xlxs和csv:数据表(DataFrame)的前世今生
2.5.1.什么是数据表
在本教程中,我们已经多次的使用了表格来展示数据,例如上一页的numpy用法表格.在Python中,如果需要将两个数相互对应,那么自然会想到一个dict
字典,例如还是当时将类与对象的那张表格:
名称 | 年龄 | 工作岗位 | 工作时长·小时/天 | 性别 |
---|---|---|---|---|
A | 10 | student | 8 | F |
B | 20 | worker | 9 | M |
C | 30 | teacher | 12 | F |
先看A.按照字典,A应当这样写:
A={"age":10,"job":"worker","work_time":8,"sex":"F"}
如果需要进行储存,虽然这样也可行,但是如果我们希望将其像上表一样直观的一一对应的表现出来,就可以使用DataFrame(下文简称DF)
数据表进行储存.
先安装并导入pandas库:
#pip install pandas
import pandas as pd
然后通过pd.DataFrame
类直接创建DF数据表.
DF1=pd.DataFrame(A)
print(DF1)
报错:ValueError: If using all scalar values, you must pass an index
这是因为数据框的一列下只有一个数据且没有起始索引,有两种解决方式:
第一种,在创建DF1
对象时加入索引,即DF1=pd.DataFrame(A,index=[0])
.
第二种,将每一个value转为列表,即A={"age":[10],"job":["worker"],"work_time":[8],"sex":["F"]}
.
之后成功打印:
age job work_time sex
0 10 worker 8 F
现在向该数据框的源字典加入更多内容并制作数据表.
dic={"age":[10,20,30],"job":["student","worker","teacher"],"work_time":[8,9,12],"sex":["F","M","F"]}
DF2=pd.DataFrame(dic)
print(DF2)
打印结果:
age job work_time sex
0 10 student 8 F
1 20 worker 9 M
2 30 teacher 12 F
2.5.2.csv文件和其读取
在工作中,我们经常用到Excel来进行数据操作.举个栗子,刚刚这个数据表在Python中需要手动创建,但Excel提供了丰富的自动化工具和友善的可视化界面来大大优化用户体验.但如果面临着大量数据,内部自封闭的Excel就不再是首选,而是使用Python来实现操作.
我们都知道,Excel表格的后缀名为"*.xlsx".和word一样,其内部虽然格式并不多,但板式仍然占据了大量的空间.这对于存储不同数据产生了巨大的空间浪费.而"*.csv"格式则提供了一种纯字节式表格,每一行分别输入该行上每一列的数据,以逗号分割.还是上面那个表格,写入csv时它长这样:
age,job,work_time,sex
10,student,8,F
20,worker,9,M
30,teacher,12,F
其可以根据DF数据表来写入.直接调用DF类下封装好的to_csv
方法即可:
DF2.to_csv("example.csv")
既然能写入,也能读出.读出格式默认为DF:
DF3=pd.read_csv("example.csv")
如果纵向列较多,那么直接打印DF3时会只打印前5行和最后5行,当中以...
代替.如果希望打出完整的表格,需要使用to_string
方法,例如:
print(DF3.to_string())
如果数据量大,只读取头部n行,可以使用pd.head(n)
.n不写时默认为5.
如果只读取尾部n行,可以使用pd.tail(n)
.同样n默认为5.
上述两个方法与直接read_csv()
使用方法类似,均返回DF数据表.
如果需要将DF数据表转回字典,可以使用以下代码:
new_dict=DF3.to_dict(orient="list")
回到最开始的状态.(格式: {列名:[内容1,内容2,…],列名:[内容1,内容2,…],…})
2.6.第一个自己的包
2.6.1.Pypi官网
Pypi官网
我的项目(mml-qae)直达
Pypi官网是python官方提供的专业用户社区,可以很方便的让用户向其上传并公开自己制作的库/包并提供他人下载.基本所有库都只能也必须通过pypi来公开下载渠道.
2.6.2.pip原理
在初次配置之前,pip默认使用pypi官网下载,下载路径默认为www.pypi.org/project/item ,其中item为包名.但作为一个外国网站,虽说访问用不着VPN,但是外部下载确实慢.因此国内有着不少的pypi镜像提供,例如清华镜像,中科大镜像,豆瓣镜像,阿里云镜像等等.可以使用pip install -i 下载地址 包名
,详见 pip详细教程.
So,pip的原理是什么?很简单 通过网络基层socket向pypi发送请求,以其独有的header来请求tar.gz 包并解压至lis/site-packages/ 以实现调用.
2.6.3.setup.py&project.toml
在写完自己的库了以后,如果希望上传至pypi,那么需要这样的代码结构:
其中,dist文件夹和.egg-info文件夹不需要手动创建,在首次执行setup.py之后会自动生成.主文件夹mml-qae
为包名.其下必须有初始化文件__init__.py
来进行包初始化.在与主文件同级的文件夹下存放说明文档、setup.py和project.toml.有需要亦可以放入许可证.
在首次执行setup.py之前,结构应当是这样的:
setup.py和pyproject.toml格式如下:
setup.py:
import setuptools
setuptools.setup(
name='包的名称',
version='包的版本',
description='包的简介',
long_description='包的描述',
author='作者',
author_email='作者邮箱',
url='https://www.python.org',
packages=setuptools.find_packages(),
)
pyproject.toml:
[project]
name = "example_package_YOUR_USERNAME_HERE"
version = "0.0.1"
authors = [
{ name="Example Author", email="author@example.com" },
]
description = "A small example package"
readme = "README.md"
requires-python = ">=3.7"
classifiers = [
"Programming Language :: Python :: 3",
"License :: OSI Approved :: MIT License",
"Operating System :: OS Independent",
]
[project.urls]
"Homepage" = "https://github.com/pypa/sampleproject"
"Bug Tracker" = "https://github.com/pypa/sampleproject/issues"
记得替换其中的邮箱、许可证类型、版本、python要求、作者、简介等内容.
2.6.4.twine上传自己的包
在所有前置工作完成后,运行
python setup.py sdist
twine upload dist/生成的文件名(以.tar.gz结尾,格式为包名-版本.tar.gz)
第一步一般不会有所报错.如果报错请检查setup.py和project.toml格式.
第二步应当输入你的pypi账号名称和密码,如果没有先去注册.报错别慌,先复制到百度翻译看看啥意思.
如果提示上传错误,请检查你是否更改setup.py和project.toml中的版本(都要改),以及pypi上是否已经存在了同名的包,或者只是你的用户信息输错了!如果遇上twine/dong/requests等包的版本冲突,别急,看我这篇文章就行.
2.7.纯数视化:matplotlib的使用
从本节开始,我们正式进入数据科学的学习.
2.7.1.等形数组
在画图软件(例如Geogebra/几何画板/draw.io等)中,函数的绘制是依靠足够多的离散的数据点从而近似成一条光滑的曲线.在Python中也是同样如此.通过库来对近似曲线,或者直接绘制离散点.
对于每一个点
A
(
x
,
y
)
A(x,y)
A(x,y)都必须有且只有一个
x
x
x值和一个
y
y
y值与之对应.因为格式相同,因此一般都用上文讲过的DF数据表来存放离散点坐标.
2.7.2.不同的展示方法
注意先下载包:
pip install matplotlib
2.7.2.1.绘制连续函数
因为离散性的存在和像素的限制,我们永远不可能在电脑屏幕上画出一个绝对标准的函数(无论在哪里画都不可能绝对标准!).如果想画出一个非常近似的函数图像,我们可以取足够多的 x x x并通过numpy计算每一个 x x x对应的 y y y,并一一绘制.
import matplotlib.pyplot as plt
import numpy as np
X=np.linspace(-2*np.pi,2*np.pi,5000)#数量越多曲线越光滑
plt.plot(X,np.sin(X))
plt.show()#最后启动plot小窗
其他函数同理,只需要替换np.sin(X)
为其他一维、与X等形的数组即可.
2.7.2.2.离散点绘制
如果数据量不够多,或者要求就是分别绘制某一些点的位置,可以使用离散画图.
import matplotlib.pyplot as plt
import numpy as np
X=np.linspace(1,40,20)#数量越多曲线越光滑
Y=np.array((1,2,3,4,5,4,3,2,1,2,3,4,5,4,3,2,1,2,3,4))
plt.scatter(X,Y)
plt.show()#最后启动plot小窗
由于matplotlib内容极多,此处受篇幅限制,只讲到了简单函数和散点图绘制.具体教程可以看这一篇,更加具体.
从下一节(2.8)开始,我们进入数据结构与算法的学习.
课后作业
现在给定文件text.txt
,内容为:
特征组,目标组
1,5
2,10
3,15
4,20
5,25
6,30
7,35
8,40
9,45
10,50
将其读出并分别绘制由它们组成的散点图和函数图(
y
=
5
x
y=5x
y=5x).随后将这些数据变为数据表并复制进result.txt
.
作业上传地址:点我提交
作业将于第二章总结中给出答案.