`zeros_like()`, `ones_like()`, `empty_like()`:基于现有数组创建

好的,各位观众老爷,各位技术大咖,欢迎来到今天的“NumPy魔法屋”!今天我们要聊的是NumPy里三位“影子忍者”:zeros_like(), ones_like(), 和 empty_like()。这三位哥们儿啊,他们的看家本领就是——基于现有数组,克隆!但是,克隆的方式嘛,那可是各有千秋。

咱们先来个开场白,想象一下:你辛辛苦苦雕琢了一个精美的蛋糕🍰,现在想复制一个一模一样的出来,但是你不想再从头开始揉面、烘烤、抹奶油。你只想找一个现成的蛋糕,然后在这个基础上做文章。zeros_like(), ones_like(), 和 empty_like() 就扮演着“现成蛋糕”的角色。

一、三位忍者,闪亮登场!

  • zeros_like(a): “归零者”

    这位忍者擅长归零!它会创建一个与输入数组 a 具有相同形状和数据类型的数组,但是所有元素都初始化为 0。就像一个被洗得干干净净的画布,等待你挥洒创意。

    想象一下,你要做一个图像处理,需要一个跟原图大小一样的空白图层,这时 zeros_like() 就派上大用场了!

  • ones_like(a): “统一者”

    这位忍者擅长统一!它同样会创建一个与输入数组 a 具有相同形状和数据类型的数组,但所有元素都被初始化为 1。就像一群整齐划一的士兵,等待你的指挥。

    在某些数学运算中,你需要一个全 1 的矩阵,作为初始值或者掩码,ones_like() 就能快速生成。

  • empty_like(a): “虚无者”

    这位忍者有点神秘,它也会创建一个与输入数组 a 具有相同形状和数据类型的数组,但是数组中的元素是未经初始化的。也就是说,里面的值是随机的,就像一片混沌的宇宙,充满了未知。

    empty_like() 的优势在于速度快,因为它不用初始化数组,直接分配内存。但是,在使用之前,你必须手动初始化数组,否则会得到一些意想不到的结果。

    注意: 使用 empty_like() 时要格外小心,因为它里面的值是随机的,如果直接拿来用,可能会导致程序出错。就像你拿到一个装满垃圾的箱子,不清理就往里面放东西,结果可想而知。

二、忍术详解:代码示例

光说不练假把式,咱们来撸几段代码,看看这三位忍者是如何施展忍术的。

import numpy as np

# 创建一个示例数组
original_array = np.array([[1, 2, 3], [4, 5, 6]])

# 使用 zeros_like()
zeros_array = np.zeros_like(original_array)
print("zeros_like:n", zeros_array)

# 使用 ones_like()
ones_array = np.ones_like(original_array)
print("ones_like:n", ones_array)

# 使用 empty_like()
empty_array = np.empty_like(original_array)
print("empty_like:n", empty_array)

# 验证数据类型
print("original_array.dtype:", original_array.dtype)
print("zeros_array.dtype:", zeros_array.dtype)
print("ones_array.dtype:", ones_array.dtype)
print("empty_array.dtype:", empty_array.dtype)

运行结果:

zeros_like:
 [[0 0 0]
 [0 0 0]]
ones_like:
 [[1 1 1]
 [1 1 1]]
empty_like:
 [[65536       0       0]
 [      0       0       0]]
original_array.dtype: int64
zeros_array.dtype: int64
ones_array.dtype: int64
empty_array.dtype: int64

从结果可以看出:

  • zeros_like()ones_like() 创建的数组与 original_array 具有相同的形状和数据类型,并且分别初始化为 0 和 1。
  • empty_like() 创建的数组与 original_array 具有相同的形状和数据类型,但里面的值是随机的。

三、忍术进阶:参数详解

这三位忍者的忍术并非只有简单的复制,它们还提供了一些参数,让你能够更灵活地控制克隆过程。

  • dtype:指定数据类型

    你可以使用 dtype 参数来指定新数组的数据类型。如果不指定,则默认与输入数组 a 的数据类型相同。

    例如:

    original_array = np.array([1, 2, 3], dtype=np.int32)
    float_array = np.zeros_like(original_array, dtype=np.float64)
    print("float_array:n", float_array)
    print("float_array.dtype:", float_array.dtype)

    运行结果:

    float_array:
     [0. 0. 0.]
    float_array.dtype: float64

    可以看到,新数组 float_array 的数据类型变成了 float64

  • order:指定存储顺序

    order 参数用于指定数组的存储顺序,可以是 'C' (行优先) 或 'F' (列优先)。如果不指定,则默认与输入数组 a 的存储顺序相同。

    这个参数在处理多维数组时比较有用,可以影响数组的访问效率。

    温馨提示: 一般情况下,我们不需要修改 order 参数,使用默认值即可。

