☰
Joyful Pandas 补充习题全解析:7 道 pandas 实战题的向量化思维与解法思路
2026/10/13 6:29:25 网站建设 项目流程
  • 文档
  • 教程
  • 数据分析

【免费下载链接】joyful-pandas

pandas中文教程

项目地址:https://gitcode.com/gh_mirrors/jo/joyful-pandas
点击查看免费下载

本文基于 Joyful Pandas(pandas 中文教程)仓库中的 source/补充习题.rst 整理而成,系统拆解 Ex1~Ex7 共 7 道综合习题的题干设定、涉及知识点、可用数据文件与参考答案思路。读者读完本文后,将能理解如何用 NumPy 向量化运算替代显式循环、如何用 pandas 的 groupby / merge / nlargest / pivot 等核心 API 完成成绩统计、审核流程分析、日志解析等真实场景任务,并掌握"尽可能不使用 for/while 循环"这一 pandas 式编程要义。

补充习题是 Joyful Pandas 教程十三个章节之外的一套综合实战题,覆盖 NumPy 向量化、索引、分组、变形、连接、缺失数据、文本数据、分类数据与时序数据等全部核心主题。整套习题开头有一条硬性要求:

在补充习题中尽可能不要使用任何 for 或 while 循环。

这条约束与教程正文反复强调的"pandasic 代码要义"一脉相承:pandas 的绝大多数操作都基于 C 层向量化实现,显式 Python 循环不仅代码冗长,性能也往往相差几个数量级。下面逐题展开。


Ex1:NumPy 的向量化运算

Ex1 是整套习题的"开胃菜",用 4 个小题训练纯 NumPy 层面的向量化思维。涉及的关键函数包括np.diff、np.nonzero、np.cumsum、np.argsort以及广播机制。

1. 缺失的最小正整数

给定一个正整数列表,找出缺失的最小正整数。题干给出的三个测试用例:

>>> arr = np.array([2,3,4]) >>> get_miss(arr) 1 >>> arr = np.array([6,3,5,1,2]) >>> get_miss(arr) 4 >>> arr = np.array([5,2,1,3,4]) >>> get_miss(arr) 6

参考思路:先对数组去重并排序,用np.diff检查相邻元素的差,若差值大于 1,则缺失值位于这两个元素之间;若整个数组是连续整数,则答案是最小值减 1(数组起始不为 1 时)或最大值加 1。该思路与 参考答案.rst 第一章 Ex5 "连续整数的最大长度"中使用的技巧同源——那里用np.diff(np.nonzero(np.r_[1, np.diff(x)!=1, 1])).max()找出最长连续段长度,可见np.diff+np.nonzero是处理"连续性"问题的标准组合。

2. 生成阶梯状二维数组get_res(n)

函数输入正整数 n,按如下规则构造二维数组:第 1 行填入 1 个 1,第 2 行在上一行填入位置的下一列连续填入 2 个 2,依此类推。n=4 时的期望输出:

array([[1., 0., 0., 0., 0., 0., 0., 0., 0., 0.], [0., 2., 2., 0., 0., 0., 0., 0., 0., 0.], [0., 0., 0., 3., 3., 3., 0., 0., 0., 0.], [0., 0., 0., 0., 0., 0., 4., 4., 4., 4.]])

参考思路:第 i 行的起始列是前 i-1 行累计填入的个数,即cumsum思想。先构造一个足够宽的全零矩阵(如 10 列),再通过行索引与列偏移的组合一次性写入每行连续的一段。整个构造可以用np.arange与广播完成,不需要逐行循环。

3. 随机游走极限估计

点 A 从数轴原点出发做 n 步简单随机游走(每步等概率向左或向右移动 1),可以证明:

$$\lim_{n\rightarrow+\infty}\frac{\mathbb{E}|S_n|}{\sqrt{n}}=\sqrt{\frac{2}{\pi}}$$

题目要求:取 n=5000 进行 1000 次试验,每次试验用 $\frac{1}{100}\sum_{k=1}^{100}|S_n|$ 代替 $\mathbb{E}|S_n|$,计算 1000 个估计值的均值、0.05 分位数与 0.95 分位数。

