当前位置: 首页 > news >正文

费曼学习法6 - 你好,NumPy!数据分析的 “瑞士军刀” (入门篇)

第一篇:你好,NumPy!数据分析的 “瑞士军刀” (入门篇)

开篇提问:

想象一下,你是一位厨艺高手,想要做出各种美味佳肴。 你手里已经有了各种食材,但是,如果想要 高效、快速、精确 地处理这些食材,做出色香味俱全的菜肴,你最需要的是什么呢? 没错,是一套 得心应手的厨具! 比如锋利的菜刀、精准的量具、高效的搅拌机等等。

在 Python 的数据分析世界里,NumPy 就扮演着 “厨具” 这样的角色。 它是一个功能强大的 工具库,专门用来 高效处理各种数据,就像瑞士军刀一样,一把在手,数据分析无忧! 那么,这个神奇的 NumPy 到底是什么? 它为什么如此重要? 今天,就让我们一起揭开 NumPy 的神秘面纱,开启数据分析的奇妙旅程!

核心概念讲解 (费曼式解释):

  1. NumPy 是什么?数据分析为什么要用它? (瑞士军刀的比喻)

    NumPy,全称 Numerical Python,顾名思义,就是 “用于数值计算的 Python 库”。 但如果仅仅理解为 “数值计算”,就太小看它了。 实际上,NumPy 是 Python 数据科学分析 领域中 最核心、最基础 的库,几乎所有其他数据分析库 (比如后面我们会学到的 Pandas, Matplotlib, Scikit-learn 等) 都离不开 NumPy 的支持。

    你可以把 NumPy 想象成一把 瑞士军刀,它集成了各种 数据处理的 “刀具”,每一种 “刀具” 都能帮你解决特定的数据处理难题。 例如:

    • 高效的 “数据容器” - NumPy 数组 (ndarray): 就像瑞士军刀的主刀,NumPy 最核心的 “刀具” 就是 NumPy 数组 (ndarray)。 它可以 高效地存储和处理大量的数值数据,无论是 一维的数字序列 (比如商品价格列表),还是 多维的数据表格 (比如学生成绩单),NumPy 数组都能轻松胜任。 而且,NumPy 数组在 运算速度上 远超 Python 自带的列表 (list),就像用锋利的菜刀切菜比用普通水果刀快得多一样!

    • 强大的 “数学工具箱” - 各种数学函数: 瑞士军刀里有各种工具,NumPy 也内置了 丰富的数学函数,可以进行各种 数学运算、统计分析、线性代数、傅里叶变换 等等。 就像瑞士军刀里的螺丝刀、锯子、尺子等工具,NumPy 的数学函数可以帮你快速完成各种复杂的数据计算和分析任务。

    • 灵活的 “数据变形” 能力 - 形状变换、索引切片: 瑞士军刀可以根据需要变形展开,NumPy 数组也具有 灵活的 “变形” 能力。 你可以 随意改变数组的形状 (比如把一维数组变成二维数组), 自由地访问和操作数组中的数据 (通过索引和切片),就像瑞士军刀可以灵活地调整刀片角度、切换不同工具一样,NumPy 数组可以灵活地适应各种数据处理需求。

    为什么要用 NumPy? 简单来说,就是为了 更高效、更方便、更强大 地进行数据分析和数值计算! 如果你想在数据科学领域有所作为,NumPy 绝对是你 必须掌握 的 “瑞士军刀”!

  2. 安装 NumPy: 准备好你的 “瑞士军刀”

    想要使用 NumPy 这把 “瑞士军刀”,首先要把它 安装 到你的 Python 环境中。 安装 NumPy 非常简单,只需要一行命令:

    pip install numpy
    

    和安装 PIL 库 (Pillow) 一样,打开你的电脑终端 (Windows 用户是命令提示符或 PowerShell,Mac/Linux 用户是终端),复制粘贴这行代码,按下回车键,等待安装完成就可以了。 就像网购了一把瑞士军刀,收到货拆开包装就OK了!

    安装完成后,你就可以在 Python 代码中 导入 NumPy 库,开始使用它的各种功能了。 通常我们 约定俗成 地使用 np 作为 NumPy 的 别名 (alias),这样可以更方便地调用 NumPy 的函数和对象。

    import numpy as np  # 导入 NumPy 库,并使用 np 作为别名
    
    # 现在你就可以使用 np.xxx 来调用 NumPy 的功能了,例如:
    # np.array(), np.zeros(), np.sum(), np.mean() ...
    
  3. NumPy 数组 (ndarray): 数据分析的 “积木”

    NumPy 最核心的概念就是 NumPy 数组 (ndarray),全称 N-dimensional array,也就是 “N 维数组”。 你可以把 NumPy 数组想象成 数据分析的 “积木”,我们可以用它来 构建各种复杂的数据结构,进行各种数据处理和计算。

    • 什么是数组? (有序的 “数据集合”)

      简单来说,数组 就是 一组有序排列的 “数据” 的集合。 这组数据可以是数字、文字、图像、音频等等。 在 NumPy 中,我们主要处理的是 数值数据。 NumPy 数组和 Python 自带的列表 (list) 有些类似,但它们之间有着本质的区别。 NumPy 数组更像是一个 “数学上的向量或矩阵”,它对 数值运算进行了专门的优化,因此在处理数值数据时,NumPy 数组的效率远高于 Python 列表。 就像用专业的搅拌机打果汁比用手动搅拌器快得多一样!

    • 数组的维度 (ndim): “积木” 的层数

      维度 (ndim) 描述了数组是 “几维的”。 你可以把数组的维度想象成 “积木的层数”

      • 一维数组 (1D array): 就像 一条直线,或者 一列数字,只有一个维度 (层)。 例如,[1, 2, 3, 4, 5] 就是一个一维数组,它只有一个轴 (axis),通常称为 行 (row)列 (column) (取决于方向)。

      • 二维数组 (2D array): 就像 一个表格,或者 一个矩阵,有两个维度 (层)。 例如,[[1, 2, 3], [4, 5, 6]] 就是一个二维数组,它有两个轴,通常称为 行 (row)列 (column)

      • 三维数组 (3D array): 就像 一个立方体,或者 多张表格堆叠在一起,有三个维度 (层)。 例如,在图像处理中,彩色图像通常用三维数组表示,三个维度分别代表 高度 (height)、宽度 (width) 和颜色通道 (channels) (比如 RGB 三个颜色通道)。

      • 更高维度的数组 (ND array): NumPy 数组可以扩展到 任意维度,维度数由 ndim 属性表示。 维度越多,数据结构就越复杂,但 NumPy 都能高效地处理。

    • 数组的形状 (shape): “积木” 的尺寸

      形状 (shape) 描述了数组在 每个维度上的 “长度” (或者说 “尺寸”)。 你可以把数组的形状想象成 “积木的尺寸”。 形状通常用一个 元组 (tuple) 来表示。

      • 一维数组的形状: 形状元组只有一个元素,表示数组的 长度。 例如,一维数组 [1, 2, 3, 4, 5] 的形状是 (5,),表示它有 5 个元素。

      • 二维数组的形状: 形状元组有两个元素,分别表示数组的 行数和列数。 例如,二维数组 [[1, 2, 3], [4, 5, 6]] 的形状是 (2, 3),表示它有 2 行 3 列。

      • 三维数组的形状: 形状元组有三个元素,分别表示数组在 高度、宽度、深度 (或其他维度) 上的长度。 例如,一个表示 RGB 图像的三维数组,形状可能是 (256, 256, 3),表示图像高度 256 像素,宽度 256 像素,颜色通道数为 3 (RGB)。

      • 可以通过 数组名.shape 来查看数组的形状。

    • 数组的数据类型 (dtype): “积木” 的材质

      数据类型 (dtype) 描述了数组中 元素的数据类型。 你可以把数组的数据类型想象成 “积木的材质”。 NumPy 数组要求 所有元素的类型必须相同,这是 NumPy 数组高效运算的关键。 常见的数据类型包括:

      • int: 整数类型 (例如 int8, int16, int32, int64 等,表示不同位数的整数)

      • float: 浮点数类型 (例如 float16, float32, float64 等,表示不同精度的浮点数)

      • bool: 布尔类型 (True 或 False)

      • string_U: 字符串类型 (Unicode 字符串)

      • object: Python 对象类型 (可以存储任意 Python 对象,但效率较低,一般不常用)

      • 可以通过 数组名.dtype 来查看数组的数据类型。 在创建数组时,NumPy 会 自动推断数据类型,也可以 手动指定数据类型

  4. 创建 NumPy 数组: “搭积木” 的第一步

    掌握了 NumPy 数组的基本概念,我们就可以开始 创建 NumPy 数组 了,就像 “搭积木” 的第一步! NumPy 提供了多种创建数组的方法,我们可以根据不同的需求选择合适的方法。

    • 从 Python 列表或元组创建: np.array()

      np.array() 函数是最常用的创建数组的方法之一,它可以 将 Python 列表 (list) 或 元组 (tuple) 转换为 NumPy 数组

      import numpy as np
      
      # 从 Python 列表创建一维数组
      list1 = [1, 2, 3, 4, 5]
      array1 = np.array(list1)
      print("从列表创建的一维数组:\n", array1)
      print("数组的形状:", array1.shape)
      print("数组的维度:", array1.ndim)
      print("数组的数据类型:", array1.dtype)
      
      # 从 Python 列表创建二维数组
      list2 = [[1, 2, 3], [4, 5, 6]]
      array2 = np.array(list2)
      print("\n从列表创建的二维数组:\n", array2)
      print("数组的形状:", array2.shape)
      print("数组的维度:", array2.ndim)
      print("数组的数据类型:", array2.dtype)
      
      # 从 Python 元组创建数组 (方法类似,只需要把列表换成元组)
      tuple1 = (1, 2, 3)
      array3 = np.array(tuple1)
      print("\n从元组创建的一维数组:\n", array3)
      

      代码解释:

      • np.array(object, dtype=None, ...): np.array() 函数的主要参数是 object,表示要转换为数组的 Python 对象 (例如列表、元组、或其他数组)。 dtype 参数可以 手动指定数组的数据类型,如果不指定,NumPy 会 自动推断
    • 创建全零数组: np.zeros()

      np.zeros(shape, dtype=float, ...) 函数可以 创建指定形状和数据类型的 “全零” 数组。 就像准备一块 “空白画布”,可以用来 初始化数组,或者作为 占位符

      import numpy as np
      
      # 创建一个形状为 (3, 4) 的全零二维数组 (默认数据类型为 float64)
      zeros_array1 = np.zeros((3, 4)) # 注意形状参数要用元组表示
      print("全零二维数组:\n", zeros_array1)
      print("数组的形状:", zeros_array1.shape)
      print("数组的数据类型:", zeros_array1.dtype)
      
      # 创建一个形状为 (2, 2, 2) 的全零三维数组,并指定数据类型为 int32
      zeros_array2 = np.zeros((2, 2, 2), dtype=np.int32) # 或者 dtype='int32'
      print("\n全零三维数组 (int32 类型):\n", zeros_array2)
      print("数组的数据类型:", zeros_array2.dtype)
      

      代码解释:

      • np.zeros(shape, dtype=float, ...): shape 参数是 数组的形状,需要用 元组 表示。 dtype 参数可以 指定数组的数据类型,默认为 float64 (双精度浮点数)。 可以使用 np.int32, np.float32, np.bool_, np.string_ 等 NumPy 内置的数据类型,也可以使用 Python 内置的数据类型字符串,例如 'int32', 'float64', 'bool', 'U10' (Unicode 字符串,长度为 10) 等。
    • 创建全一数组: np.ones()

      np.ones(shape, dtype=float, ...) 函数可以 创建指定形状和数据类型的 “全一” 数组。 和 np.zeros() 类似,但数组元素都是 1。 可以用来 初始化数组,或者作为 “单位矩阵” (在线性代数中)。

      import numpy as np
      
      # 创建一个形状为 (2, 5) 的全一二维数组 (默认数据类型为 float64)
      ones_array1 = np.ones((2, 5))
      print("全一二维数组:\n", ones_array1)
      
      # 创建一个形状为 (3,) 的全一维数组,并指定数据类型为 int8
      ones_array2 = np.ones(3, dtype=np.int8) # 注意:一维数组的形状可以直接写整数,不用元组
      print("\n全一维数组 (int8 类型):\n", ones_array2)
      print("数组的数据类型:", ones_array2.dtype)
      

      代码解释:

      • np.ones(shape, dtype=float, ...): 参数与 np.zeros() 类似,shape 是形状,dtype 是数据类型,默认为 float64注意:当创建一维数组时,shape 参数可以直接写一个整数,表示数组的长度,不用写成元组 (length,) 但为了代码风格统一,建议都写成元组形式,例如 (3,)
    • 创建未初始化数组: np.empty()

      np.empty(shape, dtype=float, ...) 函数可以 创建指定形状和数据类型的 “未初始化” 数组注意:“未初始化” 并不意味着数组是空的,而是数组的元素值是随机的,取决于内存中的现有数据,而不是被设置为 0 或 1。 np.empty()创建速度通常比 np.zeros()np.ones() 更快,因为它不需要初始化数组元素。 但使用 np.empty() 创建的数组,在使用前必须手动赋值,否则可能会得到意想不到的结果。 np.empty() 通常用于 对性能要求较高,并且后续会覆盖数组元素值的场景

      import numpy as np
      
      # 创建一个形状为 (2, 3) 的未初始化二维数组 (数据类型为 float64)
      empty_array = np.empty((2, 3))
      print("未初始化二维数组 (元素值随机):\n", empty_array) # 每次运行结果可能不一样
      print("数组的数据类型:", empty_array.dtype)
      

      代码解释:

      • np.empty(shape, dtype=float, ...): 参数与 np.zeros()np.ones() 类似。 请务必注意 np.empty() 创建的数组是未初始化的,元素值是随机的,使用前需要手动赋值!
    • 创建连续整数序列数组: np.arange()

      np.arange([start, ]stop, [step, ]dtype=None, ...) 函数可以 创建等差的整数序列数组,类似于 Python 内置的 range() 函数,但 np.arange() 返回的是 NumPy 数组,而不是列表。

      import numpy as np
      
      # 创建从 0 到 9 的整数序列数组 (不包含 10,步长为 1,默认数据类型为 int64)
      arange_array1 = np.arange(10) # 相当于 range(0, 10)
      print("arange 整数序列数组 (0-9):\n", arange_array1)
      
      # 创建从 5 到 15 的整数序列数组 (不包含 16,步长为 2)
      arange_array2 = np.arange(5, 16, 2) # 相当于 range(5, 16, 2)
      print("\narange 整数序列数组 (5-15, 步长 2):\n", arange_array2)
      print("数组的数据类型:", arange_array2.dtype)
      
      # 创建从 0 到 1 的浮点数序列数组 (不包含 1,步长为 0.1)
      arange_array3 = np.arange(0, 1, 0.1) # 步长可以是浮点数,但结果可能 неточное из-за проблем с плавающей точкой
      print("\narange 浮点数序列数组 (0-1, 步长 0.1):\n", arange_array3)
      print("数组的数据类型:", arange_array3.dtype) # 注意数据类型变成了 float64
      

      代码解释:

      • np.arange([start, ]stop, [step, ]dtype=None, ...): 参数类似于 range() 函数:
        • start: 序列的 起始值 (可选,默认为 0)。
        • stop: 序列的 结束值 (必须, 不包含 结束值)。
        • step: 序列的 步长 (可选,默认为 1)。
        • dtype: 可以 指定数组的数据类型,如果不指定,NumPy 会 自动推断
      • 注意: np.arange()stop 参数是不包含在序列内的,就像 Python 的 range() 函数一样。 另外,使用浮点数作为步长时,由于浮点数精度问题,结果可能会 不完全精确,建议尽量使用整数步长,或者使用 np.linspace() 函数创建更精确的等差浮点数序列。
    • 创建等间隔浮点数序列数组: np.linspace()

      np.linspace(start, stop, num=50, endpoint=True, ...) 函数可以 创建指定数量的、等间隔的浮点数序列数组。 与 np.arange() 不同,np.linspace() 更精确地控制序列的元素数量和间隔,并且 默认包含结束值

      import numpy as np
      
      # 创建从 0 到 1 的 5 个等间隔浮点数序列数组 (包含 1,默认包含结束值)
      linspace_array1 = np.linspace(0, 1, num=5) # num 参数指定元素数量
      print("linspace 等间隔浮点数序列数组 (0-1, 5 个元素):\n", linspace_array1)
      print("数组的数据类型:", linspace_array1.dtype) # 数据类型为 float64
      
      # 创建从 0 到 1 的 10 个等间隔浮点数序列数组 (不包含 1,endpoint=False)
      linspace_array2 = np.linspace(0, 1, num=10, endpoint=False) # endpoint=False 不包含结束值
      print("\nlinspace 等间隔浮点数序列数组 (0-1, 10 个元素, 不含结尾):\n", linspace_array2)
      

      代码解释:

      • np.linspace(start, stop, num=50, endpoint=True, ...):
        • start: 序列的 起始值
        • stop: 序列的 结束值 ( 默认包含 结束值,可以通过 endpoint=False 设置为不包含)。
        • num: 要生成的 元素数量 (默认为 50)。
        • endpoint: 是否 包含结束值,默认为 True (包含),设置为 False 则不包含结束值。
    • 创建 0-1 之间均匀分布的随机数数组: np.random.rand()

      np.random.rand(d0, d1, ..., dn) 函数可以 创建指定形状的、元素值在 0-1 之间均匀分布的随机数数组np.random 是 NumPy 的 随机数模块,提供了各种随机数生成函数。

      import numpy as np
      
      # 创建一个形状为 (2, 3) 的 0-1 均匀分布随机数二维数组
      rand_array1 = np.random.rand(2, 3) # 注意形状参数直接写整数,不用元组
      print("0-1 均匀分布随机数二维数组:\n", rand_array1)
      print("数组的形状:", rand_array1.shape)
      print("数组的数据类型:", rand_array1.dtype) # 数据类型为 float64
      
      # 创建一个形状为 (5,) 的 0-1 均匀分布随机数一维数组
      rand_array2 = np.random.rand(5) # 一维数组的形状可以直接写整数
      print("\n0-1 均匀分布随机数一维数组:\n", rand_array2)
      

      代码解释:

      • np.random.rand(d0, d1, ..., dn): 参数 d0, d1, ..., dn 表示数组的 各个维度的长度注意: np.random.rand() 的形状参数是直接写整数,不用写成元组形式。 例如 np.random.rand(2, 3) 表示创建形状为 (2, 3) 的二维数组, np.random.rand(5) 表示创建形状为 (5,) 的一维数组。
  5. 案例应用: 用 NumPy 数组表示班级学生的成绩单

    现在,我们来做一个简单的 案例应用,展示 NumPy 数组的 实用性。 假设我们要用 NumPy 数组来 表示一个班级学生的成绩单,并进行一些简单的 数据分析

    import numpy as np
    
    # 假设有 5 个学生,3 门科目 (语文、数学、英语) 的成绩,用二维数组表示成绩单
    # 每行代表一个学生,每列代表一门科目
    grades_array = np.array([
        [85, 92, 78],  # 学生 1 的成绩 (语文, 数学, 英语)
        [90, 88, 95],  # 学生 2 的成绩
        [75, 80, 82],  # 学生 3 的成绩
        [95, 98, 92],  # 学生 4 的成绩
        [80, 85, 88]   # 学生 5 的成绩
    ])
    
    print("学生成绩单 (NumPy 数组):\n", grades_array)
    print("成绩单的形状:", grades_array.shape) # (5, 3),5 行 3 列
    print("成绩单的维度:", grades_array.ndim) # 2 维
    
    # 1. 计算每门科目的平均分 (按列计算平均值,axis=0 表示按列)
    average_scores = np.mean(grades_array, axis=0)
    print("\n每门科目的平均分:", average_scores) # 语文平均分, 数学平均分, 英语平均分
    
    # 2. 计算每个学生的总分 (按行计算总和,axis=1 表示按行)
    total_scores = np.sum(grades_array, axis=1)
    print("\n每个学生的总分:", total_scores) # 学生 1 总分, 学生 2 总分, ...
    
    # 3. 找出数学科目的最高分 (第二列,索引为 1)
    max_math_score = np.max(grades_array[:, 1]) # 冒号 : 表示所有行,1 表示第二列
    print("\n数学科目的最高分:", max_math_score)
    
    # 4. 找出英语科目的最低分 (第三列,索引为 2)
    min_english_score = np.min(grades_array[:, 2]) # 冒号 : 表示所有行,2 表示第三列
    print("\n英语科目的最低分:", min_english_score)
    

    代码解释:

    • 用二维数组表示成绩单: 我们用一个 5 行 3 列的二维数组 grades_array 来表示 5 个学生的 3 门科目成绩。 每一行代表一个学生,每一列代表一门科目。 这就像一个 电子表格 一样,非常直观。
    • np.mean(grades_array, axis=0): np.mean() 函数可以计算数组的 平均值axis=0 参数表示 沿着第 0 轴 (列) 计算平均值,也就是 按列计算平均值,得到每门科目的平均分。
    • np.sum(grades_array, axis=1): np.sum() 函数可以计算数组的 总和axis=1 参数表示 沿着第 1 轴 (行) 计算总和,也就是 按行计算总和,得到每个学生的总分。
    • grades_array[:, 1]: 数组索引和切片 操作, [:, 1] 表示 选取所有行 (冒号 : 表示所有行),第二列 (索引为 1),也就是 数学科目的所有成绩np.max(grades_array[:, 1]) 可以找出数学科目的最高分。 [:, 2] 同理,表示 英语科目的所有成绩np.min(grades_array[:, 2]) 可以找出英语科目的最低分。
    • 这个简单的案例展示了 NumPy 数组在数据表示和简单数据分析方面的便捷性和高效性。 在后续的文章中,我们会学习更多 NumPy 数组的强大功能,进行更复杂的数据处理和分析。