四、忍术应用:实战演练

光说理论没意思,咱们来几个实战演练,看看这三位忍者在实际项目中是如何大显身手的。

  • 图像处理:创建掩码

    在图像处理中,我们经常需要创建掩码,用于提取图像的特定区域。zeros_like()ones_like() 可以快速创建与原图大小相同的掩码。

    import cv2
    import numpy as np
    
    # 读取图像
    image = cv2.imread('image.jpg')  # 替换成你的图像文件
    
    # 创建一个与图像大小相同的掩码,初始化为 0
    mask = np.zeros_like(image)
    
    # 在掩码上绘制一个圆形
    center = (image.shape[1] // 2, image.shape[0] // 2)  # 图像中心
    radius = 100
    cv2.circle(mask, center, radius, (255, 255, 255), -1)  # 白色圆形
    
    # 将掩码应用到图像上
    masked_image = cv2.bitwise_and(image, mask)
    
    # 显示结果
    cv2.imshow('Original Image', image)
    cv2.imshow('Mask', mask)
    cv2.imshow('Masked Image', masked_image)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

    这段代码会读取一张图像,创建一个与图像大小相同的掩码,并在掩码上绘制一个圆形。然后,使用 cv2.bitwise_and() 函数将掩码应用到图像上,提取圆形区域。

  • 数值计算:初始化数组

    在数值计算中,我们经常需要初始化数组,用于存储计算结果。zeros_like()ones_like() 可以快速创建与输入数组大小相同的数组,并分别初始化为 0 和 1。

    import numpy as np
    
    # 创建一个示例数组
    x = np.array([1, 2, 3, 4, 5])
    
    # 创建一个与 x 大小相同的数组,用于存储计算结果
    y = np.zeros_like(x)
    
    # 计算 y = x * 2
    for i in range(len(x)):
        y[i] = x[i] * 2
    
    print("x:", x)
    print("y:", y)

    这段代码会创建一个与数组 x 大小相同的数组 y,并使用循环计算 y = x * 2

  • 机器学习:占位符

    在机器学习中,我们经常需要创建占位符,用于存储输入数据和模型参数。empty_like() 可以快速创建与输入数据大小相同的占位符。

    注意: 使用 empty_like() 创建占位符时,需要在使用之前手动初始化数组,否则会得到一些意想不到的结果。

五、三位忍者,优缺点分析

咱们来总结一下这三位忍者的优缺点,方便大家在实际项目中做出选择。

特性 zeros_like() ones_like() empty_like()
初始化值 0 1 未初始化
速度 较慢 较慢 最快
内存占用 较大 较大 较小
适用场景 需要初始化为 0 的数组 需要初始化为 1 的数组 对速度要求高,且在使用前会手动初始化的数组
注意事项 使用前必须初始化

六、总结:选择合适的忍者

zeros_like(), ones_like(), 和 empty_like() 都是NumPy中非常实用的函数,它们可以帮助我们快速创建与现有数组具有相同形状和数据类型的数组。

  • 如果你需要一个初始化为 0 的数组,选择 zeros_like()
  • 如果你需要一个初始化为 1 的数组,选择 ones_like()
  • 如果你对速度要求很高,并且在使用前会手动初始化数组,可以选择 empty_like()

记住,没有最好的忍者,只有最适合你的忍者!

七、彩蛋:NumPy的广播机制

在结束今天的课程之前,咱们再来聊一个NumPy的隐藏技能——广播机制。

广播机制是指NumPy在进行数组运算时,如果两个数组的形状不匹配,NumPy会自动扩展数组的形状,使其能够进行运算。

例如:

import numpy as np

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

c = a + b
print("c:", c)

运行结果:

c: [3 4 5]

在这个例子中,数组 a 的形状是 (3,),标量 b 的形状是 ()。NumPy会自动将标量 b 扩展成形状为 (3,) 的数组 [2, 2, 2],然后再与数组 a 进行加法运算。

广播机制可以让我们在进行数组运算时,避免手动扩展数组的形状,从而简化代码。

八、下课!

今天的“NumPy魔法屋”就到这里了。希望通过今天的学习,大家能够掌握zeros_like(), ones_like(), 和 empty_like() 这三位忍者的忍术,并在实际项目中灵活运用。

记住,编程的道路是漫长的,需要不断学习和实践。希望大家能够保持学习的热情,不断提升自己的编程技能!

下次再见啦! 👋

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注