参考思路:把 1000 次试验、每次 100 条路径、每条路径 5000 步的随机游走整体构造成一个三维数组np.random.choice([-1, 1], size=(1000, 100, 5000)),沿最后一维累加得到每条路径的终点,取绝对值后沿路径维求均值,最后一次性得到 1000 个估计值。构造三维数组并利用sum/mean的axis参数,是完全避免两层 for 循环的关键。随后用np.mean、np.quantile(或np.percentile)即可计算所需统计量。

4. 点云相关矩阵 S

二维平面上有 n 个点(坐标node_xy)与 k 维特征(node_fea),点 a、b 的相关系数定义为:

$$S_{ab} = \frac{\sigma_{ab}}{2} + \frac{\lambda_{ab}}{2}$$

其中 $\sigma_{ab}$ 是特征向量 A、B 的余弦相似度:

$$\sigma_{ab} = \frac{\sum_{i=1}^kA_iB_i}{\sqrt{\sum_{i=1}^kA^2_i}\sqrt{\sum_{i=1}^kB^2_i}}$$

$\lambda_{ab}$ 基于二维平面距离排名:把到点 a 的距离排序,最近的点(点 a 自身)排名为 1,点 b 排名记为 $r^{(a)}_b$,则:

$$\lambda_{ab} = 1 - \frac{2\times (r^{(a)}_b-1)}{n-1}$$

题干明确提示使用np.argsort()。参考思路分三步:

  1. 欧氏距离矩阵:利用广播计算d = np.sqrt(((node_xy[:, None, :] - node_xy[None, :, :])**2).sum(-1)),得到 $n\times n$ 的距离矩阵;
  2. 排名矩阵:对距离矩阵沿 axis=1 做argsort,再对结果做一次argsort,即可把"距离"转换为"排名"(每行排名从 0 开始,对角线恰好为 0,即自身排名第 1)。这一"argsort 后再 argsort"的写法是把排序结果映射回原始下标的标准技巧;
  3. 特征余弦相似度:sigma = (node_fea @ node_fea.T) / np.outer(np.sqrt((node_fea**2).sum(1)), np.sqrt((node_fea**2).sum(1))),此时 $\sigma$ 对角线恒为 1(向量与自身的余弦相似度)。

最后S = (sigma + lam) / 2即可得到完整的 $n\times n$ 相关矩阵。


Ex2:统计学生的成绩情况

数据说明

data/supplement/ex2 目录存放了某校高三第一学期的成绩数据,包含 16 次周测成绩、期中考试成绩和期末考试成绩,共 18 个 CSV 文件(实测每个文件 897 行,即 896 名学生)。各文件列结构一致:

班级,姓名,选科,语文,数学,英语,科目 1,吴刚,地理,93,95,82,69
  • 所有表中相同的行表示同一位同学,可用"班级 + 姓名"作为连接键;
  • 选科共有 6 种取值:物理、化学、生物、历史、地理、政治(周测 1 中人数分布约为:化学 246、生物 166、历史 132、物理 131、地理 127、政治 94);
  • 科目列存放该生选科考试的成绩(无缺失值)。

典型读取方式:

df = pd.read_csv('data/supplement/ex2/第1次周测成绩.csv') df.head()

题目拆解

Q1:该校高三年级中是否存在姓名相同的学生?

直接用df['姓名'].duplicated().any()判断。注意同名判断需要限定在同一班级内(不同班级同名是正常的),严格做法是按['班级', '姓名']去重后比较数量。

Q2:第一次周测中,每个班级选修物理或化学同学的语数英总分平均值,哪个班级最高?

q = df[df['选科'].isin(['物理', '化学'])] res = q.groupby('班级')[['语文', '数学', '英语']].sum().mean(axis=1) res.idxmax()

先布尔筛选出物理/化学选科的学生,再按班级分组求和,最后按行求三科均值。实测示例数据中最高的是4 班。该题考察isin布尔筛选与groupby分组聚合的组合。

Q3:总评前十

总评 = 各次考试总分的加权平均值,周测权重 50%(16 次等权,每次 3.125%)、期中 20%、期末 30%。参考流程:

  1. 用pd.concat把 16 次周测按同一键纵向拼接(或用pd.concat(..., keys=range(16))保留周次信息);
  2. 每次考试的总分 = 语文 + 数学 + 英语 + 科目;
  3. 周测部分先求每次总分再按学生求均值,再与期中、期末总分按 0.5 / 0.2 / 0.3 加权求和;
  4. 用nlargest(10, '总分')取出前十。

