news 2026/9/2 5:54:54

Python数据分析实战:爬取与可视化迈克尔·杰克逊Billboard榜单数据

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Python数据分析实战:爬取与可视化迈克尔·杰克逊Billboard榜单数据

在流行音乐史上,迈克尔·杰克逊(Michael Jackson)是一个无法绕过的名字。他不仅是“流行音乐之王”,更是一位用作品和舞台表现力重新定义了流行音乐标准的艺术家。对于开发者、数据分析师或任何对流行文化数据感兴趣的人来说,分析他的音乐成就,尤其是他在 Billboard Hot 100 榜单上的表现,是一个绝佳的数据分析实践项目。Billboard Hot 100 是美国乃至全球最具权威性的单曲排行榜,一首歌能进入榜单已是成功,而能长期占据高位、多次夺冠,则代表了其巨大的商业成功和流行影响力。

本文将从一个技术实践的角度出发,带你完成一个数据分析项目:如何获取、处理并可视化迈克尔·杰克逊在 Billboard Hot 100 榜单上成绩最好的 25 首歌曲。我们不会仅仅罗列一个歌单,而是会通过编写 Python 脚本,从公开数据源获取信息,进行数据清洗和分析,最终生成一份包含排名、峰值位置、在榜周数等关键指标的可视化报告。这个过程涉及网络爬虫基础、数据清洗、Pandas 数据处理以及 Matplotlib/Seaborn 可视化,适合有一定 Python 基础,希望将编程技能应用于实际场景的开发者。

1. 理解 Billboard Hot 100 与数据获取挑战

在开始写代码之前,我们需要明确目标数据是什么,以及从哪里、如何获取。

1.1 Billboard Hot 100 榜单关键指标

Billboard Hot 100 榜单的排名算法综合考虑了单曲销量、电台点播量和流媒体播放量。对于历史数据(尤其是迈克尔·杰克逊活跃的 80-90 年代),电台和销量是主要因素。我们关心的核心数据字段通常包括:

  • 歌曲名称 (Track Name): 歌曲的主标题。
  • 艺人 (Artist): 演唱者,注意可能有合作艺人。
  • 峰值排名 (Peak Position): 该单曲在 Hot 100 上达到的最高位置(1 表示冠军)。
  • 在榜周数 (Weeks on Chart): 该单曲停留在 Hot 100 榜单上的总周数。
  • 夺冠周数 (Weeks at No.1): 保持在冠军位置的周数。
  • 入榜日期 (Date Entered)/峰值日期 (Peak Date): 历史数据的重要时间维度。

我们的目标是找出迈克尔·杰克逊所有单曲中,根据某种综合标准(例如:峰值排名最高、在榜周数最长、或两者加权)成绩最好的 25 首

1.2 数据来源与获取策略

Billboard 官网并不直接提供完整的历史数据库下载。通常有以下几种获取方式:

  1. 官方 API/数据库: Billboard 有商业 API,但通常收费且针对历史数据的接口有限。
  2. 第三方维基或数据社区: 如 Wikipedia 上 “Michael Jackson singles discography” 页面,通常有整理好的表格,包含 Hot 100 成绩。这是最可行的免费数据来源。
  3. 手动整理: 效率低下,容易出错。

因此,本项目的技术路线将选择从 Wikipedia 页面抓取结构化表格数据。这涉及到使用 Python 的requests库获取网页,以及pandas库直接读取 HTML 中的表格。

注意: 网络爬虫应遵守网站的robots.txt规则,并对目标网站保持友好,避免高频请求。Wikipedia 通常允许适度的机器人访问用于数据收集。

1.3 项目环境准备

我们需要一个 Python 环境(3.7 及以上)和必要的库。建议使用虚拟环境。

创建并激活虚拟环境 (可选但推荐):

# 使用 venv python -m venv mj_billboard_env # 在 Windows 上激活 mj_billboard_env\Scripts\activate # 在 macOS/Linux 上激活 source mj_billboard_env/bin/activate

