从数据清洗到可视化:用Python分析SpaceX发射记录的数据科学实战
1. 项目概述从数据视角看商业航天最近在整理个人项目库时翻到了一个挺有意思的旧项目叫“SpaceX火箭分析”。这项目乍一看名字挺唬人好像要搞什么高深的航天动力学仿真。其实不然它的核心是数据分析目标是通过公开数据去解读一家商业航天公司——SpaceX——在火箭发射与回收这项核心业务上的表现、趋势与背后的商业逻辑。我自己做这个项目的初衷源于对两个领域的交叉兴趣一是对航天科技发展的持续关注二是作为数据从业者总想用数据去验证或解构一些宏观叙事。市面上关于SpaceX的讨论很多有惊叹于技术突破的也有分析其商业模式的但很多结论缺乏数据支撑流于观点。这个项目就是想做点“接地气”的事用数据说话看看那些被反复提及的“高成功率”、“低成本”、“快速迭代”究竟体现在哪些具体指标上又是如何演变的。简单来说这是一个数据驱动的分析型项目。它不涉及火箭发动机的流体力学模拟也不涉及轨道动力学的复杂计算而是聚焦于对已发生事件的结构化信息进行采集、清洗、分析和可视化。适合的读者群体很广对航天感兴趣的爱好者可以通过它获得一个数据化的观察视角数据分析的初学者可以将其作为一个完整的分析案例学习从数据获取到洞察呈现的全流程甚至对商业分析感兴趣的朋友也能从中看到如何用数据指标来衡量一家技术驱动型公司的运营效率。项目的核心输入是公开的发射记录数据输出则是一系列揭示规律、验证假设的数据洞察。接下来我会详细拆解这个项目的完整实现思路、技术细节以及我在实操中积累的经验与教训。2. 项目整体设计与数据源解析做任何数据分析项目第一步也是最关键的一步就是明确分析框架和找到可靠、可持续的数据源。拍脑袋空想几个图表没有意义必须让分析目标驱动数据需求再让可获得的数据修正和丰富分析维度。2.1 分析维度与核心问题定义在动手写一行代码之前我花了大量时间构思到底要通过数据回答哪些问题这些问题是否具备分析价值且数据可及最终我围绕SpaceX的火箭业务梳理出以下几个核心分析维度发射活动宏观趋势这是最基础的层面。SpaceX的发射频率是如何随时间变化的是线性增长还是指数增长这直接反映了其产能爬坡和市场需求。任务成功率与可靠性分析航天发射的高风险是共识。那么SpaceX的成功率究竟是多少是否在逐步提升失败案例有无集中模式如特定火箭型号、任务类型、发射阶段火箭复用能力评估这是SpaceX颠覆行业的关键。数据上如何体现例如一枚火箭助推器Booster的平均重复使用次数是多少复用火箭的成功率与新火箭相比有无差异复用周期即两次发射间隔时间是否在缩短发射成本与效率的间接观测直接的成本数据是商业机密但我们可以通过一些代理指标Proxy Metrics来间接分析。例如单位时间内每年的发射次数、每次发射的载荷质量尤其是星链卫星的“拼车”模式、以及复用次数对摊薄成本的潜在影响。载荷与客户分析都为谁发射政府NASA、军方、商业公司、还是自己的星链Starlink不同客户类型的占比变化反映了公司商业策略和收入结构的演变。基于这些维度我将其转化为更具体、可数据化的问题例如“猎鹰9号”火箭B5Block 5型号的发射成功率是多少首次使用的全新助推器与复用助推器的发射成功率有统计学差异吗星链任务占比从何时开始显著提升这对发射频率有何影响火箭助推器的“周转时间”从回收修复到再次发射呈现怎样的下降趋势2.2 数据源的选择、评估与获取策略明确了问题接下来就是找数据。理想很丰满现实常骨感。你需要评估数据源的权威性、完整性、结构化程度和可维护性。核心数据源维基百科 “List of Falcon 9 and Falcon Heavy launches” 页面为什么选它这是目前能找到的关于SpaceX发射记录最全面、更新最及时的公开汇总。社区维护积极每次发射后通常几小时内就会更新。它包含了每次任务的核心字段发射日期、时间、火箭型号、助推器编号、发射地点、载荷信息、客户信息、任务结果、助推器回收情况等。局限性数据是非结构化的HTML表格需要爬取和解析。字段格式可能存在不一致例如日期格式、缩写部分历史数据可能缺失细节。社区维护意味着可能存在短暂错误需要交叉验证。辅助与验证数据源SpaceX官方渠道官方网站的发射清单、官方推特现X。用于验证关键任务信息特别是任务结果和回收情况。官方信息是金标准。专业航天信息站如Spaceflight Now、NASA Spaceflight论坛。这些网站有更详细的任务报道、时间线和专家评论可用于补充背景信息理解某些异常数据背后的原因例如某次发射因天气多次推迟某次回收因海况恶劣而放弃。第三方API如Launch Library 2提供结构化的发射数据API。可以作为备用数据源或用于验证。但其数据本身也部分源自维基百科等公开渠道且可能更新略有延迟。我的数据获取策略我采用了“维基百科为主官方信息校验专业报道补充”的策略。具体技术实现上使用Python的requests库和BeautifulSoup库来爬取维基百科页面解析HTML表格。这里有一个关键技巧维基百科的表格有固定的class属性通常是wikitable利用这一点可以精准定位。import requests from bs4 import BeautifulSoup import pandas as pd url https://en.wikipedia.org/wiki/List_of_Falcon_9_and_Falcon_Heavy_launches response requests.get(url) soup BeautifulSoup(response.content, html.parser) # 通常页面有多个表格需要找到目标表格。可能需要通过索引或表格标题来定位。 # 例如找到所有class为‘wikitable’的表格然后选择第二个索引为1。 tables soup.find_all(table, {class: wikitable}) launch_table tables[1] # 具体索引需根据页面实际情况调整 # 使用pandas直接读取HTML表格 df pd.read_html(str(launch_table))[0]注意网络爬虫必须遵守网站的robots.txt规则并设置合理的请求间隔如time.sleep(2)避免对服务器造成压力。维基百科对善意、低频的爬取相对友好但也要保持克制。此外HTML结构可能发生变化爬虫代码需要一定的容错性或定期检查。获取到原始数据后就进入了最耗时但也至关重要的阶段数据清洗。3. 数据清洗、规整与特征工程实战从维基百科抓取下来的数据是一个“半成品”充满了数据清洗的典型挑战不一致的格式、缺失值、非结构化文本信息需要提取。这部分工作的质量直接决定了后续分析的准确度。3.1 核心字段的清洗与标准化日期与时间原始数据可能是“1 January 2023”或“2023-01-01”等格式。需要统一转换为Python的datetime对象便于进行时间序列分析。df[Date] pd.to_datetime(df[Date], errorscoerce) # errorscoerce将无法解析的转为NaT火箭型号与助推器编号这是分析复用性的关键。字段可能包含“Falcon 9 Block 5 | B1060.5”这样的信息。需要拆解提取火箭型号如“Falcon 9 Block 5”。提取助推器编号如“B1060”。编号后的“.5”表示该助推器的第5次飞行这是一个极其重要的特征需要将其分离出来创建新字段“飞行次数”。# 假设原始字段名为‘Rocket’ # 提取助推器编号例如从‘B1060.5’中提取‘B1060’ df[Booster_ID] df[Rocket].str.extract(r(B\d)) # 提取飞行次数例如从‘B1060.5’中提取‘5’ df[Flight_Number] df[Rocket].str.extract(r\.(\d)$).fillna(1).astype(int) # 新火箭首次飞行记为1任务结果字段可能是“Success”, “Success (…)”, “Failure”, “Partial failure”等。需要创建标准化的分类例如二进制的Success成功和Failure失败或者更细粒度的分类。回收情况文本描述如“Landing on ASOG”, “Expended”, “Drone ship landing failure”。需要解析出关键信息是否尝试回收是否成功回收平台类型陆地着陆场LZ还是无人船ASOG/OCISLY这需要编写自定义的解析函数处理多种文本模式。def parse_landing_outcome(text): if pd.isna(text): return No attempt text_lower text.lower() if landed in text_lower or success in text_lower: if asog in text_lower or ocisly in text_lower or jrti in text_lower: return Drone ship success elif lz in text_lower: return Land zone success elif expended in text_lower or not recovered in text_lower: return Expended elif failure in text_lower or lost in text_lower: return Failure else: return Other/Unknown df[Landing_Outcome] df[Landing outcome column].apply(parse_landing_outcome)载荷与客户从“Payload”列中需要区分是星链Starlink任务、NASA任务如CRS, Crew Dragon、军方任务USSF还是商业客户。这通常通过关键词匹配来实现。def classify_mission(payload_text): if pd.isna(payload_text): return Unknown text str(payload_text).lower() if starlink in text: return Starlink elif crs in text or crew in text or nasa in text: return NASA elif us sf in text or space force in text: return USSF else: return Commercial df[Mission_Type] df[Payload].apply(classify_mission)3.2 关键衍生特征工程清洗完基础数据后为了回答更深层的问题需要创建新的衍生特征发射间隔计算同一发射台或同一枚助推器两次发射之间的天数。这反映了发射节奏和周转效率。df df.sort_values(Date) df[Days_Since_Last_Launch] df.groupby(Launch_Site)[Date].diff().dt.days助推器生涯追踪对于每个唯一的助推器ID如B1060需要计算其累计飞行次数、成功次数、以及每次飞行后的状态是否退役。这需要按助推器ID分组进行累积计算。任务复杂度标签根据载荷目的地如低地球轨道LEO、地球同步转移轨道GTO、月球、火星、是否载人、是否需返回等可以给任务打上“复杂度”标签用于分析不同难度任务的成功率。实操心得数据清洗是“脏活累活”但也是体现分析者功底的地方。建议分步骤、分模块进行清洗每完成一个字段的清洗就进行一次检查例如df[Field].value_counts()。大量使用assert语句来验证数据逻辑例如飞行次数为1的其助推器不应出现在更早的记录中。清洗脚本最好模块化、函数化方便后续数据更新时重新运行。4. 核心分析实现与可视化洞察数据准备就绪后就可以开始用数据回答最初提出的问题了。我主要使用pandas进行数据分析matplotlib和seaborn进行可视化。下面分享几个核心分析点的实现与发现。4.1 发射频率与宏观趋势分析这是最直观的分析。计算每年的发射次数并绘制折线图或柱状图。import matplotlib.pyplot as plt import seaborn as sns # 设置中文字体如需要和样式 # plt.rcParams[font.sans-serif] [SimHei] sns.set_style(whitegrid) df[Year] df[Date].dt.year launches_per_year df.groupby(Year).size() plt.figure(figsize(12, 6)) launches_per_year.plot(kindbar, colorskyblue) plt.title(SpaceX Falcon Series Annual Launch Count) plt.xlabel(Year) plt.ylabel(Number of Launches) plt.xticks(rotation45) # 在柱子上标注数字 for i, v in enumerate(launches_per_year): plt.text(i, v 0.5, str(v), hacenter) plt.tight_layout() plt.show()分析洞察图表会清晰显示SpaceX的发射次数在2018年后开始加速增长尤其在2022、2023年呈现近乎垂直的上升这主要得益于星链Starlink星座的大规模部署。这直观地展示了其“规模化”和“高频次”发射能力的成熟。4.2 任务成功率与可靠性深度分析成功率不能只看一个总数要分层、分阶段看。整体成功率简单计算成功任务数除以总任务数。分型号成功率对比猎鹰9号F9不同批次Block 3, 4, 5以及猎鹰重型FH的成功率。你会发现Block 5的可靠性达到了惊人的高度。分任务类型成功率对比商业发射、NASA任务、星链任务、载人任务的成功率。通常载人任务和NASA关键任务的成功率要求是100%数据上也确实如此。按飞行次数复用次数分析成功率这是验证“复用是否影响可靠性”的关键。将任务按助推器的“飞行次数”分组第1次、第2次、…、第10次分别计算成功率。# 按助推器飞行次数分组计算成功率 success_by_flight_num df.groupby(Flight_Number)[Mission_Outcome_Binary].mean() * 100 # 假设已创建二进制的成功列 plt.figure(figsize(10, 6)) success_by_flight_num.plot(kindline, markero) plt.axhline(ydf[Mission_Outcome_Binary].mean()*100, colorr, linestyle--, labelOverall Avg Success Rate) plt.title(Launch Success Rate vs. Booster Flight Number (Reuse Count)) plt.xlabel(Flight Number (1 New, 1 Reused)) plt.ylabel(Success Rate (%)) plt.legend() plt.grid(True) plt.show()分析洞察我分析的数据显示复用火箭飞行次数1的成功率与新火箭首次飞行相比没有出现统计学上的显著下降甚至在某些高复用次数上保持稳定。这有力地用数据支撑了“火箭复用不影响可靠性”的工程论断。当然样本量特别是高复用次数需要持续关注。4.3 火箭复用能力量化评估平均复用次数计算所有已退役或当前活跃助推器的平均飞行次数。这个数字在逐年攀升。复用周转时间分析对于同一枚助推器计算其每次飞行与上一次飞行的间隔时间“周转时间”。绘制其随时间或随着复用次数增加的变化趋势。# 假设已按助推器ID和日期排序并计算了间隔天数‘Turnaround_Days’ booster_turnaround df[df[Flight_Number] 1].groupby(Booster_ID)[Turnaround_Days].mean() # 可以分析周转时间的中位数、分布以及随年份下降的趋势。回收成功率趋势按年份统计火箭助推器回收尝试的成功率。可以看到从早期频繁的海上回收失败到后期陆地、海上回收都达到极高稳定性的过程。分析洞察数据显示周转时间在显著缩短。早期复用需要数月检修现在对于星链这类常规任务周转时间已压缩到数周甚至更短。这直接关联到发射成本的降低和发射频率的提升。4.4 载荷与客户结构演变计算每年不同任务类型星链、NASA、商业、军方的发射次数占比绘制堆叠面积图或百分比柱状图。mission_type_by_year pd.crosstab(df[Year], df[Mission_Type], normalizeindex) * 100 mission_type_by_year.plot(kindarea, stackedTrue, figsize(14, 7)) plt.title(Mission Type Distribution Over Time (%)) plt.xlabel(Year) plt.ylabel(Percentage) plt.legend(titleMission Type) plt.tight_layout() plt.show()分析洞察图表会清晰地揭示一个战略转折点大约从2021年开始星链任务从零迅速增长并很快占据了年度发射量的绝对主导地位超过50%。这解释了发射频率陡增的原因也反映了SpaceX业务重心从“发射服务提供商”向“太空基础设施运营商”的转变。商业和政府发射则保持了相对稳定的份额。5. 项目难点、问题排查与经验总结这个项目看似思路清晰但在实操中遇到了不少坑。这里记录下主要的挑战和解决方案供大家参考。5.1 数据质量与一致性问题问题维基百科表格的格式会随时间微调字段名可能变化合并单元格处理麻烦文本描述存在多种写法如“Success (payload deployed)” vs “Success”。排查与解决编写健壮的解析器不要依赖固定的列索引而是尝试通过列名th标签内容来定位列。使用try-except块处理可能缺失的字段。正则表达式是利器对于复杂的文本字段如助推器编号、回收描述精心设计的正则表达式regex比简单的字符串包含更可靠。建立数据快照与版本控制每次运行爬虫后将原始数据、清洗后的数据分别以带日期戳的文件名如raw_launches_20231027.csv保存。使用Git管理代码和关键数据快照便于回溯和对比。人工抽样校验定期抽取最新几条记录与SpaceX官方报道进行人工比对确保解析逻辑仍然正确。5.2 分析逻辑的陷阱问题1幸存者偏差。我们分析的都是已发射的火箭。那些在测试中失败、从未执行过正式发射任务的火箭或设计不会被记录在这个列表里。因此基于此数据计算的整体“成功率”可能高于从项目伊始算起的“总成功率”。应对在报告中注明数据范围明确分析的是“已执行的轨道发射任务”的成功率。问题2因果与相关性的混淆。例如“复用次数高的火箭成功率也高”这不能直接推导出“复用提高了可靠性”。更可能的原因是只有性能最稳定、最健壮的火箭才能被选中进行多次复用。这是一个“选择效应”。应对在陈述结论时使用更严谨的语言如“数据显示高复用次数的火箭保持了较高的成功率”而非“复用提高了成功率”。5.3 技术实现优化点使用SQLite或数据库当数据量增大或分析关系复杂时如追踪每个助推器的完整生涯将清洗后的数据存入轻量级数据库如SQLite比单纯操作DataFrame更高效、清晰。自动化与调度使用cronLinux/Mac或Task SchedulerWindows定期运行爬虫和清洗脚本自动更新数据集。结合GitHub Actions可以实现完全自动化的数据流水线。交互式可视化对于探索性数据分析Plotly或Altair库可以生成交互式图表方便自己深度挖掘。最终报告则使用静态的matplotlib或seaborn确保可复现性。5.4 项目扩展方向这个基础分析框架可以沿多个方向深化整合财务与市场数据如果能找到或估算每次发射的合同金额部分政府合同公开可以粗略分析发射收入趋势。结合星链用户增长数据可以尝试构建更简单的商业模型分析。加入竞争对手对比爬取或收集阿里安空间Arianespace、联合发射联盟ULA、俄罗斯航天国家集团Roscosmos等主要对手的发射记录在成功率、发射频率、载荷能力等维度进行横向对比。时间序列预测基于历史发射数据使用ARIMA、Prophet等模型尝试预测未来几个季度或一年的发射次数。网络分析将每次发射涉及的实体火箭、发射台、客户、载荷类型作为节点发射事件作为边构建一个知识图谱分析网络中的关键节点和集群。做这个项目最大的体会是数据分析的价值不在于使用了多复杂的模型而在于能否提出正确的问题并找到合适的数据来清晰地回答它。SpaceX火箭分析项目就是一个很好的例子用公开、相对规整的数据通过系统的清洗、分析和可视化就能揭示出一家明星公司关键业务线的清晰图景验证或修正许多公众印象。整个过程从数据获取的曲折到清洗时的繁琐再到看到图表揭示出明显趋势时的豁然开朗是一个完整的数据科学工作流的微型演练。对于想入门数据分析的朋友我强烈建议从这样一个有明确目标、数据可得、且自己感兴趣的领域项目开始收获会远比学习抽象理论要大得多。