nlargest是 pandas 提供的"无需排序再取头 N 个"的高效 API,本题明确要求"结合 nlargest 函数"。实测示例数据中年级总评前十的第一名是 8 班的王想(总分约 427.2)。

Q4:1~8 班文理科期末总分前 5

物化生为理科、政史地为文科,统计各班期末总分前 5,输出格式要求如"王大锤:历史(102)",即"姓名:选科(选科分数)"拼接字符串。参考思路:

  1. 读取期末成绩,按选科分出文理两组;
  2. groupby(['班级', '文理'])后对总分做nlargest(5),或对每组sort_values后取head(5);
  3. 用apply/字符串拼接把"姓名:选科(科目分)"格式组装成 DataFrame 列,最终拼出 16 列的宽表(8 个班 × 文/理)。

Q5:成绩稳定性分析

稳定性定义为"每次考试在全年级相同选科学生中的总分排名标准差"。参考流程:

  1. 把 18 次考试成绩表纵向合并,构造 (学生, 选科, 考试) 维度的长表;
  2. 对每次考试、每个选科分别做rank(ascending=False),得到该生该次考试在年级同选科中的总分排名;
  3. 按学生计算排名标准差,再按班级×选科聚合求均值,最终得到行索引为班级(1~11)、列索引为 6 个选科的 11×6 表格:
pd.DataFrame( np.random.rand(11, 6), index=pd.Index(range(1, 12), name="班级"), columns=pd.Index(["物理", "化学", "生物", "历史", "地理", "政治"], name="选科"), )

本题综合考察长表构造、rank排名、多重分组与groupby聚合,是分组章节知识点(参见 source/Content/ch4.rst)的完整应用。


Ex3:统计商品的审核情况

数据说明

data/supplement/ex3 下有两张表:

  • 商品信息.csv:约 26832 个商品,列为ID号, 识别码, 类别(类别取值如 T1、Q1、S1、S2);
  • 申请与审核记录.csv:约 147500 条审核记录,列为ID号, 申请人, 申请时间, 审核人, 审核时间, 结果(结果仅"通过"与"未通过"两种)。