费曼回顾 (知识巩固):

现在,请你用自己的话,像给一个完全不懂编程的朋友解释一下,今天我们都学习了哪些关于 NumPy 的知识? 例如:

  • NumPy 是什么? 为什么说它是数据分析的 “瑞士军刀”? 它最重要的 “刀具” 是什么?
  • 什么是 NumPy 数组 (ndarray)? 它和 Python 列表有什么区别? 它有哪些重要的属性 (维度、形状、数据类型)? 它们分别是什么意思?
  • 我们学习了哪些创建 NumPy 数组的方法? np.array(), np.zeros(), np.ones(), np.empty(), np.arange(), np.linspace(), np.random.rand() 分别有什么用途? 你能用生活中的例子来比喻它们吗?
  • 在学生成绩单案例中,我们是如何使用 NumPy 数组来表示数据,并进行简单的数据分析的?

尝试用最简洁、最形象的语言来解释,就像你是一位老师,正在给你的学生讲解一样。 如果你能清晰地解释出来,就说明你已经掌握了今天学习的内容!

课后思考 (拓展延伸):

  1. 尝试修改学生成绩单案例的代码,例如:
    • 增加学生人数或科目数量,看看代码是否仍然有效?
    • 计算每门科目的标准差、最高分、最低分,或者其他统计指标?
    • 找出总分最高的学生?
    • 将成绩单保存到文件 (例如 CSV 文件),再从文件中读取数据进行分析? (提示:可以使用 np.savetxt()np.loadtxt() 函数,我们会在后续文章中学习)
  2. 思考一下,除了学生成绩单,NumPy 数组还可以用来表示哪些数据? 例如,图像、音频、股票价格、地理位置信息等等。 你有什么有趣的应用想法吗?
  3. 尝试查阅 NumPy 官方文档或其他 NumPy 教程,了解更多 NumPy 数组的创建方法和属性,例如 np.full(), np.eye(), np.identity(), np.asarray(), array.size, array.itemsize 等。

