Python程序设计 实验8:Numpy 和标准库
Posted 上山打老虎D
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python程序设计 实验8:Numpy 和标准库相关的知识,希望对你有一定的参考价值。
Python程序设计 实验8:Numpy 和标准库
实验过程及内容(实验思路,代码实现过程以及运行并测试结果):
1. Numpy 基础:
运行以下代码,理解每句代码的意思或输出结果(print 语句):
(a)
mysqrt = [math.sqrt(x) for x in range(0,5)]
mycrt = [x**(1/3) for x in range(0,5)]
npData = np.array(mysqrt)
print(“The shape:”, npData.shape)
print(“The dimensionality:”, npData.ndim)
print(“The type:”, npData.dtype)
twoDarray = np.array([mysqrt, mycrt])
print(“The shape:”, twoDarray.shape)
print(“The dimensionality:”, twoDarray.ndim)
print(“The type:”, twoDarray.dtype)
【代码解释】
-
npData.shape:shape函数的功能是查看矩阵或者数组的维数。
-
npData.ndim:ndim函数的功能是查看数组中每个元素的维数。
-
npData.dtype:dtype函数的功能是查看该数组中每个元素的数据类型。
因此,对于npData = np.array(mysqrt)数组的维数是5,每个元素是单独的浮点型数,因此每个元素的维数是1.又因为每个元素是浮点型小数,因此数据类型是float64。
同理,对于twoDarray = np.array([mysqrt,mycrt])数组的维数是2*5,每个元素是两个浮点型数组成的元组,因此每个元素的维数是2.又因为每个元素是浮点型小数,因此数据类型是float64。
【运行结果】
(b)
zeros = np.zeros(3)
zMat = np.zeros((4,3))
ones = np.ones(3)
oMat = np.ones((3,2))
diag = np.eye(4)
rng = np.arange(5)
dm = np.diag(rng)
print(dm.shape)
zMat_re = zMat.reshape(6,2)
【代码解释】
通过分析代码,可知最终起作用的代码只有如下三行的部分:
-
numpy.arange(start, stop, step, dtype = None)在给定间隔内返回均匀间隔的值。值在半开区间 [开始,停止]内生成(换句话说,包括开始但不包括停止的区间),返回的是 ndarray 。
-
np.diag()以一维数组的形式返回方阵的对角线(或非对角线)元素,或将一维数组转换成方阵(非对角线元素为0)
-
因此首先生成了一个数组[0,1,2,3,4],然后以这个数组为对角线生成了一个5*5的矩阵,再调用函数打印矩阵的维数,因此将输出(5,5)
【运行结果】
( c )
A = np.random.randint(0,10, size = (3,2))
B = np.random.randint(0,10, size = (3,3,3))
C = np.random.randint(0,10, size = (3,1))
print(A**2)
print(np.sqrt(A))
print(A + C)
print(B + C)
B[:, 0:2 , 0:2 ] -= 20
print(B)
【代码解释】
-
np.random.randint(a,b, size)表示生成范围在a~b内的,维度为size的矩阵。
-
A**2表示将A中的每个元素平方。
-
np.sqrt(A)表示将A中的每个元素开平方。
-
A + C、B + C:表示将两个矩阵相加,将两个矩阵对应相加,当遇到两矩阵大小不一样的情况,两个矩阵的shape必须满足若干个小矩阵可以组成与大矩阵同大小的矩阵。此时,将小矩阵中的元素对应地加到大矩阵上。
-
B[:, 0:2 , 0:2 ] -= 20:通过切片选择第一维的全部,第二维的前两行,第三维的前两列中的每个元素各减20。
【运行结果】
- 由于本题中使用了随机数生成数据,因此本题的数据具有偶然性。本次运行结果只对如下生成的A、B、C三个数据:
- A**2
- numpy.sqrt(A)
- A + C
- B + C
- B[:, 0:2 , 0:2 ] -= 20
(d)
from numpy import linalg
A = np.array([[2, 1, -2],[1,-1,-1], [1, 1 ,3]])
b = np.array([3, 0, 12])
x = linalg.solve(A,b)
print(x)
【代码解释】
-
首先创建了两个数组。
-
solve函数有两个参数a和b。a是一个N*N的二维数组,而b是一个长度为N的一维数组,solve函数找到一个长度为N的一维数组x,使得a和x的矩阵乘积正好等于b,数组x就是多元一次方程组的解。
【运行结果】
2. Numpy 应用 1:
给定一个矩阵 2n×2n,将该矩阵分成四个象限(参见示例),然后返回一个新的 2×2 矩阵,包含每个象限的平均值。
例子:
原矩阵:
新矩阵:
【解题思路】
对于本题,由于前面第一题已经介绍了切片,获取矩阵维度以及获取矩阵部分的累加和的方法,本题中可以直接使用。可以首先获取矩阵的维度,从而获取结果矩阵中的4个数分别与原矩阵的四个象限的对应关系。再通过切片选定区域后,使用sum进行求和,最后再除以维度即可。
【编程实现】
import numpy
# 获取初始矩阵
matrix1 = numpy.array(
[[1, 2, 5, 7], [4, 1, 8, 0], [2, 0, 5, 1], [0, 2, 1, 1]])
# 获得矩阵维度
n = (int)(matrix1.shape[0]/2)
# 进行切片分割
res = numpy.array(
[[matrix1[:n, :n].sum()/(n**2), matrix1[:n, n:].sum()/(n**2)], [matrix1[n:, :n].sum()/(n**2), matrix1[n:, n:].sum()/(n**2)]])
print(res)
首先利用shape函数获取矩阵的维度,并除以二获得四个象限的分界点。然后通过切片获取每个象限并求和。最后将每个象限的和除以象限中元素个数(n^2)即为平均值,然后再利用array函数将四个平均值转成数组的形式。
【运行测试】
3. Numpy 应用 2:
仿照课件中利用 numpy 处理图片的方法,选择一张自己喜欢的图片进行处理,方法不限(如调整亮度、彩色变黑白、模糊化等等;鼓励自学图片处理方法,提出自己的方法)。
【解题思路】
在本题中,我使用隔行取样对图片进行了压缩。当我们遇到图片需要压缩的情况,常常可以想到进行隔行取样的方法,完成对图片的压缩。
【编程实现】
# 引入所需的库
import numpy as np
import matplotlib.pyplot as plt
from PIL import Image
# 打开图片文件
image = Image.open('test.jpg')
# 将图片转成矩阵表示
image_array = np.array(image)
# 进行图片压缩
image_array1 = image_array[::2, ::2, ]
# 展示图片
plt.imshow(image_array1)
plt.show()
首先打开图片文件,转成矩阵之后,采用切片进行隔行取样,此处需注意,隔行的值不能太大,否则图像会严重失真。取样后直接输出结果即可。
【运行测试】
原图:
压缩后的图:
可以看到,图片被压缩了。被压缩的图片比压缩前模糊了。
4. Python 标准库 itertools:
编写函数 sum0(lst),接受一个包含 8 个整数的列表lst。如果列表中的某些非空子集的总和返回 0,则返回 True。例如,lst=[-3, 11, 21, 5, 10, 11, 2, 1]返回 True,因为非空子集[-3, 2, 1]中数字加起来总和为 0;又如 lst=[2, 3, 4, 5, 6, 7, 8, 9]时,函数返回 False。
【解题思路】
首先,本题中需要完成的是对所有组合情况的累加和检查,因此需要获得所有组合情况。我们不妨利用itertools中的combinations获取确定长度下的组合的迭代器并对部分和进行判断,再利用一层循环对组合长度进行遍历。
【编程实现】
import itertools
# 定义判定是否存在组合为0函数
def sum0(lst):
# 获取不同长度的组合
for num in range(1, 9):
# 获取相同长度下的不同组合迭代器
it = itertools.combinations(lst, num)
# 遍历判断是否和为0
for i in it:
if sum(i) == 0:
return True
return False
lst = [1, 2, 3, 4, 5, 6, 7, -28]
print(sum0(lst))
首先利用外层循环遍历每次获得的组合的长度,然后对于每个确定的长度通过itertools.combinations获取全部组合的迭代器,然后再利用一层循环遍历整个迭代器判断部分和是否为零,如果为零直接返回True。如果遍历完所有长度的所有组合后都没有部分和为零则返回False。
【运行测试】
当存在部分和为0时:
当不存在部分和为0时:
5. Python 标准库 datetime:
编写函数 calculate_age,计算自出生以来到目前为止,生活的总天数,总月数,总年数,返回元组(days,months,years);
【解题思路】
可以通过datetime获取当前时间并与自己的生日做差,将时间差转换为天数,然后再一次转换为对应的总年月日数。
【编程实现】
import datetime
# 定义计算年龄函数
def calculate_age():
# 将生日转为datetime
birthday = datetime.datetime(2000, 9, 28)
# 获取datetime当前时间
cur = datetime.datetime.now()
# 获得日期差
during_days = (cur-birthday).days
# 获得对应年月日
return(during_days, (int)(during_days/30), (int)(during_days/365))
print(calculate_age())
首先获取当前时间并将自己的生日转为datetime类,并直接做差获得日期差,再利用日期差,获得对应的年月日的差并转为元组。
【运行测试】
6. Python 标准库 collections, sys, os: 统计目前写过的 python 代码。
(1) 把实验、作业、小测的代码文件整理好,分开放在“作业”文件夹、“实验”文件夹、“小测”文件夹,三个文件夹放到同一个文件夹“代码”中。
【解题思路】
按照要求整理对应文件即可:
【结果如下】
(2) 编写函数,统计“代码”文件夹中 python 文件的个数(file_num),写过的代码行数( code_line ),代码中空行的行数 ( space_lines ),注释的行数 (comments_lines,只统计以#开头的),返回元组记录上述信息。
【解题思路】
通过最外层循环遍历代码文件夹下的三个文件夹,对于每个文件夹,再使用一层循环遍历文件夹中的每个文件,对于每个文件,首先判断拓展名是不是‘.py’如果不是则继续下一个文件的判断。如果是,则按行读入文件,每读入一行,行计数器加一。对于每一行,分别进行空行与注释的判断,满足则对应计数器加一。当所有文件都判断完毕后,直接返回结果元组即可。
【编程实现】
import collections
import sys
import os
def getInfo(path):
# path = './code'
# 定义各个计数器
file_num = 0
code_line = 0
space_lines = 0
comments_lines = 0
# 对文件路径非法情况进行特判
if not os.path.exists(path):
print('Invalid Path!')
return
# 首先遍历“作业”文件夹、“实验”文件夹、“小测”文件夹
for i in os.listdir(path):
# 遍历各个文件夹中的每个文件
for j in os.listdir(path+'/'+i):
# 如果是Python文件,则对应计数器加一
if j.endswith('.py'):
file_num += 1
# 按行读入Python文件
for line in open(path+'/'+i+'/'+j, encoding='utf-8'):
# 对于每行 对应计数器加一
code_line += 1
# 如果为空行 则空行计数器加一
if line == "\\n":
space_lines += 1
# 如果为注释 则注释计数器加一
if line.startswith('#'):
comments_lines += 1
# 返回结果元组
return(file_num, code_line, space_lines, comments_lines)
print(getInfo('./code'))
首先判断路径的合法性,当出现非法路径,则直接给出错误信息并返回。对于合法的路径,通过外层循环遍历三个文件夹,再通过一层循环遍历各个文件。对于每个文件,首先判断文件的拓展名是否为‘.py’,如果不是则判断下一个,如果是,则按行将文件读入,再对每行进行空行和注释的判断。当处理完所有文件后,将结果以元组的形式返回。
【运行测试】
(3) 在(2)基础上,允许用户输入指定的文件或文件夹,统计输入文件或文件夹的信息。例如,假设 python 文件名为 code_stat.py,运行方法如下:
【解题思路】
与(2)思路大致相同,只需加入对路径或文件的判断即可,在此处,我使用os.path.isdir(path)和os.path.isfile(path)完成对路径或文件的判断。
【编程实现】
import collections
import sys
import os
def getInfo(path):
# path = './code'
file_num = 0
code_line = 0
space_lines = 0
comments_lines = 0
if not os.path.exists(path):
print('Invalid Path!')
return
# 如果是路径
if os.path.isdir(path):
for j in os.listdir(path):
if j.endswith('.py'):
file_num += 1
for line in open(path+'/'+j, encoding='utf-8'):
code_line += 1
if line == "\\n":
space_lines += 1
if line.startswith('#'):
comments_lines += 1
# 如果是Python文件
elif os.path.isfile(path) and path.endswith('.py'):
file_num += 1
for line in open(path, encoding='utf-8'):
code_line += 1
if line == "\\n":
space_lines += 1
if line.startswith('#'):
comments_lines += 1
return(file_num, code_line, space_lines, comments_lines)
print(getInfo('./code/Homework'))
大致思路与(2)相同,区别只是对传入的路径进行了判断,如果是路径,则依次遍历路径中的文件进行统计;如果是文件,则直接读取文件进行统计。
【运行测试】
对路径的测试:
对文件的测试:
实验结论:
在本次实验中,我学习并学会了Numpy库的一些函数的使用方法,与之前学过的C++相比,Python多元化的库为Python处理更多数据提供了良好的技术支持。Numpy库中涵盖广泛,可以处理矩阵,线性代数等,也可以处理图片。这些都方便了我使用Python完成对数据的进一步处理。
我也学会了使用Python的标准库itertools,datetime,collections, sys,和os这些都很大程度上方便了编程。
此外,在本次实验过程中,我也遇到了一些问题:
-
在完成对图片的处理时调用了image.shape结果抛出异常。在查阅资料后发现这是读取的图片格式和PIL中Image 读取的图片格式差异问题导致的,解决方法就是在save操作之前,将图片的格式转化一下即可解决问题。
-
在完成第6题读入Python代码文件时,抛出如下异常:
通过查阅资料发现,发生该异常的原因是编码格式不是Python可以读取的格式,只需在读入的地方加上“encoding=utf-8”即可。
此外,在本次实验中我发现,代码的容错性也是编程过程中需要注意的点。在进行实验六的过程中,多次由于路径不对造成异常的发生,因此需要在程序执行前加入判断语句,对路径有效性进行检验。
以上是关于Python程序设计 实验8:Numpy 和标准库的主要内容,如果未能解决你的问题,请参考以下文章