安装依赖库:

pip install requests pandas matplotlib seaborn lxml html5lib
  • requests: 用于发送 HTTP 请求获取网页内容。
  • pandas: 核心数据分析库,其read_html函数能直接解析 HTML 表格。
  • matplotlib&seaborn: 用于数据可视化。
  • lxml&html5lib: 是pandas.read_html可能需要的 HTML 解析器后端。

2. 抓取与清洗迈克尔·杰克逊单曲数据

我们将从 Wikipedia 的迈克尔·杰克逊单曲目录页面抓取数据。

2.1 使用 Pandas 抓取网页表格

Wikipedia 页面通常有多个表格。我们需要找到包含美国 Billboard 排名信息的那一个。

import pandas as pd # 目标 Wikipedia 页面 URL url = “https://en.wikipedia.org/wiki/Michael_Jackson_singles_discography” # 使用 pandas 的 read_html 读取页面中的所有表格 # 返回一个 DataFrame 的列表 tables = pd.read_html(url) print(f“在该页面上找到了 {len(tables)} 个表格。”) # 通常,单曲成绩表是较大的一个。我们可以遍历查看前几个表格的前几行来定位。 for i, df in enumerate(tables[:5]): # 查看前5个表格 print(f“\n--- 表格 {i} (形状: {df.shape}) ---”) print(df.head(3)) # 打印前3行 print(df.columns) # 打印列名

运行这段代码后,你需要观察输出。通常,包含 “U.S.” 或 “Billboard Hot 100” 列名的表格就是我们需要的。假设我们通过观察发现tables[2]是所需的单曲列表表格。

2.2 初步提取和列筛选

找到正确的表格索引后,我们提取它并查看列结构。

# 假设目标表格是索引为 2 的 DataFrame singles_df = tables[2].copy() # 使用 .copy() 避免后续操作出现警告 print(“原始表格列名:”) print(singles_df.columns.tolist()) print(“\n原始数据预览:”) print(singles_df.head())

你可能会看到类似[‘Single’, ‘Year’, ‘Peak chart positions’, ‘Certifications’, …]的列名。‘Peak chart positions’列通常包含多个国家的排名,我们需要从中解析出美国的 Billboard Hot 100 数据。

2.3 关键数据解析与清洗

这是最核心也最繁琐的一步。‘Peak chart positions’列的内容可能像“1”, “3”, “1”, “10”, …“1 3 1 10 …”,并可能带有注释。我们需要编写函数来提取美国地区的峰值排名。

此外,我们还需要从其他列或通过其他方式获取“在榜周数”。在 Wikipedia 的某些表格版本中,可能直接有 “US (Hot 100)” 和 “US (Main. Rock)” 等子列,或者需要从复杂的合并单元格中解析。

假设一种常见但复杂的情况:‘Peak chart positions’列是一个字符串,各国排名由空格或特定符号分隔,美国通常是第一个或第二个位置。我们需要更稳健的方法。

一个更实用的方法是:直接利用 Wikipedia 表格的MultiIndex列结构pd.read_html在读取复杂表头时,可能会生成多层列索引(MultiIndex)。我们需要检查这个结构。

# 打印多层列索引的详细信息 if isinstance(singles_df.columns, pd.MultiIndex): print(“这是一个多层列索引 (MultiIndex):”) for level in range(singles_df.columns.nlevels): print(f“Level {level}: {singles_df.columns.get_level_values(level).unique()}”) else: print(“这是单层列索引。”)

如果发现类似(‘Peak chart positions’, ‘US’)这样的列,那么提取美国排名就非常简单了:

# 情况一:存在 (‘Peak chart positions’, ‘US’) 列 if (‘Peak chart positions’, ‘US’) in singles_df.columns: singles_df[‘US_Peak’] = pd.to_numeric(singles_df[(‘Peak chart positions’, ‘US’)], errors=‘coerce’) print(“成功提取 US_Peak 列。”) print(singles_df[[‘Single’, ‘US_Peak’]].head())