审核流程为:申请人发起申请 → 审核人审核 → 通过或未通过;未通过可再由另一位申请人重新申请,直到通过为止。同一商品最多可能有 10 次审核记录。商品 ID 以 "ID 000001" 形式存在,申请人/审核人字段是含特殊字符的字符串(如\#+3((52\{、3}04}%@75`),读取后需注意字符串清洗。

df_info = pd.read_csv('data/supplement/ex3/商品信息.csv') df_record = pd.read_csv('data/supplement/ex3/申请与审核记录.csv')

题目拆解

Q1:有多少商品最终通过审核?

passed = df_record[df_record['结果'] == '通过']['ID号'].nunique()

由于每个商品最终要么通过要么未通过,直接用最后一条记录(或是否存在"通过"记录)判断即可。注意一个商品有多条记录,统计的是"商品数"而非"记录数"。

Q2:各类别商品的通过率?

先把商品信息与审核记录按ID号连接,再按类别分组,通过率 = 该类别最终通过的商品数 / 该类别商品总数。这里需要"每个商品取最终状态":因为审核流程保证"未通过可以继续申请",所以每个商品的最新一条记录的"结果"就是其最终状态,可用sort_values+groupby('ID号').tail(1)(或groupby('ID号').last())实现。

Q3:类别 T1 且最终通过的商品的平均审核次数?

先取最终通过的 T1 类商品,再统计这些商品在审核记录表中出现的次数(即审核次数),最后求平均。审核次数可由groupby('ID号')['结果'].count()得到。

Q4:是否存在商品在上一次审核未完成时就提交了下一次审核申请?

把审核记录按ID号、申请时间排序后,用groupby('ID号')['申请时间'].diff()计算同一商品相邻两次申请的时间间隔,检查是否存在前一次审核时间晚于后一次申请时间的记录:

d = df_record.sort_values(['ID号', '申请时间']) # 上一次审核时间与本次申请时间比较

严格判定是:对每个商品的记录按申请时间排序,判断申请时间[i+1] < 审核时间[i]是否成立。该题考察"分组内自比较",groupby+shift/diff是标准工具。

Q5:审核通过商品的第一位申请人与最后一位审核人

pd.DataFrame({ "ID号": ["ID 000001"] + ["..."]*3, "类别": ["T1"] + ["..."]*3, "申请人": ["\#+3((52\{"] + ["..."]*3, "审核人": ["3`}04}%@75"] + ["..."]*3, }, index=[1, 2, 3, "..."])

参考思路:对最终通过的每个商品,按其全部审核记录取第一条(最早)的申请人与最后一条(最新)的审核人,再与商品信息连接补上类别列。题目提示:"groupby 对象上也定义了 head 和 tail 方法"——即df_grouped.head(1)/df_grouped.tail(1)可取每个组的最前/最后若干行,这是本题的核心技巧。同样以sort_values保证组内顺序为前提。


Ex4:删除同样的行

给定两张表,在 df1 中剔除在 df2 中出现过的行:

df1 = pd.DataFrame({"A": [3,2,2,3,1,3], "B": [2,1,1,3,6,2], "C": [1,2,2,7,7,1], "D": [5,6,6,1,2,5]}) df2 = pd.DataFrame({"A": [2,3,1], "B": [1,9,6], "C": [2,7,7], "D": [6,1,2]})

期望结果保留 df1 中三行(第 0、3、5 行):

pd.DataFrame({"A": [3,3,3], "B": [2,3,2], "C": [1,7,1], "D": [5,1,5]})

参考思路:利用pd.merge的indicator=True参数做"外连接 + 来源标记",再筛选_merge == 'left_only'的行:

res = df1.merge(df2, how='left', indicator=True) res = res[res['_merge'] == 'left_only'].drop(columns='_merge')

该题的另一个常用解法是把两表拼接后drop_duplicates(keep=False),但由于 df1 自身存在重复行(如第 1、2 行同为[2,1,2,6]),用merge + indicator更稳妥。本题对应连接章节的"关系连接"知识点(参见 source/Content/ch6.rst),实测结果与期望输出完全一致。


Ex5:统计每个学区的开课数量

数据说明

data/supplement/ex5/school_course.csv 共 1921 行,列为Area, School, Course:

Area,School,Course area_1,school_99,course_90 area_2,school_32,course_20 area_3,school_64,course_38 area_1,school_231,course_9 course_40 course_100
  • 某城市共 4 个学区(area_1~area_4),共 367 所互不重名的学校;
  • 一条记录表示该学校开设的一门(或多门)课程,同一学校的不同记录之间课程可能重复(实测约 1274 行 Course 字段包含空格,即一条记录含多门课程,课程以空格分隔);
  • 课程种类共 100 门,编号course_1~course_100。

解题要点

要求统计每个学区开设每门课程的学校数量(学校去重),输出 100 行 × 4 列的宽表:

res = pd.DataFrame( 0, index=["course_%d" % (i+1) for i in range(100)], columns=["area_%d" % (i+1) for i in range(4)] )

参考思路分三步:

  1. 拆课程:把Course字段按空格拆分——最自然的方式是df['Course'].str.split()配合explode(),将一行多条课程拆成多行;
  2. 去重:按['Area', 'School', 'Course']去重,避免同一学校多记录导致的重复计数;
  3. 统计:pd.crosstab(df['Course'], df['Area'])得到课程×学区计数表,再按 100 门课程全集reindex,补齐未开设的课程为 0。

本题集中考察str.split、explode(把列表展开为多行的变形操作)、drop_duplicates与crosstab/pivot_table的组合使用,是"变形 + 分类 + 分组"的综合应用题。


Ex6:捕获非零的行列索引

给定如下数据框,返回所有非零单元格对应的"列-行"组合构成的多级索引:

df = pd.DataFrame( [[0,5,0], [2,1,0], [0,0,6], [0,9,0]], index=list("ABCD"), columns=list("XYZ")) df

期望结果(注意顺序按列优先):

res = pd.Index([ ('X', 'B'), ('Y', 'A'), ('Y', 'B'), ('Y', 'D'), ('Z', 'C')])

参考思路:核心是把二维布尔掩码"摊平"成一维后与"列×行的笛卡尔积索引"对齐:

idx = pd.MultiIndex.from_product([df.columns, df.index]) res = idx[df.to_numpy().ravel() != 0]
  • df.to_numpy().ravel()把 4×3 矩阵按行优先展开,顺序恰好与MultiIndex.from_product([columns, index])的元素一一对应;
  • 布尔索引一次性选出非零位置对应的(列, 行)组合。

本题考察MultiIndex.from_product构造笛卡尔积多级索引、ravel展平以及布尔索引三者的配合,属于索引章节中多层索引构造的应用(参见 source/Content/ch3.rst)。


Ex7:分析集群日志

Ex7 是整套补充习题中数据量最大、综合性最强的一道,考察文本解析、脏数据清洗、连接、透视与区间合并等多项能力。

数据说明

data/supplement/ex7/logs.txt 共约 35 万行(实测 350668 行),是某分布式文件集群 2022-09-27 一天的文件传输日志。集群共 134 台服务器,分布于五个机房:R0 机房 23 台、R1 机房 16 台、R2 机房 47 台、R3 机房 30 台、R4 机房 18 台,每机房服务器编号从 001 开始。单行日志格式:

[PUSH|2022-09-27 07:08:12] Cluster#R1#007 | tgfuHOAjDJ | 4.41 GB [SAVE|2022-09-27 08:17:00] Cluster#R0#019 | neLAGbGkvd | 7.99 GB

字段含义:

  • 方括号内为操作类型与操作时间:PUSH表示向其他服务器发出文件,SAVE表示接收其他服务器文件;
  • Cluster#R4#014表示 R4 机房第 14 号机器;
  • 十位字符串为传输文件的唯一标识file_id;
  • 末尾为文件大小(带单位,如4.41 GB、91.64 MB);
  • 若 SAVE 机器接收了某文件,则必然存在另一台机器 PUSH 该文件的记录;若同一对 PUSH/SAVE 的文件大小不一致,则该次传输处于未完成状态(Unfinished)。

日志读取示例:

with open("data/supplement/ex7/logs.txt", "r") as f: for i, txt in enumerate(f.readlines()): if i >= 5: break print(txt.strip())

Q1:解析日志并清洗脏数据

要求用高效方法提取信息,清洗脏数据(时间格式错误、无效数字),输出如下格式(push_time按时间排序):

pd.DataFrame({ "file_id": ["wfjqoIDhsD", "QigjDSEGje", "..."], "file_size": [6.35, 149.23, "..."], "save_size": [6.32, np.nan, "..."], # np.nan 表示没收到 "push_from": ["A3-007", "A0-017", "..."], "push_to": ["A2-012", np.nan, "..."], # np.nan 表示没收到 "push_time": pd.to_datetime(["20220927 01:03:55", "20220927 01:03:58", pd.NaT]), "save_time": pd.to_datetime(["20220927 01:03:57", pd.NaT, pd.NaT]), }, index=[0, 1, "..."])

参考思路:

  1. 正则解析:用str.extract一次性拆出操作类型、时间、机房、机器号、file_id、大小与单位:

    pat = r'\[(PUSH|SAVE)\|([0-9\- :]+)\]\s+Cluster#(R\d)#(\d+)\s+\|\s+(\w+)\s+\|\s+([\d.]+)\s+(\w+)'
  2. 单位统一:把GB/MB统一换算为统一单位(如 MB 或 GB),将无效数字清洗为 NaN;

  3. 时间清洗:把时间字符串用pd.to_datetime转为时间戳,非法时间清洗为pd.NaT;

  4. 宽表拼接:题目提示"本质上是把两个一一对应的文件信息进行连接"——先分别构造 PUSH 表与 SAVE 表,再以file_id为键做outer join(因为存在只有 PUSH 没有 SAVE 的 Missed 文件),得到每条文件的一对推送/接收信息。这正是连接章节中方向连接的应用(参见 source/Content/ch6.rst)。

Q2:机房间平均传输速度

对传输完成的文件(PUSH 与 SAVE 大小一致),按发送机房→接收机房分组计算平均速度(MB/s),输出 5×5 矩阵:

pd.DataFrame( np.random.rand(25).reshape(5, -1), index=["R%d" % i for i in range(5)], columns=["R%d" % i for i in range(5)], )

参考思路:速度 = 文件大小 / 传输耗时(save_time - push_time),先构造"push_from 机房 → push_to 机房"两列,再用groupby(['机房_from', '机房_to'])['速度'].mean()聚合,最后unstack成矩阵。可进一步验证题干给出的猜想:矩阵对角线(同机房内传输)均值是否高于非对角线(跨机房传输),这正是分组聚合 + 透视(unstack/pivot_table)的综合应用。

Q3:各机房传输状态比例

定义文件传输状态:

  • Finished:文件大小等于接收大小(传输成功);
  • Missed:日志中只有单条记录(只有 PUSH 没有 SAVE);
  • Unfinished:文件大小不等于接收大小;按传输比例(接收/发出)超过 90% 与超过 50% 分为三档:Unfinished-Almost、Unfinished-Fair、Unfinished-Bad。

输出按状态排序(Finished > Unfinished-Almost > Unfinished-Fair > Unfinished-Bad > Missed)、再按机房号排序的比例表:

pd.DataFrame({ "Status": ["Finished"]*3 + ["..."] + ["Missed"], "Room": ["R0", "R1", "R2", "...", "R5"], "Ratio": [0.1, 0.15, 0.1, "...", 0.05], }, index=[0, 1, 2, "...", 24])

参考思路:基于 Q1 拼接好的宽表,用np.select或pd.cut按比例区间打标签,再用groupby(['Status', '机房']).size() / 总数计算比例,最后用Categorical类型给 Status 设定有序类别后sort_values。有序类别排序正是分类数据章节(source/Content/ch9.rst)中cat.reorder_categories(ordered=True)的典型应用场景。

Q4:按小时统计大文件收发差

大文件指大小超过 800M 的文件。要求按小时计算每个机房"发送的大文件数 − 接收的大文件数",结果行索引为时间(小时),列索引为机房。参考思路:分别对 PUSH 与 SAVE 记录筛选大文件,groupby(['小时', '机房']).count()后做差(或pivot_table后相减),自然衔接 Q1 的解析结果与dt.floor('H')/resample时间分组。

Q5:按小时统计每台机器的空闲率

对某一台机器,空闲时间指其"既没有处于发送任务中又没有处于接收任务中"的时间;每小时的空闲率 = 该小时区间内空闲时间占比。输出行索引为时间、列索引为机器。

题目给出了两条外部提示:

本题涉及到了区间合并问题,pandas 的区间索引没有定义类似于 merge intervals 的函数,请阅读 Stack Overflow 上"Efficient merge overlapping intervals in same pandas dataframe with start and finish"的讨论来思考如何实现。

参考思路:把每台机器的每条 PUSH/SAVE 记录视为一个"忙碌区间"[start, end],先按机器对区间做合并(merge intervals),得到互不重叠的忙碌区间集合,再用合并后的总忙碌时长反推空闲时长;按小时切分(pd.interval_range或cut)计算每小时的空闲占比。核心难点在于:pandas 的IntervalIndex只提供区间构造与索引能力,并未内置区间合并函数,需要自行用排序 + 贪心扫描实现,这是本题对"时序数据 + 区间运算"能力的最高阶考查。


总结:补充习题的技术地图

习题主题核心 API / 技巧关联章节
Ex1NumPy 向量化np.diff、np.argsort、广播、三维数组聚合第一章 预备知识
Ex2学生成绩统计groupby、nlargest、rank、加权聚合第二章/第四章
Ex3商品审核分析groupby.head/tail、sort_values、外连接第四章/第六章
Ex4删除重复行merge(indicator=True)第六章 连接
Ex5学区开课统计str.split、explode、crosstab第五章/第八章
Ex6非零索引捕获MultiIndex.from_product、ravel、布尔索引第三章 索引
Ex7集群日志分析正则解析、outer join、区间合并第六章/第十章

整套补充习题的练习数据均位于仓库 data/supplement 目录下,配套代码环境与正文章节保持一致(import numpy as np; import pandas as pd; import matplotlib.pyplot as plt)。各章正文与章末习题的参考实现可对照 参考答案.rst 学习。建议读者在动手时严格遵循题首要求"尽可能不要使用任何 for 或 while 循环"——当你发现自己忍不住要写循环时,停下来思考对应的 pandas/NumPy 向量化写法,这正是 Joyful Pandas 训练的核心目标。

  • 文档
  • 教程
  • 数据分析

【免费下载链接】joyful-pandas

pandas中文教程

项目地址:https://gitcode.com/gh_mirrors/jo/joyful-pandas
点击查看免费下载

相关推荐

上一篇:三大技术突破:OpenCore Legacy Patcher如何让旧Mac重获新生
下一篇:从零到一:Embodied-AI-Guide具身智能完整学习路线图与实战指南

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询