【Numpy】练习题100道(76-100题完结)

🌻个人主页:相洋同学
🥇学习在于行动、总结和坚持,共勉!

#学习笔记#

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 = shape
    x, y = center
    r_half, c_half = r // 2, c // 2

    start_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]] = extracted
        return filled
    return extracted

# 示例使用
arr = np.random.randint(1, 10, size=(5, 5))
shape = (3, 3)
center = (1, 1)
fill = 0

subarray = 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来创建数组的实例,然后将其视为Symmetric2DArray
    return np.ndarray(shape, dtype, buffer, offset, strides, order).view(Symmetric2DArray)

# 创建一个5x5的对称数组
Z = symmetric_array((3, 3))
Z[0, 1] = 1

print(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 X
    X = 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] = a
    return 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题完结

以上

学习在于行动,总结和坚持,共勉

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值