如果不存在这样清晰的列,我们可能需要更复杂的文本解析,或者寻找其他数据源。为了本教程的可行性,我们假设已经成功提取了‘US_Peak’(峰值排名)和‘US_Weeks’(在榜周数)两列。

数据清洗还包括:

  • 处理缺失值: 对于没有上榜或数据缺失的歌曲,其排名可能为‘—’‘N/A’,转换数值时会变成NaN。我们需要决定是过滤掉还是保留。
  • 统一歌曲名: 可能包含 ““” 引号或 featuring 信息,可以根据分析需求决定是否拆分。
  • 年份处理: 将年份列转换为整数。
# 清洗示例:过滤掉没有美国排名数据的行,并确保排名是数字 cleaned_df = singles_df.dropna(subset=[‘US_Peak’]).copy() cleaned_df[‘US_Peak’] = cleaned_df[‘US_Peak’].astype(int) # 假设我们也有周数列,同样进行处理 if ‘US_Weeks’ in cleaned_df.columns: cleaned_df[‘US_Weeks’] = pd.to_numeric(cleaned_df[‘US_Weeks’], errors=‘coerce’).fillna(0).astype(int) print(f“清洗后数据形状: {cleaned_df.shape}”) print(cleaned_df[[‘Single’, ‘Year’, ‘US_Peak’, ‘US_Weeks’]].head(10))

3. 定义“成绩好”的算法与筛选 Top 25

什么是“成绩好”?这需要定义一个量化标准。常见的有:

  1. 按峰值排名排序US_Peak值越小越好(1 最好)。但这样会把所有冠军单曲并列第一,无法区分。
  2. 按在榜周数排序US_Weeks值越大越好,代表持久生命力。
  3. 综合评分: 一个更合理的办法是结合两者。例如,可以设计一个简单的“榜单得分”
    • 冠军单曲基础分最高。
    • 在榜周数作为加分项。
    • 峰值排名越靠前,基础分越高。

我们来设计一个简单的综合评分算法:

def calculate_score(row): """ 计算单曲综合得分。 规则示例:峰值排名第1得100分,第2得95分,...第100得1分。 在榜周数每多一周加1分。 这是一个非常简化的模型,你可以根据需要调整权重。 """ peak = row[‘US_Peak’] weeks = row.get(‘US_Weeks’, 0) # 如果周数列不存在,则视为0 # 基础分: 线性递减,冠军100分,第100名1分 # 防止 peak > 100 的情况,最低分为0 base_score = max(0, 101 - peak) # 周数加分 weeks_bonus = weeks * 0.5 # 每周加0.5分,权重可调 total_score = base_score + weeks_bonus return round(total_score, 2) cleaned_df[‘Score’] = cleaned_df.apply(calculate_score, axis=1)

现在,我们可以根据这个Score列进行排序,选出 Top 25。

# 按得分降序排列 top_25_df = cleaned_df.sort_values(by=‘Score’, ascending=False).head(25).reset_index(drop=True) print(“迈克尔·杰克逊 Billboard Hot 100 综合成绩 Top 25:”) print(top_25_df[[‘Single’, ‘Year’, ‘US_Peak’, ‘US_Weeks’, ‘Score’]])

4. 数据可视化与洞察分析

有了 Top 25 的数据,我们可以通过图表更直观地展示。

4.1 绘制 Top 25 歌曲得分分布图

使用水平条形图,可以清晰地展示每首歌的得分及其构成(如果需要)。

