Python 数据处理工作流:marimo、PyCharm 与数据存储

发布时间:2026/7/13 13:38:31
Python 数据处理工作流:marimo、PyCharm 与数据存储 经过较长时间的实践和调整我们逐渐形成了一套相对成熟的 Python 数据处理流程。这套流程覆盖了数据读取、清洗、转换、分析、可视化以及结果保存等环节。在开发环境方面我主要使用 marimo 进行交互式数据分析并以 PyCharm 作为补充用于脚本开发、代码检查、项目重构和数据库操作。Python 环境和项目依赖则交由 uv 管理。这套工作流并不追求使用尽可能多的工具。相反它更关注如何让不同工具各司其职并尽量保证分析过程清晰、可复现且易于维护。开发环境marimo 笔记本相较于 Jupyter Notebook我现在更喜欢使用 marimo 进行交互式数据分析。marimo 是一个响应式 Python 笔记本。某个变量发生变化后依赖它的单元格会自动更新或者被标记为需要重新运行。这种执行方式使代码、程序状态和输出结果能够保持较好的一致性。传统笔记本的一个常见问题是隐藏状态。我们可能修改了一段代码却忘记重新运行相关单元格也可能删除了变量定义但旧变量仍然保留在内存中。此时页面中显示的代码并不一定能够完整解释当前输出。这类问题在短时间的数据探索中可能并不明显但随着笔记本变长或者项目需要在几个月后重新打开排查成本就会明显增加。marimo 根据变量依赖关系组织执行过程在很大程度上减少了这种不确定性。它的笔记本还会保存为普通的.py文件因此更适合使用 Git 进行版本管理也更方便与其他 Python 工具配合。严格命名带来的好处marimo 对变量定义有相对严格的要求。一个全局变量通常不应在多个单元格中被重复定义因此我们需要更加认真地命名变量。在临时分析中人们经常反复使用df而在 marimo 中更适合根据处理阶段分别命名raw_df cleaned_df summary_df这可能使变量名变长但也让变量的含义更加明确。从短期看严格命名增加了一点输入成本从长期维护的角度看这种成本通常是值得的。清晰的变量名能够帮助我们理解数据所处的处理阶段避免意外覆盖也能减少后续检查未知状态的时间。使用 uv 管理项目我推荐使用 uv 管理 Python 项目及其依赖。相比手动创建虚拟环境并逐个安装包uv 更适合以项目为中心的工作方式。一个简单的初始化过程如下uv init uvaddmarimo pandas numpy scipy matplotlib uv run marimo edit其中pyproject.toml用于描述项目及其依赖.venv保存项目的虚拟环境uv.lock记录解析后的准确依赖版本uv run确保命令在对应项目环境中运行。使用下面的命令即可启动 marimouv run marimo edit也可以直接打开指定笔记本uv run marimo edit analysis.pyuv run会在运行命令前检查项目环境是否与依赖声明保持同步。这种方式减少了手动激活环境和维护依赖版本的负担也让项目更容易在另一台计算机上重新构建。marimo 的基本使用方式与 Jupyter 并没有特别大的差异依然由代码单元格、Markdown 和运行结果组成。主要区别在于marimo 更强调变量依赖、确定性执行和可复现性。具体可以参考marimo 官方网站marimo 官方文档uv 项目管理文档PyCharmPyCharm 是 JetBrains 开发的 Python 集成开发环境。在代码补全、静态检查、调试、项目导航、重构、测试和版本控制等方面PyCharm 都具有比较成熟的支持。从 PyCharm 2025.1 开始原来的 Community Edition 和 Professional Edition 被整合为统一的 PyCharm 产品。核心功能可以免费使用其中也包括 Jupyter Notebook 支持部分高级功能仍需要 Pro 订阅。我主要在两种情况下使用 PyCharm。脚本与模块开发当一段数据处理逻辑仍处于探索阶段时把它放在 marimo 中通常比较方便。我们可以直接观察中间结果并快速修改参数。但当这段逻辑逐渐稳定并开始被多个分析重复使用时就更适合将其整理成独立函数或模块。例如project/ ├── notebooks/ ├── src/ │ └── project_name/ │ ├── readers.py │ ├── cleaning.py │ ├── analysis.py │ ├── plotting.py │ └── storage.py ├── tests/ ├── pyproject.toml └── uv.lock这种组织方式可以将数据读取、清洗、计算、绘图和保存分别放在不同模块中。marimo 负责交互式分析和结果展示PyCharm 则负责维护底层代码。二者不是相互替代的关系而是分别承担探索和工程化开发的任务。数据库操作PyCharm 还可以用于连接和操作数据库。在支持相应功能的版本中可以直接查看数据表、执行 SQL 查询、修改记录和管理表结构。对于 SQLite 这类本地数据库使用 Python 标准库中的sqlite3已经能够完成绝大部分操作。不过在检查表结构、编写 SQL 查询或者查看少量数据时图形化数据库界面往往更加直观。需要注意的是数据库工具的具体可用范围可能取决于当前 PyCharm 版本和订阅状态。统一版 PyCharm 的核心功能可以免费使用但部分高级数据库功能可能仍属于 Pro 功能。PyCharm 的官方说明可以参考统一版 PyCharm 介绍PyCharm 数据科学工具数据读取与清洗数据读取和清洗通常使用 Python 标准库、pathlib和 pandas 完成。对于大多数表格型数据我倾向于先将其直接或间接转换为 pandas 的DataFrame。DataFrame 提供了成熟的索引、筛选、类型转换、缺失值处理、分组和聚合能力适合作为数据处理流程中的通用中间形式。对于规则明确的文本文件可以使用 Python 自带的open()withopen(path,encodingutf-8)asfile:contentfile.read()对于 CSV、Excel 等表格文件则通常直接使用 pandasimportpandasaspd dfpd.read_csv(data.csv)或者dfpd.read_excel(data.xlsx)如果原始文件结构并不标准可以先编写专门的读取函数将不同来源的数据统一转换成 DataFramedfcustom_reader(path)这样做的好处是后面的清洗和分析代码不需要了解原始文件的具体排版。无论数据来自文本文件、电子表格还是其他格式只要读取函数最终返回结构一致的 DataFrame后续流程就可以保持统一。使用 Path 管理文件在处理大量文件时推荐使用pathlib.Path而不是通过字符串拼接路径。例如frompathlibimportPath data_folderPath(data)forfileindata_folder.rglob(*.csv):print(file.name)Path提供了一组直观的属性file.namefile.stemfile.suffixfile.parent它不仅让代码更容易阅读也减少了 Windows、Linux 和 macOS 路径分隔符不同所带来的问题。清洗不仅是删除缺失值数据清洗经常被简单地理解为删除空值但实际工作通常还包括统一列名去除多余空格规范特殊字符转换数据类型检查重复记录处理异常值统一单位检查排序和索引记录数据来源验证关键字段是否存在。例如可以统一处理列名dfdf.rename(columnslambdacolumn:(column.strip().replace( ,_).replace(/,_)))数值列则可以进行显式转换df[value]pd.to_numeric(df[value],errorscoerce,)清洗规则最好保持明确和稳定。如果某个规则会改变原始数据的含义应当将其写入代码和文档而不是依赖人工记忆。同时原始数据应尽量保持不变。比较稳妥的目录结构是data/ ├── raw/ ├── interim/ └── processed/其中raw保存未经修改的原始文件interim保存处理中间结果processed保存最终结构化数据。原始数据最好被视为只读输入。所有清洗和转换结果都应保存到新的位置从而保证分析过程可以追溯和重新执行。数据分析与数值计算pandaspandas 主要用于处理表格数据适合数据筛选缺失值处理分组聚合多表合并长宽表转换时间序列处理描述性统计。DataFrame 的优势是直观、通用并且与大量输入输出格式兼容。因此即使最终数据不以 DataFrame 保存它也非常适合作为读取和清洗阶段的中间表示。NumPyNumPy 提供了 Python 科学计算的基础数组结构适合向量化运算数组索引矩阵计算数值变换随机数生成底层数据结构转换。很多 pandas、SciPy、xarray 和 Matplotlib 操作实际上都建立在 NumPy 数组之上。SciPySciPy 在 NumPy 的基础上提供了更完整的科学计算能力包括插值优化数值积分曲线拟合信号处理统计分析线性代数。在数据分析中如果任务已经超出简单的表格运算通常可以先检查 SciPy 是否已经提供相应的标准实现。使用成熟函数通常比自行实现底层算法更加可靠也更容易验证。数据可视化数据可视化既用于结果展示也用于发现数据质量问题。Matplotlib对于静态绘图和学术图表我主要使用 Matplotlib。它的优势在于控制能力强可以精细调整坐标轴刻度字体图例颜色线型子图布局输出尺寸与分辨率。Matplotlib 比较适合生成论文、报告和演示文稿中的最终图形。随着项目增长建议将重复的绘图逻辑封装成函数避免不同分析使用不一致的样式。例如可以统一设置字体、图片尺寸、颜色和导出格式。Plotly如果需要交互式图表可以考虑使用 Plotly。它支持缩放、悬停提示、选择和动态图例适合数据探索和网页展示。Matplotlib 与 Plotly 的定位有所不同Matplotlib 更适合静态图和精细排版Plotly 更适合交互探索和在线展示。在实际工作中可以先用交互图检查数据再使用 Matplotlib 制作最终图表。数据存储将处理后的数据保存为合适的结构化格式是完整数据流程中非常重要的一步。保存数据时不仅要考虑“能否写入文件”还应考虑是否保留数据类型是否支持元数据是否支持多维数据是否方便查询是否便于交换是否适合长期维护能否从保存结果重新生成分析。不同存储格式解决的问题并不相同。CSVCSV 是最简单、最通用的表格格式之一。它的优点包括易于生成易于人工查看几乎所有数据软件都能读取适合作为交换格式。但 CSV 也存在明显限制数据类型信息有限不支持复杂层级元数据表达能力弱多表关系需要通过多个文件维护单位和说明通常需要另外保存。因此CSV 很适合数据交换和简单结果导出但不一定适合作为复杂项目唯一的长期存储格式。SQLiteSQLite 是一种轻量级关系型数据库不需要单独运行数据库服务器数据库可以保存在单个文件中。它适合保存结构化记录对象之间的关系实验或业务元数据文件索引处理状态汇总结果需要按条件查询的数据。SQLite 支持标准 SQL 查询比大量分散的 CSV 文件更容易维护数据关系。例如可以快速查找满足多个条件的记录而不需要逐个读取文件。不过SQLite 更擅长管理行列式记录和关系数据。对于大型数组、多维数据或包含丰富坐标的数据它未必是最自然的存储形式。xarray 与 NetCDF对于具有明确坐标、维度和多个变量的科学数据xarray 是一个值得考虑的选择。pandas 的 DataFrame 更强调行和列而 xarray 可以更明确地表达维度坐标数据变量单位属性多维关系。xarray 中的Dataset可以包含多个共享坐标的数据变量并允许为数据和坐标附加元数据。数据可以保存为 NetCDFdataset.to_netcdf(processed_data.nc)之后再读取importxarrayasxr datasetxr.open_dataset(processed_data.nc)NetCDF 能够保留坐标、变量、维度和属性因此比 CSV 更适合保存结构较丰富的科学数据。如果数据具有层级结构还可以使用 xarray 的DataTree。DataTree 可以将多个 Dataset 组织成类似文件系统的树形结构并保存到支持分组的 NetCDF 文件中。需要注意的是写入 NetCDF 的属性应尽量使用字符串、整数和浮点数等简单类型。复杂 Python 对象通常不适合直接序列化。如何选择存储方式不同格式并没有绝对的优劣关键在于数据的性质和使用方式。数据类型推荐形式简单二维表格CSV、Parquet需要频繁条件查询的结构化记录SQLite带坐标和元数据的多维数组xarray NetCDF多组层级化科学数据DataTree NetCDF临时交换和人工查看CSV大型分析型表格Parquet在较复杂的项目中也可以组合使用不同格式。例如使用 NetCDF 保存数组和坐标使用 SQLite 保存记录、索引和关系使用 CSV 导出需要共享的简单结果使用 Parquet 保存较大的分析型表格。没有必要强迫所有数据进入同一种格式。从笔记本走向项目交互式笔记本非常适合探索但随着项目变大将所有逻辑都放在笔记本中会逐渐产生维护压力。一种实用的演进方式是在 marimo 中探索数据和验证思路将稳定的逻辑整理为函数在 PyCharm 中将函数拆分到独立模块为关键逻辑添加测试在 marimo 中导入这些模块并完成交互分析使用 uv 管理项目依赖和运行环境将原始数据、处理结果与代码分别管理。这种方式保留了笔记本的灵活性同时也获得了普通 Python 项目的可维护性。可复现性比“能够运行”更重要一段代码在当前计算机上成功运行并不意味着它已经构成了可靠的数据工作流。一个相对完整的流程还应回答数据来自哪里使用了哪些依赖版本数据经过了哪些处理步骤中间结果如何产生参数是否被记录原始数据是否保持不变更换计算机后能否重新运行几个月后是否还能理解代码最终结果能否从保存的数据重新生成为了提高可复现性我通常遵循以下原则原始数据只读保存使用项目环境隔离依赖将pyproject.toml和uv.lock纳入版本控制使用明确的变量名将重复逻辑封装为函数将稳定代码移出笔记本保存必要的元数据和单位在关键步骤增加输入验证避免依赖手工执行顺序尽量让结果可以从代码和原始数据重新生成。工具之间的职责分工目前这套工作流中的工具大致承担以下职责类别工具主要用途项目和依赖管理uv管理Python版本、依赖、虚拟环境和锁文件交互式分析marimo数据探索、过程检查、交互分析和结果展示工程化开发PyCharm脚本开发、调试、重构、测试和数据库操作路径管理pathlib文件遍历和跨平台路径处理表格数据处理pandas读取、清洗、转换、合并和统计数值计算NumPy、SciPy数组运算、拟合、优化和科学计算静态可视化Matplotlib学术绘图和精细排版交互可视化Plotly数据探索和交互展示多维数据管理xarray管理坐标、维度、变量和元数据关系型数据管理SQLite保存结构化记录、关系和索引表格交换CSV、Parquet数据交换和分析型表格存储科学数据存储NetCDF保存多维数据、坐标与元数据总结这套 Python 数据处理工作流的重点并不是某一个具体工具而是让不同工具承担适合自己的任务。marimo 提供了响应式、可复现的交互分析环境PyCharm 提供了成熟的代码开发、调试和重构能力uv 让项目依赖和运行环境更加可控pandas、NumPy 和 SciPy 构成了数据处理与数值计算的基础Matplotlib 和 Plotly 分别服务于静态与交互式可视化xarray、NetCDF 和 SQLite 则用于保存不同类型的结构化数据。随着项目不断发展工作流也会持续调整。但有几个目标始终不会改变数据来源应当清楚处理过程应当能够检查运行环境应当可以重建最终结果应当能够复现。相比一次性得到某个结果我更希望建立一套在较长时间后仍然能够理解、维护和继续使用的数据处理体系。