🌻个人主页:相洋同学
🥇学习在于行动、总结和坚持,共勉!
#学习笔记#
Git-hub链接
题目列表(题解往下翻)
76.考虑一个一维数组Z,构建一个二维数组,其第一行为(Z[0],Z[1],Z[2]),每个后续行都向右移动1个位置(最后一行应为(Z[-3],Z[-2],Z[-1]))(★★★)
77.如何对一个布尔值取反,或者改变一个浮点数的符号?(★★★)
78.考虑两组点P0,P1描述的线(2D)和一个点p,如何计算点p到每条线i (P0[i],P1[i])的距离?(★★★)
79.考虑两组点P0,P1描述的线(2D)和一组点P,如何计算每个点j (P[j])到每条线i (P0[i],P1[i])的距离?(★★★)
80.考虑一个任意数组,编写一个函数提取一个固定形状的子部分,且以一个给定元素为中心(必要时用fill
值填充)(★★★)
81.考虑一个数组Z = [1,2,3,4,5,6,7,8,9,10,11,12,13,14],如何生成一个数组R = [[1,2,3,4], [2,3,4,5], [3,4,5,6], ..., [11,12,13,14]]?(★★★)
82.计算一个矩阵的秩(★★★)
83.如何找到数组中出现频率最高的值?
84.从一个随机的10x10矩阵中提取所有连续的3x3块(★★★)
85.创建一个2D数组子类,使得Z[i,j] == Z[j,i](★★★)
86.考虑一组p个形状为(n,n)的矩阵和一组p个形状为(n,1)的向量。如何一次性计算p个矩阵乘积的和?(结果的形状为(n,1))(★★★)
87.考虑一个16x16的数组,如何得到块求和(块大小为4x4)?(★★★)
88.如何使用numpy数组实现生命游戏?(★★★)
89.如何获取一个数组的n个最大值(★★★)
90.给定任意数量的向量,构建笛卡尔积(每个项的每种组合)(★★★)
91.如何从常规数组创建记录数组?(★★★)
92.考虑一个大向量Z,使用3种不同方法计算Z的三次方(★★★)
93.考虑两个形状为(8,3)和(2,2)的数组A和B。如何找到A的行,这些行包含B的每行的元素,不考虑B中元素的顺序?(★★★)
94.考虑一个10x3的矩阵,提取具有不等值的行(例如[2,2,3])(★★★)
95.将一个整数向量转换为矩阵的二进制表示形式(★★★)
96.给定一个二维数组,如何提取唯一的行?(★★★)
97.考虑2个向量A和B,编写内积、外积、求和和乘法函数的einsum等价形式(★★★)
98.考虑由两个向量(X,Y)描述的路径,如何使用等距样本对其进行采样?(★★★)
99.给定一个整数n和一个2D数组X,从X中选择可以解释为具有n度的多项式分布抽样的行,即,只包含整数且总和为n的行。(★★★)
100.对于一个1D数组X的平均值,计算其引导式95%置信区间(即,用替换的方式重采样数组元素N次,计算每个样本的平均值,然后计算平均值的百分位数)。(★★★)
题目解析
76.考虑一个一维数组Z,构建一个二维数组,其第一行为(Z[0],Z[1],Z[2]),每个后续行都向右移动1个位置(最后一行应为(Z[-3],Z[-2],Z[-1]))(★★★)
# 通过numpy库来解决,使用stride_tricks技巧
# np.lib.stride_tricks.as_strided函数允许我们在数组上使用给定的步长来创建新视图,而不实际复制数据
# 通过切片的方式也可以解决,但是这种方法会复制数据,对大数组来说效率较低。总体来说numpy就是为了高效计算而创建的
import numpy as np
from numpy.lib.stride_tricks import as_strided
vector = np.arange(10)
# [0,1,2,3,4,5,6,7,8,9]window_size = 3
shape = (len(vector) - window_size + 1, window_size) # output shape
strides = vector.strides + vector.strides #步长
result = as_strided(vector,shape = shape, strides=strides)
result
# array([[0, 1, 2],
# [1, 2, 3],
# [2, 3, 4],
# [3, 4, 5],
# [4, 5, 6],
# [5, 6, 7],
# [6, 7, 8],
# [7, 8, 9]])
77.如何对一个布尔值取反,或者改变一个浮点数的符号?(★★★)
# 取反
bool_arry = np.array([True, False, True, True, False])
negated_bool_arry = np.logical_not(bool_arry)
print(negated_bool_arry)
# 结果:[False True False False True]
78.考虑两组点P0,P1描述的线(2D)和一个点p,如何计算点p到每条线i (P0[i],P1[i])的距离?(★★★)
# 两种情况:有限长度的线段和无限直线
# 生成两组点
P0 = np.random.rand(10,2)
P1 = np.random.rand(10,2)
p = np.array([0,0])# 计算每个点到每条线的距离
def distance_point_to_line(P0,P1,p):# 计算线段方向向量d = P0 - P1# 计算p到每个P0的向量p0 = p - P0# 计算p在每条线段方向向量上的投影长度/向量d的长度t = np.sum(d*p0,axis=1)/np.sum(d*d,axis=1) # 代表了p0在d上投影的长度与d长度的比例# 将投影长度限制在0-1之间,以保证投影点在线段上t = np.clip(t,0,1).reshape(-1,1)# 计算投影点projection = P0 + t*d# 计算p到投影点的距离向量distance_vectors = p - projection# 计算并返回距离distance = np.sqrt(np.sum(distance_vectors*distance_vectors,axis=1))return distance
79.考虑两组点P0,P1描述的线(2D)和一组点P,如何计算每个点j (P[j])到每条线i (P0[i],P1[i])的距离?(★★★)
# 生成两组点
import numpy as np
P0 = np.random.rand(10,2)
P1 = np.random.rand(10,2)
P = np.random.rand(10,2)
def distance_point_to_line(P0,P1,P):# 计算线段方向向量d = P0 - P1# 计算p到每个P0的向量p0 = P - P0# 计算p在每条线段方向向量上的投影长度/向量d的长度t = np.sum(d*p0,axis=1)/np.sum(d*d,axis=1) # 代表了p0在d上投影的长度与d长度的比例# 将投影长度限制在0-1之间,以保证投影点在线段上t = np.clip(t,0,1).reshape(-1,1)# 计算投影点projection = P0 + t*d# 计算p到投影点的距离向量distance_vectors = P - projection# 计算并返回距离distance = np.sqrt(np.sum(distance_vectors*distance_vectors,axis=1))return distance
80.考虑一个任意数组,编写一个函数提取一个固定形状的子部分,且以一个给定元素为中心(必要时用
fill
值填充)(★★★)
def extract_subarray_with_fill(arr, shape, center, fill=0):"""从一个给定数组中提取一个以特定元素为中心的固定形状的子数组。如果子数组超出原数组的边界,则使用fill值进行填充。参数:- arr: 原始数组。- shape: 目标子数组的形状(tuple)。- center: 子数组中心元素的索引(tuple)。- fill: 用于填充超出边界部分的值。返回:- 提取(并可能填充)后的子数组。"""r, c = shapex, y = centerr_half, c_half = r // 2, c // 2start_x, start_y = max(0, x - r_half), max(0, y - c_half)end_x, end_y = min(arr.shape[0], x + r_half + 1), min(arr.shape[1], y + c_half + 1)extracted = arr[start_x:end_x, start_y:end_y]if extracted.shape != shape:# 创建填充数组filled = np.full(shape, fill, dtype=arr.dtype)# 计算填充偏移offset_x, offset_y = -min(0, x - r_half), -min(0, y - c_half)filled[offset_x:offset_x+extracted.shape[0], offset_y:offset_y+extracted.shape[1]] = extractedreturn filledreturn extracted# 示例使用
arr = np.random.randint(1, 10, size=(5, 5))
shape = (3, 3)
center = (1, 1)
fill = 0subarray = extract_subarray_with_fill(arr, shape, center, fill)
print(subarray)
81.考虑一个数组Z = [1,2,3,4,5,6,7,8,9,10,11,12,13,14],如何生成一个数组R = [[1,2,3,4], [2,3,4,5], [3,4,5,6], ..., [11,12,13,14]]?(★★★)
# 同第76题使用滑动窗口
from numpy.lib.stride_tricks import as_strided
vector = np.arange(1, 15)
# [1,2,3,4,5,6,7,8,9,10,11,12,13,14]window_size = 4
shape = (len(vector) - window_size + 1, window_size) # output shape
strides = vector.strides + vector.strides #步长
result = as_strided(vector,shape = shape, strides=strides)
result
# 1,2,3,4
# 2,3,4,5
# 3,4,5,6
# 4,5,6,7
# 5,6,7,8
# 6,7,8,9
# 7,8,9,10
# 8,9,10,11
# 9,10,11,12
# 10,11,12,13
# 11,12,13,14
82.计算一个矩阵的秩(★★★)
# 定义一个矩阵
A = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])# 计算矩阵的秩
rank = np.linalg.matrix_rank(A)print("矩阵的秩是:", rank)
83.如何找到数组中出现频率最高的值?(★★★)
# 示例数组
arr = np.array([1, 2, 3, 4, 5, 1, 2, 1, 1, 2, 2, 2, 3])# 对于非负整数数组
if arr.min() >= 0 and np.issubdtype(arr.dtype, np.integer):counts = np.bincount(arr)most_frequent = np.argmax(counts)
else:# 对于其他类型的数组,包括负数和浮点数values, counts = np.unique(arr, return_counts=True)most_frequent = values[np.argmax(counts)]print("出现频率最高的值是:", most_frequent)
84.从一个随机的10x10矩阵中提取所有连续的3x3块(★★★)
# 要从一个给定的10x10矩阵中提取所有连续的3x3块,可以使用stride_tricks模块中的as_strided函数来有效地实现。通过这种方式,我们可以创建一个新的视图来表示每个3x3的块,而无需复制数据。
from numpy.lib.stride_tricks import as_strided# 创建一个随机的10x10矩阵
matrix = np.random.rand(10, 10)# 提取所有3x3块
block_shape = (3, 3)
blocks = as_strided(matrix, shape=(8, 8, 3, 3), strides=matrix.strides + matrix.strides)print("所有连续的3x3块:")
print(blocks)
85.创建一个2D数组子类,使得Z[i,j] == Z[j,i](★★★)
class Symmetric2DArray(np.ndarray):def __setitem__(self, index, value):# 调用基类的__setitem__来设置值super().__setitem__(index, value)# 设置对称元素的值,以保持数组的对称性if isinstance(index, tuple) and len(index) == 2:super().__setitem__((index[1], index[0]), value)def symmetric_array(shape, dtype=float, buffer=None, offset=0, strides=None, order=None):# 使用np.ndarray来创建数组的实例,然后将其视为Symmetric2DArrayreturn np.ndarray(shape, dtype, buffer, offset, strides, order).view(Symmetric2DArray)# 创建一个5x5的对称数组
Z = symmetric_array((3, 3))
Z[0, 1] = 1print(Z)
86.考虑一组p个形状为(n,n)的矩阵和一组p个形状为(n,1)的向量。如何一次性计算p个矩阵乘积的和?(结果的形状为(n,1))(★★★)
# 示例数据
p, n = 3, 4 # 假设有3个4x4矩阵和3个4x1向量
matrices = np.random.rand(p, n, n) # p个n x n矩阵
vectors = np.random.rand(p, n, 1) # p个n x 1向量# 计算p个矩阵乘积的和
# 使用np.einsum进行计算
result = np.einsum('ijk,ikl->jl', matrices, vectors)print("最终结果的形状为:", result.shape)
print(result)
87.考虑一个16x16的数组,如何得到块求和(块大小为4x4)?(★★★)
# 创建一个16x16的随机数组
arr = np.random.rand(16, 16)# 对数组进行块求和(块大小为4x4)
# 我们将使用reshape和sum操作来完成这个任务# 步骤1: 将数组重构为(4, 4, 4, 4),这样每个4x4的块都是独立的
# 步骤2: 对重构后的数组沿着最后两个维度求和,以获得每个块的总和
# 步骤3: 最终得到一个4x4的数组,每个元素代表原始数组中对应4x4块的总和
block_sum = arr.reshape(4, 4, 4, 4).sum(axis=(2, 3))print("块求和的结果为:")
print(block_sum)
88.如何使用numpy数组实现生命游戏?(★★★)
# 康威的生命游戏是一个经典的细胞自动机,其规则简单但能产生复杂的行为。在生命游戏中,每个细胞可以处于活着(1)或死亡(0)两种状态之一,细胞的状态由其周围的8个细胞在上一代中的状态决定。具体规则如下:
#
# 生存:如果一个活细胞周围有2或3个活细胞,该细胞在下一代中保持活着。
# 死亡:如果一个活细胞周围的活细胞少于2个或多于3个,该细胞在下一代中死亡。
# 繁殖:如果一个死细胞周围正好有3个活细胞,该细胞在下一代中变为活细胞。
# 使用NumPy数组实现生命游戏,我们可以利用卷积操作来计算每个细胞周围的活细胞数量。
import numpy as np
from scipy.signal import convolve2d
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
from IPython.display import HTML
%matplotlib notebook
def life_step(X):"""执行生命游戏的一步"""kernel = np.array([[1, 1, 1],[1, 0, 1],[1, 1, 1]])neighbors = convolve2d(X, kernel, mode='same', boundary='wrap')return (neighbors == 3) | (X & (neighbors == 2))# 初始化游戏状态
np.random.seed(0)
X = np.random.randint(0, 2, (100, 100))fig, ax = plt.subplots()
img = ax.imshow(X, cmap='binary', interpolation='nearest')
ax.axis('off') # 不显示坐标轴def update(frame):global XX = life_step(X)img.set_data(X)return img,# 创建动画
ani = FuncAnimation(fig, update, frames=10, blit=True)plt.show()
效果如下:
89.如何获取一个数组的n个最大值(★★★)
arr = np.array([1, 3, 2, 4, 5])
n = 3# 使用np.partition获取n个最大值
partitioned_arr = np.partition(arr, -n)[-n:]
print("使用np.partition得到的N个最大值:", partitioned_arr)# 如果你也需要这些值的索引,可以这样做
indices = np.argpartition(arr, -n)[-n:]
print("使用np.partition得到的N个最大值的索引:", indices)
90.给定任意数量的向量,构建笛卡尔积(每个项的每种组合)(★★★)
def cartesian_product(*arrays):la = len(arrays)dtype = np.result_type(*arrays)arr = np.empty([len(a) for a in arrays] + [la], dtype=dtype)for i, a in enumerate(np.ix_(*arrays)):arr[...,i] = areturn arr.reshape(-1, la)# 示例向量
vectors = [np.array([1, 2]), # 第一个向量np.array([4, 5]), # 第二个向量np.array([7, 8]) # 第三个向量
]# 构建笛卡尔积
result = cartesian_product(*vectors)print("笛卡尔积:\n", result)
# 笛卡尔积:
# [[1 4 7]
# [1 4 8]
# [1 5 7]
# [1 5 8]
# [2 4 7]
# [2 4 8]
# [2 5 7]
# [2 5 8]]
91.如何从常规数组创建记录数组?(★★★)
# 假设我们有以下数据(两列,一列是整数,另一列是浮点数)
data = np.array([(1, 2.5), (3, 4.5), (5, 6.5)])# 创建记录数组
rec_array = np.array(data, dtype=[('col1', int), ('col2', float)])# 现在rec_array是一个记录数组,我们可以通过列名访问数据
print(rec_array['col1']) # 输出第一列数据
print(rec_array['col2']) # 输出第二列数据
92.考虑一个大向量Z,使用3种不同方法计算Z的三次方(★★★)
# 方法1:使用Z**3
Z = np.array([1, 2, 3, 4, 5]) # 示例向量
result1 = Z ** 3
# 方法2:使用np.power(Z, 3)
result2 = np.power(Z, 3)
# 方法3:使用Z*Z*Z
result3 = Z * Z * Z
print("使用**运算符:", result1)
print("使用np.power函数:", result2)
print("使用元素级乘法:", result3)
# 使用**运算符: [ 1 8 27 64 125]
# 使用np.power函数: [ 1 8 27 64 125]
# 使用元素级乘法: [ 1 8 27 64 125]
93.考虑两个形状为(8,3)和(2,2)的数组A和B。如何找到A的行,这些行包含B的每行的元素,不考虑B中元素的顺序?(★★★)
A = np.array([[1, 2, 3],[4, 5, 6],[7, 8, 9],[10, 11, 12],[13, 14, 15],[16, 17, 18],[19, 20, 21],[22, 23, 24]])B = np.array([[2, 3],[11, 12]])# 初始化一个空列表来存储每个B中行的结果
rows_for_b = []# 对于B中的每一行
for b_row in B:# 对于A中的每一行rows_with_b_elements = []for i, a_row in enumerate(A):# 如果A中的这一行包含B中当前行的任意元素if np.any(np.isin(b_row, a_row)):rows_with_b_elements.append(i)rows_for_b.append(rows_with_b_elements)print("对于B中的每一行,在A中找到的包含B元素的行索引:")
for i, rows in enumerate(rows_for_b):print(f"B中的第{i}行对应的A中的行索引:{rows}")
94.考虑一个10x3的矩阵,提取具有不等值的行(例如[2,2,3])(★★★)
# 创建一个10x3的随机矩阵,为了示例明显性,这里使用整数
np.random.seed(0) # 确保示例的可重复性
matrix = np.random.randint(0, 5, size=(10, 3))print("原始矩阵:")
print(matrix)# 提取具有不等值的行
# 我们可以通过比较每一行的最大值和最小值来实现,如果最大值不等于最小值,则该行具有不等值
unique_rows = matrix[matrix.max(axis=1) != matrix.min(axis=1)]print("具有不等值的行:")
print(unique_rows)
95.将一个整数向量转换为矩阵的二进制表示形式(★★★)
# 示例整数向量
vector = np.array([3, 10, 15])# 确定二进制表示需要的最大长度
max_length = np.max(np.floor(np.log2(vector)).astype(int) + 1)# 将每个整数转换为二进制表示,并填充到相同长度
binary_matrix = np.array([list(np.binary_repr(v, width=max_length)) for v in vector], dtype=int)print("二进制表示矩阵:")
print(binary_matrix)
96.给定一个二维数组,如何提取唯一的行?(★★★)
# 示例二维数组
array = np.array([[1, 2, 3],[4, 5, 6],[1, 2, 3],[7, 8, 9]])# 提取唯一的行
unique_rows = np.unique(array, axis=0)print("唯一的行:")
print(unique_rows)
97.考虑2个向量A和B,编写内积、外积、求和和乘法函数的einsum等价形式(★★★)
A = np.array([1, 2, 3])
B = np.array([4, 5, 6])# 使用einsum计算内积
dot_product = np.einsum('i,i->', A, B)
print("内积:", dot_product)
# 使用einsum计算外积
outer_product = np.einsum('i,j->ij', A, B)
print("外积:\n", outer_product)
# 使用einsum计算A的求和
sum_A = np.einsum('i->', A)
print("A的求和:", sum_A)
# 使用einsum计算元素乘法
elementwise_multiplication = np.einsum('i,i->i', A, B)
print("元素乘法:", elementwise_multiplication)
# 内积: 32
# 外积:
# [[ 4 5 6]
# [ 8 10 12]
# [12 15 18]]
# A的求和: 6
# 元素乘法: [ 4 10 18]
98.考虑由两个向量(X,Y)描述的路径,如何使用等距样本对其进行采样?(★★★)
import numpy as np
from scipy.interpolate import interp1d# 假设X和Y描述的路径
X = np.array([0, 1, 2, 3, 4, 5])
Y = np.array([0, 1, 0, 1, 0, 1])# 计算每一步的距离
dX = np.diff(X)
dY = np.diff(Y)
dist = np.sqrt(dX**2 + dY**2)# 计算累积距离
cumulative_dist = np.insert(np.cumsum(dist), 0, 0)# 插值
interp_X = interp1d(cumulative_dist, X, kind='linear')
interp_Y = interp1d(cumulative_dist, Y, kind='linear')# 等距采样
num_samples = 20 # 采样点数
sample_points = np.linspace(0, cumulative_dist[-1], num_samples)
sampled_X = interp_X(sample_points)
sampled_Y = interp_Y(sample_points)
99.给定一个整数n和一个2D数组X,从X中选择可以解释为具有n度的多项式分布抽样的行,即,只包含整数且总和为n的行。(★★★)
import numpy as np# 示例数据
X = np.array([[1, 2, 2],[2, 2, 2],[3, 3, 1],[4, 4, 1]])
n = 6 # 给定的总和# 检查每个元素是否为整数
is_integer = np.all(X == np.floor(X), axis=1) # 或使用其他方法检查整数性# 计算每行的元素之和,并检查是否等于n
sum_to_n = np.sum(X, axis=1) == n# 结合两个条件,选择满足条件的行
rows_meeting_criteria = X[np.logical_and(is_integer, sum_to_n)]print("满足条件的行:")
print(rows_meeting_criteria)
100.对于一个1D数组X的平均值,计算其引导式95%置信区间(即,用替换的方式重采样数组元素N次,计算每个样本的平均值,然后计算平均值的百分位数)。(★★★)
import numpy as np# 示例1D数组
X = np.random.normal(0, 1, 100) # 假设X是从标准正态分布中抽取的100个样本
N = 1000 # 重采样次数# 存储每次重采样的平均值
resampled_means = np.empty(N)# 重采样并计算平均值
for i in range(N):resampled = np.random.choice(X, size=X.size, replace=True) # 重采样resampled_means[i] = np.mean(resampled) # 计算平均值# 计算95%置信区间
lower_percentile = np.percentile(resampled_means, 2.5)
upper_percentile = np.percentile(resampled_means, 97.5)print(f"95%置信区间: ({lower_percentile}, {upper_percentile})")
100题完结
以上
学习在于行动,总结和坚持,共勉