import matplotlib.pyplot as plt import seaborn as sns # 设置中文字体(如果需要显示中文歌名,请确保系统有中文字体) # plt.rcParams[‘font.sans-serif’] = [‘SimHei’, ‘Arial’] # Windows # plt.rcParams[‘axes.unicode_minus’] = False plt.figure(figsize=(12, 10)) # 创建水平条形图,y轴为歌曲名,x轴为得分 bars = plt.barh(top_25_df[‘Single’], top_25_df[‘Score’]) plt.xlabel(‘综合得分’) plt.title(‘迈克尔·杰克逊 Billboard Hot 100 成绩 Top 25 (按自定义综合得分)’) plt.gca().invert_yaxis() # 得分最高的在顶部 # 在条形末端标注得分 for bar in bars: width = bar.get_width() plt.text(width + 0.5, bar.get_y() + bar.get_height()/2, f’{width:.1f}‘, ha=’left‘, va=’center‘) plt.tight_layout() plt.show()

4.2 绘制峰值排名与在榜周数散点图

这个图可以揭示歌曲的“爆发力”(峰值高)和“耐力”(周数长)之间的关系。

plt.figure(figsize=(10, 6)) scatter = plt.scatter(top_25_df[‘US_Peak’], top_25_df[‘US_Weeks’], alpha=0.7, s=100, c=top_25_df[‘Score’], cmap=‘viridis’) plt.xlabel(‘Billboard Hot 100 峰值排名 (数值越小越好)’) plt.ylabel(‘在榜周数’) plt.title(‘Top 25 歌曲:峰值排名 vs. 在榜周数 (颜色代表综合得分)’) plt.gca().invert_xaxis() # 反转X轴,让排名第1在最右边 plt.colorbar(scatter, label=‘综合得分’) # 为每个点添加歌曲名标签(为避免重叠,可选择性标注) for i, row in top_25_df.iterrows(): # 只标注前几名或特定歌曲 if i < 5: plt.annotate(row[‘Single’], (row[‘US_Peak’], row[‘US_Weeks’]), xytext=(5, 5), textcoords=‘offset points’, fontsize=8) plt.grid(True, linestyle=‘--’, alpha=0.5) plt.tight_layout() plt.show()

4.3 按年代分布分析

查看 Top 25 歌曲主要集中在哪个年代,了解其创作黄金期。

# 将年份转换为年代(例如 1980s) top_25_df[‘Decade’] = (top_25_df[‘Year’] // 10) * 10 decade_counts = top_25_df[‘Decade’].value_counts().sort_index() plt.figure(figsize=(8, 5)) decade_counts.plot(kind=‘bar’, color=‘skyblue’) plt.xlabel(‘年代’) plt.ylabel(‘Top 25 歌曲数量’) plt.title(‘迈克尔·杰克逊 Top 25 热门单曲年代分布’) plt.xticks(rotation=0) for i, v in enumerate(decade_counts): plt.text(i, v + 0.1, str(v), ha=‘center’) plt.tight_layout() plt.show()

5. 项目运行验证与结果解读

5.1 运行完整脚本

将以上关键步骤整合到一个 Python 脚本文件中(例如mj_billboard_analysis.py),并运行它。

预期输出应包括:

  1. 控制台打印出找到的表格数量。
  2. 打印出清洗后的数据预览,包含Single,Year,US_Peak,US_Weeks,Score等列。
  3. 打印出按Score排序的 Top 25 歌曲列表。
  4. 弹出三个图表窗口(或保存为图片文件)。

5.2 结果分析与解读

运行脚本后,你得到的 Top 25 列表可能会包含以下经典歌曲(具体顺序取决于你的评分算法):

  • Billie Jean
  • Beat It
  • Thriller
  • The Way You Make Me Feel
  • Man in the Mirror
  • Smooth Criminal
  • Black or White
  • Remember the Time
  • You Are Not Alone
  • They Don’t Care About Us

从图表中我们可以得到一些洞察:

  • 散点图: 真正的“神曲”通常聚集在图的右上角(即峰值排名非常靠前(左侧)且周数很长)。例如Billie JeanBeat It
  • 年代分布图: 绝大多数歌曲很可能集中在1980年代,这与他的专辑《Thriller》(1982)和《Bad》(1987)的统治性地位相符。
  • 综合得分条形图: 直观地展示了根据你的算法,哪些歌曲的综合商业成绩最突出。

