数据科学全流程实战:从Pandas清洗到Spark分布式计算

📅 发布时间:2026/9/8 4:11:51
数据科学全流程实战:从Pandas清洗到Spark分布式计算 大家在学习数据科学时是不是经常有这种感觉单看 Pandas 的 API 能看懂SQL 查询也会写机器学习模型能调库但一旦要把“数据获取 → 清洗 → 建模 → 部署 → 分布式扩展”整个流程串起来就会卡壳。网上的资料大多是零散的知识点缺少一条贯穿始终的主线。如果你正处于这个阶段UC Berkeley 的Data 100Data Science Principles and Techniques是一门非常值得系统跟完的课程。它是伯克利本科高年级的数据科学核心课覆盖了 Pandas 数据处理、SQL 查询、可视化、机器学习建模、特征工程以及 Spark 分布式计算。更重要的是它的作业和 Project 都是完整的数据科学实战项目而不是割裂的小练习。这篇文章会结合 Data 100 的课程主线把数据科学全流程的关键环节拆开来讲。你可以把它当作一份学习笔记 实战手册也可以作为跟课之外的中文补充材料。全文会涉及大量可复制的 Python 代码、SQL 查询和 Spark 示例适合有 Python 基础、想系统补齐数据科学项目能力的学习者。1. 数据科学全流程先建立整体认知在 Data 100 的第一周课程就会强调一个核心理念数据科学不是机器学习也不是单纯的统计学而是一套从问题定义到数据洞察的完整方法论。1.1 数据科学项目的五个阶段一个标准的数据科学项目通常包含以下步骤阶段核心任务常用工具提出问题明确业务目标把业务问题转化为数据问题无数据获取从数据库、API、文件中读取数据SQL、pandas.read_csv、requests数据清洗处理缺失值、异常值、重复数据统一格式pandas、numpy建模与分析特征工程、模型训练、参数调优、结果评估scikit-learn、statsmodels部署与扩展把模型应用到大规模数据上Spark、Flask、云平台Data 100 的 Project 1 通常会让大家用 pandas 完成一份完整的数据探索报告Project 2 开始引入机器学习建模Project 3 则会把数据量放大引导大家使用 Spark 来处理单机 pandas 跑不动的数据。1.2 为什么是“全流程”而不是单一工具很多初学者容易陷入“只学工具”的误区。比如花两周时间背 pandas 函数或者专门研究 matplotlib 的画图参数。但真实的数据科学项目里工具只是手段流程才是骨架。Data 100 的课程设计正好对应了这个骨架Data 100 前 1/3pandas SQL 可视化解决“如何拿到并理解数据”。Data 100 中 1/3回归、分类、特征工程解决“如何用数据做预测”。Data 100 后 1/3Spark 大规模数据处理解决“数据太大单机跑不动怎么办”。下面我们就按照这条主线逐个环节展开。2. 环境准备与版本说明在开始动手之前先把环境准备好。Data 100 的官方作业是在 Jupyter Notebook / JupyterLab 中完成的本地环境推荐使用 Anaconda 管理。2.1 软件环境清单组件版本建议说明Python3.9 / 3.10 / 3.113.12 部分旧库可能不支持Anaconda最新稳定版自带 conda 包管理JupyterLab随 Anaconda 安装建议 3.x 以上pandas1.5.x 或 2.x1.x 最稳2.x 新增功能SQLite / SQLAlchemy随环境安装课程初期使用 SQLite 较多scikit-learn1.2.x 以上机器学习建模PySpark3.4.x 或 3.5.x大数据部分使用2.2 安装核心依赖如果你已经有 Anaconda可以直接在终端里执行conda create -n data100 python3.10 -y conda activate data100 conda install pandas numpy matplotlib seaborn scikit-learn jupyter -y conda install -c conda-forge pyspark3.4.1 -y这里是创建了一套独立环境避免和系统 Python 冲突。pandas、numpy、matplotlib、seaborn 是数据分析标配scikit-learn 用于机器学习pyspark 是 Spark 的 Python 接口。验证安装import pandas as pd import sklearn print(pd.__version__) print(sklearn.__version__)如果正常输出版本号说明环境没问题。注意如果只是跟课学习 pandas 和机器学习可以先不安装 PySpark等学到 Spark 章节再装也不迟。3. pandas 数据分析核心技能Data 100 的前半部分会花大量时间讲解 pandas。但课程并不是机械地罗列 DataFrame 的 API而是强调用 pandas 完成数据探索的思维方式。3.1 读取数据与初步检查拿到一份数据后不要急着画图或建模。第一步是“摸清数据底细”import pandas as pd # 读取 CSV 文件 df pd.read_csv(data/sample_data.csv) # 查看前 5 行 print(df.head()) # 查看数据规模 print(df.shape) # 查看列名、非空计数、数据类型 print(df.info()) # 描述性统计 print(df.describe())这里有几个关键点df.shape返回(行数, 列数)让你立刻知道数据量级。df.info()用来检查每列是否有缺失值以及数据类型是否正确。比如年龄列被读成了object而不是int说明里面混入了脏数据。df.describe()只统计数值型列可以快速发现异常范围比如最大年龄是 999明显有问题。3.2 数据清洗实战数据清洗是数据科学项目中最耗时的一步。Data 100 会涵盖以下几类典型操作。缺失值处理# 统计每列缺失值数量 print(df.isnull().sum()) # 删除缺失值过多的列例如缺失超过 50% threshold len(df) * 0.5 df df.dropna(axis1, threshthreshold) # 用均值填充数值列缺失值 df[salary] df[salary].fillna(df[salary].mean()) # 用前向填充处理时间序列缺失值 df[price] df[price].ffill()数据类型转换这是热词里“pandas 数据类型转换”对应的高频场景# 字符串转数值 df[age] pd.to_numeric(df[age], errorscoerce) # 字符串转日期 df[date] pd.to_datetime(df[date], errorscoerce) # 分类变量转 category 类型节省内存 df[gender] df[gender].astype(category)这里特别说明一下errorscoerce当某个值无法解析时会被转换成NaN而不是直接报错。这在处理脏数据时非常常用。重复数据处理# 查看重复行数量 print(df.duplicated().sum()) # 删除重复行保留第一条 df df.drop_duplicates()3.3 分组聚合与透视表分组聚合是业务数据分析最核心的操作对应 SQL 里的GROUP BY。# 按部门分组计算平均薪资 result df.groupby(department)[salary].mean() print(result) # 多列聚合 result df.groupby([department, gender]).agg( avg_salary(salary, mean), max_age(age, max), count(employee_id, count) ).reset_index() print(result.head())agg()函数可以同时对不同列执行不同聚合操作输出结果会自动命名列名如avg_salary。如果需要生成类似 Excel 透视表的输出可以用pivot_tablepivot pd.pivot_table( df, valuessalary, indexdepartment, columnsgender, aggfuncmean ) print(pivot)3.4 pandas 数据清洗实战一个完整示例下面用一个综合示例把上面的知识点串起来。假设有一份用户注册信息表包含脏数据import pandas as pd import numpy as np # 模拟一份脏数据 data { user_id: [1, 2, 3, 4, 5, 6], name: [张三, 李四, 王五, 赵六, 钱七, 孙八], age: [25, 30, unknown, 22, 40, 18], signup_date: [2024-01-01, 2024/02/15, 2024-03-30, 20240315, 2024-05-01, None], city: [北京, 上海, 北京, 广州, None, 深圳], spend: [100.5, 200, None, 50.2, 99.9, 1500] } df pd.DataFrame(data) print(原始数据) print(df) print() # 1. 清洗 age转为数值无法转换的设为 NaN df[age] pd.to_numeric(df[age], errorscoerce) # 2. 清洗 signup_date统一日期格式 df[signup_date] pd.to_datetime(df[signup_date], errorscoerce) # 3. 处理 spend 缺失值用城市平均消费填充 df[spend] df.groupby(city)[spend].transform(lambda x: x.fillna(x.mean())) # 4. 删除年龄缺失的行因为只有一条且无法估算 df df.dropna(subset[age]) # 5. 删除完全重复的行 df df.drop_duplicates() print(清洗后数据) print(df) print() print(数据类型) print(df.dtypes)运行这段代码你会发现脏数据被逐步规整年龄列从字符串变成了数值日期格式统一了缺失消费被填充年龄未知的行被删除。这就是 Data 100 里强调的“数据清洗不是一次性工作而是反复探索和修正的过程”。4. SQL 查询从数据库取数的基本功Data 100 的 SQL 部分并不仅仅是教SELECT ... FROM ... WHERE而是强调“如何在数据获取阶段就做好过滤和聚合减少 Python 端的计算压力”。4.1 基本查询与聚合-- 查询所有字段限制返回 10 行 SELECT * FROM users LIMIT 10; -- 条件过滤 排序 SELECT user_id, name, age FROM users WHERE age 18 AND city Beijing ORDER BY age DESC LIMIT 20;4.2 SQL 窗口函数Data 100 考试与面试高频考点热词里出现了“SQL 窗口函数”这也是 Data 100 中大作业常考察的内容。窗口函数可以在不改变行数的情况下对每行计算分组聚合结果。-- 按部门分组给每个员工计算薪资排名 SELECT department, employee_name, salary, ROW_NUMBER() OVER (PARTITION BY department ORDER BY salary DESC) AS rn FROM employees; -- 计算累计薪资 SELECT department, employee_name, salary, SUM(salary) OVER (PARTITION BY department ORDER BY employee_name) AS cum_salary FROM employees;窗口函数和GROUP BY的区别在于GROUP BY会压缩行数而窗口函数保留了每一行的原始信息只是在旁边多了一列计算结果。4.3 Python 中调用 SQL在数据科学项目中通常会通过sqlite3或SQLAlchemy在 Python 中执行 SQL 查询。import sqlite3 import pandas as pd # 连接 SQLite 数据库内存模式 conn sqlite3.connect(:memory:) # 创建示例表 conn.execute( CREATE TABLE employees ( department TEXT, employee_name TEXT, salary INTEGER ) ) # 插入数据 conn.executemany( INSERT INTO employees VALUES (?, ?, ?), [ (Engineering, Alice, 15000), (Engineering, Bob, 12000), (Sales, Charlie, 11000), (Sales, David, 9000), ] ) conn.commit() # pandas 直接读取 SQL 查询结果 df pd.read_sql_query( SELECT department, employee_name, salary, ROW_NUMBER() OVER (PARTITION BY department ORDER BY salary DESC) AS rn FROM employees , conn) print(df) conn.close()输出department employee_name salary rn 0 Engineering Alice 15000 1 1 Engineering Bob 12000 2 2 Sales Charlie 11000 1 3 Sales David 9000 2这种“SQL 负责取数、pandas 负责分析”的组合是数据科学项目最常见的分工。5. 机器学习建模实战Data 100 的机器学习部分不会停留在“调 sklearn 接口”的层面而是重点讲解特征工程和模型评估。课程默认你已经知道基本的回归和分类概念更关注如何从数据中提取有用的特征以及你的模型到底有没有用。5.1 特征工程决定模型上限的环节很多初学者拿到一份 DataFrame 就直接扔给LinearRegression结果效果不好还不知道为什么。特征工程就是在建模之前把原始数据转换成更能表达业务含义的格式。import pandas as pd import numpy as np df pd.DataFrame({ price: [100, 250, 80, 120, 300], area: [50, 120, 40, 60, 150], rooms: [2, 4, 1, 2, 5], has_garage: [yes, no, no, yes, yes] }) # 1. 数值型特征创建组合特征 df[price_per_area] df[price] / df[area] # 2. 类别型特征One-Hot 编码 df pd.get_dummies(df, columns[has_garage], prefixgarage, dtypeint) print(df.head())输出price area rooms price_per_area garage_no garage_yes 0 100 50 2 2.000000 0 1 1 250 120 4 2.083333 1 0 2 80 40 1 2.000000 1 0 3 120 60 2 2.000000 0 1 4 300 150 5 2.000000 0 1price_per_area是组合特征表达“每平米单价”比单独的price和area更有业务含义。pd.get_dummies()把字符串类别转成了 0/1 数值列这样才能输入到 sklearn 模型中。5.2 构建完整的建模 PipelineData 100 中期 Project 会引导学生使用sklearn.pipeline.Pipeline将预处理和模型训练流程封装起来。from sklearn.pipeline import Pipeline from sklearn.compose import ColumnTransformer from sklearn.preprocessing import StandardScaler, OneHotEncoder from sklearn.linear_model import LinearRegression from sklearn.model_selection import train_test_split from sklearn.metrics import mean_squared_error # 准备数据 X df[[area, rooms, has_garage]] y df[price] # 划分训练集和测试集 X_train, X_test, y_train, y_test train_test_split(X, y, test_size0.2, random_state42) # 定义预处理数值特征标准化类别特征 One-Hot numeric_features [area, rooms] categorical_features [has_garage] preprocessor ColumnTransformer( transformers[ (num, StandardScaler(), numeric_features), (cat, OneHotEncoder(), categorical_features) ] ) # 构建 Pipeline pipeline Pipeline(steps[ (preprocessor, preprocessor), (regressor, LinearRegression()) ]) # 训练 pipeline.fit(X_train, y_train) # 预测与评估 y_pred pipeline.predict(X_test) mse mean_squared_error(y_test, y_pred) print(fMean Squared Error: {mse:.2f})使用 Pipeline 的好处是把数据预处理和模型打包在一起训练集和测试集使用同一套预处理逻辑避免数据泄露。5.3 模型评估不要只看准确率Data 100 会反复强调不同业务场景下模型评估指标完全不同。回归问题常用 RMSE均方根误差和 R²分类问题常用准确率和 F1-score。from sklearn.metrics import r2_score, accuracy_score, f1_score # 回归评估 r2 r2_score(y_test, y_pred) print(fR²: {r2:.2f}) # 分类评估示例如果是分类问题 # y_pred_class pipeline.predict(X_test) # acc accuracy_score(y_test, y_pred_class) # f1 f1_score(y_test, y_pred_class, averageweighted)实际项目中还要注意类别不均衡问题如果正样本只占 1%即使模型把全部样本预测为负类准确率也有 99%但这个模型没有实际价值。这时候要重点关注 Precision、Recall 和 F1-score。6. Spark 分布式计算入门Data 100 的后半部分会突然切换到 Spark很多同学刚学完 pandas 会觉得不习惯。其实 Spark 的核心数据结构 DataFrame 和 pandas 非常相似只是它把计算分布到了多台机器或多核上。要理解 Spark 在大数据处理中的作用可以参考英伟达近期与 Spark 生态的整合趋势——当数据量级达到 TB 甚至 PB 级别单机内存已经无法承载分布式计算框架成为必需。6.1 Spark DataFrame 与 pandas 的对应关系先看一个最简单的对比# pandas 读取 CSV import pandas as pd pdf pd.read_csv(data.csv) print(pdf.groupby(city)[sales].sum())# Spark DataFrame 读取 CSV from pyspark.sql import SparkSession spark SparkSession.builder.appName(data100_demo).getOrCreate() sdf spark.read.csv(data.csv, headerTrue, inferSchemaTrue) sdf.groupBy(city).sum(sales).show()两者语法非常接近pandas 的groupby()对应 Spark 的groupBy()pandas 的print()对应 Spark 的.show()。区别在于Spark 的show()只会打印前 20 行到控制台因为 DataFrame 可能分布在多台机器上不能直接print整个对象。6.2 何时使用 SparkSpark 并非任何时候都比 pandas 好。课程会明确告诉你场景推荐工具数据量在几百 MB 到几 GB单机内存放得下pandas数据量在几十 GB 以上或需要分布式计算Spark需要复杂的数据可视化探索pandas matplotlib/seaborn需要处理海量日志、ETL 清洗Spark快速原型验证pandas生产环境大规模数据处理Spark如果你的本机只有 8GB 内存强行读取 20GB 的 CSVpandas 会直接内存溢出而 Spark 可以将数据分片加载分而治之。6.3 Spark 数据处理实战日志 ETL下面是一个常见的 ETL 场景读取原始日志文件过滤掉空数据按时间维度聚合最后输出结果。from pyspark.sql import SparkSession from pyspark.sql.functions import col, to_date, count # 创建 SparkSession spark SparkSession.builder \ .appName(log_etl) \ .master(local[*]) \ .getOrCreate() # 读取 CSV logs spark.read.csv( logs/, headerTrue, inferSchemaTrue ) # 查看原始数据规模 print(f原始数据量: {logs.count()} 行) # 过滤空 user_id logs_clean logs.filter(col(user_id).isNotNull()) # 转换日期格式 logs_clean logs_clean.withColumn(dt, to_date(col(timestamp))) # 按日期统计活跃用户数 daily_stats logs_clean.groupBy(dt).agg( count(user_id).alias(active_users) ) # 展示结果 daily_stats.orderBy(dt).show() # 保存结果覆盖模式 daily_stats.write.mode(overwrite).csv(output/daily_stats/)关于热词中提到的 “spark on yarn cpu 只能用 1 个” 的问题这里顺带说明当你用local[*]时Spark 会使用本机所有 CPU 核心但如果提交到 YARN 集群每个 Executor 的 CPU 核心数是由spark.executor.cores配置决定的默认可能只有 1 个 vCore。你可以在提交任务时指定spark-submit \ --master yarn \ --deploy-mode cluster \ --executor-cores 4 \ --num-executors 10 \ --executor-memory 8g \ job.py如果不指定这些参数YARN 会按默认配置分配资源这往往与你的需求不符。6.4 Spark 与 pandas 的互操作Data 100 的 Project 3 里你经常会需要在 Spark 和 pandas 之间切换。比如先用 Spark 做大体量的数据聚合再把聚合结果转成 pandas 做可视化。# Spark DataFrame 转 pandas DataFrame pandas_df logs_clean.limit(1000).toPandas() # pandas DataFrame 转 Spark DataFrame spark_df spark.createDataFrame(pandas_df)注意toPandas()会把数据全部收集到 driver 节点也就是你的本机所以只适合转换结果量较小的数据。如果分布式跑出 10 亿行直接toPandas()会导致内存溢出。7. 综合实战从数据获取到建模的完整项目为了让整篇文章的流程连贯起来这一节给出一个综合案例把前面讲的 pandas、SQL、机器学习、Spark 串到一条主线上。这个案例参考了 Data 100 Project 的常见形式但是做了简化方便你在本地跑通。业务场景假设你是一家电商公司的数据分析师需要分析用户消费行为并预测用户的下单金额。7.1 数据准备import pandas as pd import numpy as np # 生成模拟数据 np.random.seed(42) n 2000 users pd.DataFrame({ user_id: range(1, n 1), age: np.random.randint(18, 60, n), gender: np.random.choice([M, F], n), city: np.random.choice([Beijing, Shanghai, Guangzhou, Shenzhen], n), signup_days: np.random.randint(1, 365, n), total_orders: np.random.randint(1, 50, n), avg_order_value: np.round(np.random.uniform(20, 500, n), 2) }) # 添加少量缺失值 users.loc[np.random.choice(n, 50, replaceFalse), age] np.nan users.loc[np.random.choice(n, 30, replaceFalse), avg_order_value] np.nan users.to_csv(user_data.csv, indexFalse) print(users.head())7.2 数据清洗与特征工程# 读取数据 df pd.read_csv(user_data.csv) print(f原始数据量: {df.shape}) print(f缺失值统计:\n{df.isnull().sum()}) # 数据清洗 df[age] pd.to_numeric(df[age], errorscoerce) df[age] df[age].fillna(df[age].median()) df[avg_order_value] df[avg_order_value].fillna( df.groupby(city)[avg_order_value].transform(median) ) # 特征工程创建消费总额特征 df[total_spend] df[total_orders] * df[avg_order_value] # 创建交互特征平均订单价值 * 注册天数表示用户活跃度和价值的综合指标 df[engagement_score] df[avg_order_value] * np.log1p(df[signup_days]) # One-Hot 编码城市和性别 df pd.get_dummies(df, columns[city, gender], dtypeint) print(f清洗后数据量: {df.shape}) print(df.head())7.3 训练机器学习模型from sklearn.model_selection import train_test_split from sklearn.ensemble import RandomForestRegressor from sklearn.metrics import mean_squared_error, r2_score # 特征列 features [age, signup_days, total_orders, avg_order_value, engagement_score, city_Beijing, city_Guangzhou, city_Shanghai, city_Shenzhen, gender_F, gender_M] X df[features] y df[total_spend] X_train, X_test, y_train, y_test train_test_split(X, y, test_size0.2, random_state42) # 随机森林模型 model RandomForestRegressor(n_estimators100, max_depth8, random_state42) model.fit(X_train, y_train) y_pred model.predict(X_test) print(fRMSE: {mean_squared_error(y_test, y_pred, squaredFalse):.2f}) print(fR²: {r2_score(y_test, y_pred):.2f}) # 查看特征重要性 feature_importance pd.Series(model.feature_importances_, indexfeatures).sort_values(ascendingFalse) print(特征重要性Top 5) print(feature_importance.head())7.4 使用 Spark 读取并验证结果当数据规模扩大后pandas 可能跑不动了。下面演示用 Spark 读取刚才生成的数据做一个简单的聚合验证from pyspark.sql import SparkSession from pyspark.sql.functions import sum as sql_sum spark SparkSession.builder.appName(simple_validation).master(local[*]).getOrCreate() # 读取数据 sdf spark.read.csv(user_data.csv, headerTrue, inferSchemaTrue) # 聚合统计 result sdf.groupBy(city).agg( sql_sum(total_orders).alias(total_orders) ) result.show()这段代码展示了同一个业务问题在单机和分布式环境下的处理差异在本地用 pandas 验证逻辑在生产环境用 Spark 处理全量数据。8. 常见问题与排查思路以我自己的学习经验Data 100 的作业和实战项目中经常遇到的问题主要有这几类问题现象常见原因解决思路pandas 读取大 CSV 时内存溢出数据量超过内存使用read_csv的chunksize分块读取或用 Sparkpd.to_numeric()报错数据中包含无法转换的字符串设置errorscoerce将错误值转为 NaN 后再处理sklearn 模型报错输入包含 NaN数据清洗不彻底训练前必须处理缺失值可以用isnull().sum()检查Spark 运行很慢没有合理配置并行度增加spark.executor.cores和spark.executor.memory或调整分区数toPandas()内存溢出收集到 driver 的数据量太大先进行聚合、采样或limit()再转 pandas模型训练集和测试集结果差异大可能存在数据泄露使用 Pipeline 统一预处理逻辑避免在切分前做全局标准化另外单独说一下热词里出现过的 “pycharm 怎么安装 pandas 包” 的问题。如果你的 IDE 是 PyCharm推荐不要直接在 PyCharm 的终端里pip install而是在项目设置里正确配置解释器打开File → Settings → Project → Python Interpreter。点击号搜索pandas点击Install Package。如果安装失败确认当前选择的解释器是 conda 环境还是系统 Python。更推荐的做法是先在终端里激活 conda 环境再启动 PyCharm这样 PyCharm 会自动识别到你当前的环境。9. 最佳实践与工程建议9.1 数据清洗阶段清洗步骤要写成函数或 Pipeline不要直接在 Notebook 里反复手动修改 DataFrame。Data 100 的作业会要求你提交“可重复运行的 Notebook”如果每一步都靠手动修改后续很难回溯。保留原始数据备份。永远不要直接在原始 DataFrame 上原地修改建议df_clean df.copy()。缺失值处理要有业务理由。不要所有列都无脑填充中位数比如“注册时间”缺失和“薪资”缺失的处理逻辑完全不同。9.2 机器学习建模阶段训练集和测试集必须严格分开。任何基于全局数据的操作填充均值、标准化、One-Hot 编码都应该在train_test_split之后进行否则会造成数据泄露。优先使用Pipeline和ColumnTransformer管理预处理流程而不是手动对每个特征变形。评估指标要匹配业务目标。房价预测可以用 RMSE信用卡欺诈检测则要重点看 Precision 和 Recall。9.3 Spark 使用阶段优先用 DataFrame 的声明式 APIselect、filter、groupBy不要写过于复杂的 UDF 自定义函数因为 UDF 会让 Spark 无法优化执行计划。注意show()和count()会触发实际计算。在写代码时可以先.limit(100)再.show()做探索避免每次都跑全量数据。数据倾斜是 Spark 作业性能差的主要原因。如果一个 key 的数据量特别大比如“北京”这个城市有 80% 的数据可以考虑加盐salt或调整分区策略。9.4 代码管理与协作每个 Project 建一个独立目录包含data/、notebooks/、scripts/、output/四个子目录。Notebook 文件建议关闭输出后再提交避免几百 MB 的图片/结果被包含进去。固定 Python 依赖版本用conda env export environment.yml导出环境文件方便别人复现。10. 总结与学习路线到这里Data 100 的核心主线已经梳理了一遍从 pandas 做数据清洗与分析到 SQL 取数与窗口函数再到机器学习建模与评估最后用 Spark 解决大规模数据问题。如果你正在跟 Data 100 的课程建议按这个节奏来学第 1-3 周先熟练 pandas 的groupby、merge、apply、pivot_table这是完成 Project 1 的基础。第 4-5 周把 SQL 的JOIN、窗口函数练熟。特别是窗口函数考试和 Project 都常考。第 6-8 周机器学习阶段不要只调 sklearn 接口多花时间理解特征工程和交叉验证。把Pipeline用熟。第 9-10 周Spark 阶段先理解“分布式”的基本思想再对比 pandas 和 Spark 的语法差异。遇到问题先看执行计划.explain()而不是盲目调参数。最后想说的是Data 100 这门课真正的价值不在于某个具体工具用得多熟而是帮你建立一套数据科学项目的整体思维。以后你拿到任何一份新数据、任何一个新项目都能清楚地知道现在我在哪个阶段我下一步要做什么这一步做完之后怎么验证如果你正卡在“只会局部操作、不会全流程”的阶段希望这份实战笔记能帮你把碎片知识串成一条线。如果本文对你有帮助可以收藏备用也欢迎在评论区交流你写 Project 时遇到的问题。