简介:本资源是一份面向数据科学学习者、游戏行业研究者及商业分析从业者的高质量Steam游戏市场数据集,覆盖2021至2025年关键发展周期,助力趋势建模、品类洞察与定价策略分析。压缩包共含2个文件(1个Python采集脚本collect_data_v2.py用于复现数据获取逻辑,1个结构化CSV文件a_steam_data_2021_2025.csv),总大小仅1.93MB,轻量易加载,适配Jupyter/Pandas等主流分析环境。已有345人下载学习,反映出其在入门级数据分析项目与课程实践中的实用价值。数据集包含65,521款游戏的10维核心字段:从唯一appid、发行日期、美元标价,到类型/类别标签、开发者与发行商信息,再到用户推荐数这一关键热度指标,全部源自Steam官方网页API,真实可靠;特别纳入计划于2025年发布的未发售游戏,支持前瞻性研究。
1. 一份游戏数据宝藏的诞生与价值
最近在整理个人项目时,翻出了一个压箱底的宝贝——一份从2021年到2025年期间,涵盖了超过6.5万个独立游戏条目的Steam数据集。这份数据以CSV格式存储,包含了10个核心特征字段。对于任何对游戏市场分析、数据科学学习或者独立游戏开发感兴趣的朋友来说,这都是一块未经雕琢的璞玉。你可能正在学习Python的pandas库,苦于没有一份体量适中、特征清晰、领域有趣的真实数据集来练手;或者你是一名游戏行业的观察者,想了解近几年Steam平台的游戏发布趋势、定价策略或玩家评价分布,但苦于数据获取和清洗的繁琐。这份数据集恰好能填补这个空白。
它不是什么官方发布的完美报告,而是通过技术手段从公开信息中聚合、清洗后的成果,因此更贴近“实战”环境——里面会有数据缺失、格式不一、甚至偶尔的矛盾,而这正是真实世界数据的常态。处理它的过程,本身就是一次绝佳的数据分析实战演练。接下来,我将带你全方位地“盘活”这份数据,从如何获取与理解数据结构,到使用Python进行深度分析,再到挖掘出那些隐藏在数字背后的、关于Steam游戏市场的有趣洞察。
2. 数据集深度解析:10个特征字段的“前世今生”
在动手写任何一行代码之前,彻底理解你手中的数据是至关重要的第一步。这份数据集的10个特征字段,每一个都承载着特定的信息,也隐藏着一些需要特别注意的“坑”。
2.1 核心特征字段释义与数据来源推测
根据常见的Steam游戏数据维度,我们可以对这10个特征进行合理的推断和定义。这并非数据字典,而是基于经验的解读,你需要在实际加载数据后验证。
- appid: Steam平台上每个游戏的唯一数字标识符。这是连接所有数据的“主键”,绝对唯一且至关重要。在后续与其他数据集(如玩家评论数据)关联时,全靠这个字段。
- name: 游戏的名称。需要注意的是,同一游戏在不同区域可能有细微的名称差异,数据集通常采用英文原名。这个字段可能包含特殊字符,在读取时需要指定正确的编码(如UTF-8)。
- release_date: 游戏的发行日期。格式可能是
YYYY-MM-DD,也可能是MM/DD/YYYY,这是CSV数据中常见的混乱点之一,必须在分析前进行统一的日期格式解析。 - price_final: 游戏的最终售价(通常以美元计)。这里可能指的是折扣后的价格,或者是某个时间点的采样价格。需要关注是否有免费游戏(价格为0)以及价格异常值(极高或极低)。
- price_original: 游戏的原价。与
price_final结合可以计算折扣力度(1 - price_final / price_original)。注意原价可能为0(免费游戏)或与最终价相同(无折扣)。 - discount: 折扣百分比。可能是一个直接给出的字段,也可能是通过上述价格计算得出的。如果直接提供,需检查其与价格字段的逻辑一致性。
- rating: 游戏评分。这很可能不是简单的用户好评率,而可能是综合评分(如Metacritic评分)或经过处理的推荐指数。需要查看其数值范围(例如是0-10分制,还是0-100分制)来理解其含义。
- positive_ratings: 好评数量。来自Steam用户的好评数。
- negative_ratings: 差评数量。来自Steam用户的差评数。
- owners_estimate: 所有者数量估计。这是一个非常有趣但也很“模糊”的字段。Steam不公开精确的销量数据,这个字段通常是基于玩家数量区间(如“0-20000”,“20000-50000”)或第三方算法估算得出的。处理时需要将其视为一个数量级指标,而非精确值。
注意:以上字段释义是基于通用情况的推测。在实际操作中,第一件事一定是使用
pandas的head()、info()和describe()方法查看数据的前几行、字段类型和基本统计信息,以确认每个字段的真实含义和格式。
2.2 数据质量预判与清洗预备清单
面对6.5万行数据,直接进行分析必然会遇到问题。以下是在加载数据后应立即进行的“体检”项目:
- 缺失值侦察:哪些字段存在大量空值(NaN)?
rating或owners_estimate这类字段缺失可能很常见。你需要决定是删除缺失行、填充默认值(如用中位数填充价格),还是标记后单独处理。 - 格式统一:
release_date是否是统一的日期格式?price_final和price_original是否是数值类型?如果有discount字段,它是否是字符串(如“-50%”)?需要统一转换为适合分析的格式。 - 异常值处理:是否存在价格为负数或高得离谱(如9999美元)的记录?
positive_ratings的数量是否可能远大于owners_estimate?这可能是数据抓取错误,需要根据业务逻辑进行筛选或修正。 - 重复项检查:虽然
appid应唯一,但有时可能因数据抓取周期问题导致同一游戏有多个版本记录(如预发布版和正式版)。需要检查并去重。
3. 从文件到洞察:Python Pandas 全流程实战
现在,让我们进入实战环节。假设你已经将这份CSV文件下载到本地,命名为steam_games_2021_2025.csv。我们将使用Python的Pandas库,一步步完成从数据加载到基础分析的全过程。
3.1 环境搭建与数据加载
首先,确保你的Python环境已安装pandas。如果没有,通过pip install pandas安装。我们还会用到matplotlib或seaborn进行可视化,可以一并安装pip install matplotlib seaborn。
import pandas as pd import numpy as np import matplotlib.pyplot as plt import seaborn as sns # 设置中文显示(如果需要)和图表样式 plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签 plt.rcParams['axes.unicode_minus'] = False # 用来正常显示负号 sns.set_style("whitegrid") # 加载CSV文件 # 注意编码问题,如果出错可尝试 'ISO-8859-1' 或 'latin1' file_path = 'steam_games_2021_2025.csv' try: df = pd.read_csv(file_path, encoding='utf-8') except UnicodeDecodeError: try: df = pd.read_csv(file_path, encoding='ISO-8859-1') except: df = pd.read_csv(file_path, encoding='latin1') print("数据集形状(行,列):", df.shape) print("\n前5行数据:") print(df.head()) print("\n数据基本信息:") print(df.info()) print("\n数值型字段描述性统计:") print(df.describe())运行这段代码,你将对数据有一个全局的认识:有多少行数据、每个字段的类型(是对象、整数还是浮点数)、有多少非空值,以及数值字段的分布(均值、标准差、最小最大值)。
3.2 数据清洗与预处理的关键步骤
根据df.info()和df.describe()的输出,开始针对性清洗。
步骤一:处理日期字段
# 假设 release_date 是对象类型,尝试转换为日期时间格式 # pd.to_datetime 非常强大,可以自动推断多种格式 df['release_date'] = pd.to_datetime(df['release_date'], errors='coerce') # errors='coerce' 将解析失败的转为NaT # 检查转换后有多少无效日期 print(f"无效的日期记录数: {df['release_date'].isna().sum()}")步骤二:处理价格与折扣字段
# 确保价格字段为数值型 df['price_final'] = pd.to_numeric(df['price_final'], errors='coerce') df['price_original'] = pd.to_numeric(df['price_original'], errors='coerce') # 如果存在 discount 字段且为字符串,如“-50%”,则提取数字并转换为浮点数 if 'discount' in df.columns and df['discount'].dtype == object: # 移除百分号,转换为负数(因为折扣是负的) df['discount_pct'] = df['discount'].str.rstrip('%').astype(float) * -1 # 也可以计算折扣力度 df['calculated_discount'] = (df['price_final'] - df['price_original']) / df['price_original'] * 100步骤三:处理缺失值与异常值
# 1. 删除完全空白的行(所有字段都缺失) df_cleaned = df.dropna(how='all') # 2. 对于关键字段(如appid, name)缺失的行,通常选择删除 df_cleaned = df_cleaned.dropna(subset=['appid', 'name']) # 3. 对于价格异常值,可以基于分位数进行过滤 # 假设我们认为价格高于200美元或低于0美元为异常 price_upper_limit = 200 df_cleaned = df_cleaned[(df_cleaned['price_final'] >= 0) & (df_cleaned['price_final'] <= price_upper_limit)] df_cleaned = df_cleaned[(df_cleaned['price_original'] >= 0) & (df_cleaned['price_original'] <= price_upper_limit)] # 4. 对于评分,可以填充中位数或均值,但更好的方法是标记“缺失评分”作为一个类别 rating_median = df_cleaned['rating'].median() df_cleaned['rating_filled'] = df_cleaned['rating'].fillna(rating_median) df_cleaned['is_rating_missing'] = df_cleaned['rating'].isna() print(f"清洗后数据形状: {df_cleaned.shape}")3.3 基础分析:回答关于Steam市场的第一个问题
清洗完成后,我们可以开始提出一些具体问题,并用数据来回答。
问题一:每年的游戏发行数量趋势如何?
# 提取发行年份 df_cleaned['release_year'] = df_cleaned['release_date'].dt.year # 按年统计游戏数量 games_per_year = df_cleaned['release_year'].value_counts().sort_index() # 绘制折线图 plt.figure(figsize=(10,6)) games_per_year.plot(kind='line', marker='o') plt.title('Steam平台年度游戏发行数量趋势 (2021-2025)') plt.xlabel('发行年份') plt.ylabel('游戏数量') plt.grid(True, linestyle='--', alpha=0.7) plt.tight_layout() plt.show()这段代码将生成一张折线图,直观展示从2021到2025年,Steam每年上架的游戏数量是增长、下降还是保持稳定。这能反映平台生态的活跃度。
问题二:游戏的价格分布是怎样的?大多数游戏集中在什么价位?
# 关注最终售价的分布 price_data = df_cleaned['price_final'].dropna() # 由于可能存在大量免费或低价游戏,我们使用对数坐标或分段统计 plt.figure(figsize=(12,5)) # 子图1:直方图(聚焦于0-50美元区间) plt.subplot(1,2,1) plt.hist(price_data[price_data <= 50], bins=30, edgecolor='black', alpha=0.7) plt.title('游戏价格分布 (0-50美元区间)') plt.xlabel('最终价格 (美元)') plt.ylabel('游戏数量') # 子图2:箱线图(查看整体分布和异常值) plt.subplot(1,2,2) plt.boxplot(price_data, vert=False) plt.title('游戏价格箱线图') plt.xlabel('最终价格 (美元)') plt.tight_layout() plt.show() # 计算关键分位数 print(f"价格中位数: ${price_data.median():.2f}") print(f"价格均值: ${price_data.mean():.2f}") print(f"75%的游戏价格低于: ${price_data.quantile(0.75):.2f}")这个分析能告诉你Steam游戏的定价策略。你会发现,很可能有一个非常长的右尾——即绝大多数游戏价格很低(甚至免费),但少数大作价格很高。
问题三:游戏评分与价格、好评数有关系吗?
# 计算好评率(如果原始数据没有) df_cleaned['positive_rate'] = df_cleaned['positive_ratings'] / (df_cleaned['positive_ratings'] + df_cleaned['negative_ratings']) df_cleaned['positive_rate'] = df_cleaned['positive_rate'].replace([np.inf, -np.inf], np.nan) # 处理除零错误 # 绘制散点图矩阵,观察几个核心数值变量间的关系 # 为了可视化清晰,可以采样一部分数据 plot_df = df_cleaned[['price_final', 'rating_filled', 'positive_rate', 'owners_estimate']].dropna().sample(n=1000, random_state=42) sns.pairplot(plot_df, diag_kind='kde', plot_kws={'alpha':0.5}) plt.suptitle('核心数值特征关系散点图矩阵', y=1.02) plt.show() # 计算相关系数 corr_matrix = plot_df.corr() print("相关系数矩阵:") print(corr_matrix)通过这个分析,你可能会发现一些有趣的关联,例如“好评率与评分高度正相关”(这符合直觉),但“价格与评分/好评率可能没有强相关”,甚至可能出现“低价独立游戏凭借口碑获得高评分”的现象。
4. 进阶探索:从描述性统计到洞察性挖掘
基础分析描绘了轮廓,进阶探索则试图回答更复杂的“为什么”和“怎么样”。
4.1 时间序列下的折扣策略分析
我们可以按月份或季度,分析平台整体折扣力度的变化。例如,夏季促销、冬季促销期间,平均折扣是否显著加深?
# 提取发行月份和季度 df_cleaned['release_month'] = df_cleaned['release_date'].dt.month df_cleaned['release_quarter'] = df_cleaned['release_date'].dt.quarter # 假设我们有了 calculated_discount 字段(负值表示折扣) if 'calculated_discount' in df_cleaned.columns: # 按季度计算平均折扣深度(取绝对值,使其为正值便于理解) df_cleaned['discount_depth'] = df_cleaned['calculated_discount'].abs() avg_discount_by_quarter = df_cleaned.groupby('release_quarter')['discount_depth'].mean() plt.figure(figsize=(8,5)) avg_discount_by_quarter.plot(kind='bar') plt.title('不同季度发行的游戏平均折扣深度') plt.xlabel('季度') plt.ylabel('平均折扣深度 (%)') plt.xticks(rotation=0) plt.show()这个分析可以帮助你理解Steam平台或发行商是否倾向于在特定时间点以更深的折扣发布游戏。
4.2 游戏“性价比”的量化尝试
我们可以创建一个简单的“价值指数”,综合考量价格、评分和好评数量。这并非一个科学严谨的指标,但能提供一种有趣的视角。
# 一个简单的价值指数示例: (评分 * 好评率) / (价格 + 1) # 加1是为了避免除零,并对免费游戏也能计算 df_cleaned['value_index'] = (df_cleaned['rating_filled'] * df_cleaned['positive_rate']) / (df_cleaned['price_final'] + 1) # 找出价值指数最高的游戏 top_value_games = df_cleaned[['name', 'price_final', 'rating_filled', 'positive_rate', 'value_index']].sort_values(by='value_index', ascending=False).head(20) print("价值指数最高的20款游戏:") print(top_value_games)你会发现,这个榜单很可能被那些“评分极高、价格极低(甚至免费)”的优质独立游戏或经典老游戏占据。这为寻找“宝藏游戏”提供了一个数据驱动的思路。
4.3 基于文本特征的简单探索(游戏名称)
虽然只有10个特征,但name字段是文本,我们仍可以做最基础的文本分析,比如找出最常见的词汇。
from collections import Counter import re # 将所有游戏名称合并为一个字符串,并转换为小写 all_names = ' '.join(df_cleaned['name'].dropna().astype(str).str.lower()) # 使用正则表达式提取单词(简单处理,忽略标点) words = re.findall(r'\b[a-z]{3,}\b', all_names) # 只提取长度>=3的单词 # 计算词频 word_freq = Counter(words) # 移除常见的停用词(如the, and, of, game等) common_stopwords = {'the', 'and', 'of', 'game', 'edition', 'version', 'definitive', 'complete'} filtered_word_freq = {word: count for word, count in word_freq.items() if word not in common_stopwords} # 获取前20个最常见的词 top_words = pd.Series(filtered_word_freq).nlargest(20) plt.figure(figsize=(12,6)) top_words.sort_values().plot(kind='barh') plt.title('Steam游戏名称中最常见的词汇 (2021-2025)') plt.xlabel('出现频次') plt.tight_layout() plt.show()这个分析可以直观反映出近几年游戏命名的流行趋势,比如是否大量出现“Simulator”、“Legacy”、“Remastered”等词汇。
5. 数据导出、应用扩展与避坑指南
完成分析后,你可能需要将清洗或处理后的数据保存下来,或者将分析结果应用到其他场景。
5.1 将处理好的数据保存为新CSV
# 保存清洗并添加了新特征的数据框 output_path = 'steam_games_2021_2025_cleaned_enriched.csv' df_cleaned.to_csv(output_path, index=False, encoding='utf-8-sig') # utf-8-sig 对Excel等软件更友好 print(f"处理后的数据已保存至: {output_path}")5.2 与其他工具链的衔接
- 数据库导入:你可以将CSV导入到MySQL、PostgreSQL甚至SQLite中,进行更复杂的SQL查询和分析。使用
pandas的to_sql方法或数据库的LOAD DATA INFILE(MySQL)命令可以方便地完成。 - 可视化仪表板:利用
Plotly Dash或Streamlit库,你可以快速将上述分析构建成一个交互式的Web仪表板,动态筛选年份、价格区间,查看游戏详情。 - 机器学习入门:这份数据可以作为简单的回归(预测游戏评分)或分类(根据特征划分游戏类型,如果后续能加入类型标签)任务的入门数据集。
5.3 实战中踩过的“坑”与心得
- 编码“幽灵”:CSV文件编码问题是最常见的“第一道坎”。如果
pd.read_csv默认的utf-8报错,不要慌,依次尝试encoding='ISO-8859-1'或encoding='latin1'。在保存为CSV时,使用utf-8-sig编码可以避免许多下游工具(如Excel)打开时的乱码问题。 - 日期解析的“陷阱”:
pd.to_datetime的errors='coerce'参数是你的好朋友。它会把所有无法解析的日期变成NaT(Not a Time),而不是让整个程序崩溃。之后你可以再单独检查这些NaT行,决定是删除还是手动修正。 - “免费”游戏的干扰:在分析价格分布时,免费游戏(价格为0)会极大地影响均值,并使直方图在0点处出现一个极高的柱状。通常的做法是将免费游戏单独分类,或者在分析付费游戏时将其过滤掉
df_paid = df_cleaned[df_cleaned['price_final'] > 0]。 - 估算字段的“模糊性”:像
owners_estimate这样的字段,切忌将其当作精确值进行复杂的数学运算。更合理的用法是将其分箱(binning),转化为“销量等级”(如“小众”、“热门”、“爆款”),然后进行类别分析。 - 内存与性能:6.5万行数据对于现代的Pandas来说是小菜一碟。但如果数据量增长到百万级,在
groupby、apply等操作时就要开始注意性能。可以考虑使用dtype参数指定数据类型以节省内存,或者使用pandas的query()方法进行过滤。
处理这样一份真实的、带有“毛刺”的数据集,其价值远大于处理一份完美的教学数据集。每一个数据清洗的决策、每一个异常值的处理,都是对业务理解的深化。这份Steam数据集就像一座矿山,上述分析只是最初级的勘探,更深层的宝藏——比如结合外部数据(如游戏类型、开发商信息)进行关联分析,或者构建更复杂的预测模型——正等待你去挖掘。
本文还有配套的精品资源,点击获取