6. 常见问题排查与数据获取优化

在实际操作中,你可能会遇到各种问题。

6.1 网络请求与表格定位问题

问题现象可能原因检查与解决方式
pd.read_html返回空列表或报错1. 网络连接问题。
2. 网页需要 JavaScript 渲染(read_html只能解析静态 HTML)。
3. URL 错误。
1. 检查网络,尝试用浏览器访问该 URL。
2. Wikipedia 通常是静态页面,没问题。如果目标站是动态加载,需用Selenium
3. 确认 URL 是否正确。
找不到包含 Billboard 数据的表格1. 表格索引判断错误。
2. 页面结构已更新。
3. 表格使用了不常见的属性或类名。
1. 遍历tables列表,打印每个df.shapedf.head(2)仔细查看。
2. 手动访问网页,查看元素(F12),确认目标表格的序号或特征。
3. 尝试pd.read_html(url, attrs={‘class’: ‘wikitable’})match=‘Billboard’参数进行过滤。
列名是MultiIndex,不知如何提取MultiIndex结构不熟悉。使用singles_df.columns查看结构,通过元组(‘Level0’, ‘Level1’)进行访问,或使用singles_df.xs(‘US’, axis=1, level=1)进行交叉选择。

6.2 数据清洗与计算问题

问题现象可能原因检查与解决方式
US_Peak列转换数值时大量变成NaN原始数据中包含非数字字符,如“1[注 1]”,“—”, “N/A”使用pd.to_numeric(..., errors=‘coerce’)强制转换,非数字会变NaN。然后使用.fillna().dropna()处理。对于含注释的,可用str.extract(r’(\d+)’)先提取数字。
综合得分算法结果不合理算法权重设置不当,导致周数影响过大或过小。调整calculate_score函数中的公式。例如,将基础分改为非线性(如100 / peak),或调整周数加分的系数。多试几次,观察排序结果是否符合常识。
同一首歌有多个版本(混音)导致重复原始表格可能列出了单曲的不同版本。在排序前,可能需要按歌曲名进行去重,只保留成绩最好的那个版本。使用cleaned_df.sort_values(‘US_Peak’).drop_duplicates(‘Single’)

6.3 可视化与输出问题

问题现象可能原因检查与解决方式
图表中文乱码系统或 Matplotlib 未配置中文字体。1. 若不必须,使用英文歌名。
2. 若必须,需配置中文字体路径。参考代码中的注释,并确保字体文件存在。
散点图标签重叠严重为太多点添加了标签。只对排名前5或前10的歌曲添加标签,或使用adjustText库自动调整标签位置。
脚本在 IDE 中运行不显示图表Matplotlib 的默认后端在某些 IDE 中可能不交互。在脚本开头添加import matplotlib.pyplot as plt后,加上plt.switch_backend(‘TkAgg’)‘Qt5Agg’尝试切换后端。或者使用plt.savefig(‘chart.png’)保存为图片文件。

7. 最佳实践与项目扩展方向

7.1 项目最佳实践清单

  1. 数据源验证: 在编写解析逻辑前,先用浏览器查看网页源码,确认表格结构和数据格式,避免因页面改版导致脚本失效。
  2. 异常处理: 在网络请求、数据解析等步骤添加try-except块,并记录日志,使脚本更健壮。
  3. 数据持久化: 将清洗后的cleaned_df和最终的top_25_df保存为 CSV 或 JSON 文件,避免每次分析都重新抓取。
    cleaned_df.to_csv(‘michael_jackson_singles_cleaned.csv’, index=False) top_25_df.to_csv(‘mj_top_25_billboard.csv’, index=False)
  4. 参数化配置: 将 URL、表格索引、评分算法权重等变量放在脚本开头的配置区域,方便调整。
  5. 函数封装: 将数据抓取、清洗、评分、绘图等步骤封装成独立函数,提高代码可读性和可复用性。