恭喜你!完成了 NumPy 费曼学习法的第一篇文章学习! 你已经迈出了掌握数据分析 “瑞士军刀” 的第一步! 在下一篇文章中,我们将继续探索 NumPy 数组的 “变形术”,学习如何灵活地改变数组的形状,以及如何使用索引和切片来访问和操作数组中的数据,让你的数据处理技能更上一层楼! 敬请期待!

相关文章:

  • LD_PRELOAD 绕过 disable_function 学习
  • Parameter 与 Param 有什么区别
  • hot100---day3
  • [青基解读二] 2025年国家自然科学基金---时间安排
  • C语言堆学习笔记
  • 将Ubuntu操作系统的安装源设置为阿里云
  • 八大排序算法(C语言实现)
  • JWT令牌
  • 关于单调栈问题的本质的思考
  • vue js-web-screen-shot浏览器截取其他非全屏窗口界面
  • 点击修改按钮图片显示有问题
  • 爬虫解析库:pyquery的详细使用
  • 云电脑接入DeepSeek?探讨ToDesk云电脑、海马云、顺网云的AI潜能
  • 作业day6
  • 面试八股文--数据库基础知识总结(2) MySQL
  • 五十天精通硬件设计第36天-万用表的原理及使用
  • java随堂小记
  • 【MySQL】表的内联和外联
  • Vue3中ref与reactive的区别
  • 垃圾回收算法
  • 算命网站该怎样做/百一度一下你就知道
  • 做网站挣钱/做神马seo快速排名软件
  • 去哪找网站建设公司好/windows7系统优化工具
  • 柳州做网站哪家好/免费舆情网站
  • 怎么设置网站标题/珠海网络推广公司
  • 独立网站如何做/企业百度推广