拓冰建站拓冰建站
首页 / 资讯中心 / 正文

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 官网并不直接提供完整的历史数据库下载。通常有以下几种获取方式官方 API/数据库 Billboard 有商业 API但通常收费且针对历史数据的接口有限。第三方维基或数据社区 如 Wikipedia 上 “Michael Jackson singles discography” 页面通常有整理好的表格包含 Hot 100 成绩。这是最可行的免费数据来源。手动整理 效率低下容易出错。因此本项目的技术路线将选择从 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 html5librequests: 用于发送 HTTP 请求获取网页内容。pandas: 核心数据分析库其read_html函数能直接解析 HTML 表格。matplotlibseaborn: 用于数据可视化。lxmlhtml5lib: 是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什么是“成绩好”这需要定义一个量化标准。常见的有按峰值排名排序US_Peak值越小越好1 最好。但这样会把所有冠军单曲并列第一无法区分。按在榜周数排序US_Weeks值越大越好代表持久生命力。综合评分 一个更合理的办法是结合两者。例如可以设计一个简单的“榜单得分”冠军单曲基础分最高。在榜周数作为加分项。峰值排名越靠前基础分越高。我们来设计一个简单的综合评分算法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, axis1)现在我们可以根据这个Score列进行排序选出 Top 25。# 按得分降序排列 top_25_df cleaned_df.sort_values(by‘Score’, ascendingFalse).head(25).reset_index(dropTrue) 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’], alpha0.7, s100, ctop_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’, fontsize8) plt.grid(True, linestyle‘--’, alpha0.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(rotation0) 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并运行它。预期输出应包括控制台打印出找到的表格数量。打印出清洗后的数据预览包含Single,Year,US_Peak,US_Weeks,Score等列。打印出按Score排序的 Top 25 歌曲列表。弹出三个图表窗口或保存为图片文件。5.2 结果分析与解读运行脚本后你得到的 Top 25 列表可能会包含以下经典歌曲具体顺序取决于你的评分算法Billie JeanBeat ItThrillerThe Way You Make Me FeelMan in the MirrorSmooth CriminalBlack or WhiteRemember the TimeYou Are Not AloneThey Don’t Care About Us从图表中我们可以得到一些洞察散点图 真正的“神曲”通常聚集在图的右上角即峰值排名非常靠前左侧且周数很长。例如Billie Jean和Beat 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.shape和df.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’, axis1, level1)进行交叉选择。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 项目最佳实践清单数据源验证 在编写解析逻辑前先用浏览器查看网页源码确认表格结构和数据格式避免因页面改版导致脚本失效。异常处理 在网络请求、数据解析等步骤添加try-except块并记录日志使脚本更健壮。数据持久化 将清洗后的cleaned_df和最终的top_25_df保存为 CSV 或 JSON 文件避免每次分析都重新抓取。cleaned_df.to_csv(‘michael_jackson_singles_cleaned.csv’, indexFalse) top_25_df.to_csv(‘mj_top_25_billboard.csv’, indexFalse)参数化配置 将 URL、表格索引、评分算法权重等变量放在脚本开头的配置区域方便调整。函数封装 将数据抓取、清洗、评分、绘图等步骤封装成独立函数提高代码可读性和可复用性。7.2 扩展方向扩展艺人范围 将脚本改造成函数输入任意艺人的 Wikipedia 单曲页面 URL即可分析其 Hot 100 成绩。使用官方/第三方 API 寻找更稳定、更全面的音乐榜单 API如 Spotify API, Last.fm API获取更实时、更丰富的数据如流媒体数据。深入时间序列分析 分析每首歌曲从入榜到出榜的排名变化曲线研究其生命周期模式。关联专辑数据 将单曲成绩与所属专辑的销量、奖项进行关联分析。构建简单 Web 应用 使用 Flask 或 Streamlit将数据分析过程包装成一个交互式网页应用用户可以选择艺人或调整评分权重。机器学习尝试 收集更多特征如歌曲时长、流派、发行季节等尝试预测一首新歌能否进入 Top 10 或在榜超过 20 周。通过这个项目你不仅得到了一份迈克尔·杰克逊的经典歌单更重要的是掌握了一套从网页抓取、数据处理、算法建模到可视化分析的全流程数据科学方法。这套方法可以迁移到无数其他有趣的分析场景中。
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门