7.2 扩展方向

  1. 扩展艺人范围: 将脚本改造成函数,输入任意艺人的 Wikipedia 单曲页面 URL,即可分析其 Hot 100 成绩。
  2. 使用官方/第三方 API: 寻找更稳定、更全面的音乐榜单 API(如 Spotify API, Last.fm API),获取更实时、更丰富的数据(如流媒体数据)。
  3. 深入时间序列分析: 分析每首歌曲从入榜到出榜的排名变化曲线,研究其生命周期模式。
  4. 关联专辑数据: 将单曲成绩与所属专辑的销量、奖项进行关联分析。
  5. 构建简单 Web 应用: 使用 Flask 或 Streamlit,将数据分析过程包装成一个交互式网页应用,用户可以选择艺人或调整评分权重。
  6. 机器学习尝试: 收集更多特征(如歌曲时长、流派、发行季节等),尝试预测一首新歌能否进入 Top 10 或在榜超过 20 周。

通过这个项目,你不仅得到了一份迈克尔·杰克逊的经典歌单,更重要的是掌握了一套从网页抓取、数据处理、算法建模到可视化分析的全流程数据科学方法。这套方法可以迁移到无数其他有趣的分析场景中。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/2 5:54:18

STM32H743实数IFFT实现:从频域处理到时域信号的高精度还原

简介&#xff1a;本资源是一套面向嵌入式DSP开发者的实数浮点FFT逆变换工程实现&#xff0c;专为STM32H743高性能Cortex-M7处理器设计&#xff0c;解决实时信号处理中频域数据还原为时域信号的核心需求&#xff0c;适用于通信、音频分析、工业传感等对计算精度与速度有双重要求…

作者头像 李华
网站建设 2026/9/2 5:53:34

基于SpringBoot的少儿编程培训机构管理系统(源码+lw+部署文档+讲解等)

温馨提示&#xff1a;本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;本人主页置顶文章(点我)开头有 CSDN 平台…

作者头像 李华
网站建设 2026/9/2 5:52:08

STC32F12K电磁智能车工程实践全解析

简介&#xff1a;本资源是一套面向全国大学生智能车竞赛参赛者与嵌入式初学者的电磁循迹智能车完整开发方案&#xff0c;基于STC32F12K单片机实现高精度电磁信号采集、路径识别与闭环速度控制&#xff0c;解决智能车在复杂电磁赛道中稳定循迹与动态调速的核心问题。压缩包共120…

作者头像 李华
网站建设 2026/9/2 5:52:03

GNZ48《否定句》舞台技术拆解:从录屏到二创的完整工具链

这场公演不是模型&#xff0c;也不是开源工具&#xff0c;但它非常适合用技术拆解的方式来看&#xff1a;舞台结构、机位逻辑、音频后期、视频分发、二次创作工具链&#xff0c;每一层都有值得记录的执行细节。尤其是黄楚茵“Zephyr”主题生日公演这个节点&#xff0c;整个舞台…

作者头像 李华
网站建设 2026/9/2 5:51:47

斯凯MRP编辑器源码拆解:从类C编译到.mrp打包的轻量工具链

简介&#xff1a;斯凯MRP平台的MRP编辑器源码&#xff0c;一份采用SGL模板开发的完整工程&#xff0c;适合功能机应用开发者、MRP资源处理工具研究者&#xff0c;用于学习MRP应用的界面构建、文件解析与资源打包流程。资源包共141个文件&#xff0c;zip压缩后仅615KB&#xff0…

作者头像 李华
网站建设 2026/9/2 5:49:51

Jalium UI跨平台开发实战:GPU加速渲染与声明式UI构建指南

大家好&#xff0c;最近在探索跨平台UI开发方案时&#xff0c;我深入研究了Jalium UI这个新兴框架。作为一个旨在融合现代GPU加速渲染与高效跨平台能力的UI框架&#xff0c;Jalium在开发者社区中正逐渐引起关注。本文将从其核心概念、架构设计、环境搭建到实战开发&#xff0c;…

作者头像 李华