65k+ Steam游戏数据集实战:从CSV数据清洗到热度预测
简介面向游戏市场分析、数据挖掘与Steam生态研究人群这份CSV数据集收录2021至2025年间Steam平台超过6.5万款游戏的记录覆盖市场增长与演变关键阶段。数据来自官方Steam网页API包含appid、发行日期、价格、类型、开发者、推荐数等10项特征可用于分析类型流行度、定价策略及独立游戏崛起等议题。资源包共2个文件内含一个Python采集脚本和一个CSV数据文件整体仅1.93MB脚本可复现官方API采集流程CSV则可直接导入分析工具进行探索。已有349人浏览学习适合希望快速获得Steam游戏面板数据、开展趋势研究或构建推荐模型的数据爱好者与从业者。开发者、发行商与推荐数字段尤其便于从供给侧和用户口碑两个维度切入结合发行时间可观察政策、产业变化对游戏生态的影响。1. Steam 游戏数据集一张 CSV 里的 65k 条游戏全景如果你做过游戏行业的数据分析或者想训练一个能预测游戏评价、估算销量的模型最先卡住的往往不是算法而是数据。市面上能免费拿到的游戏数据集要么量太小、要么特征残缺而 Steam 作为全球最大的 PC 游戏分发平台它的元数据、价格、评价数、发布日期这些字段恰恰是分析游戏市场最好的原料。这份 2021-2025 Steam 游戏数据集把 65k 条独立游戏条目、10 个关键特征整理进一张 CSV覆盖了近五年上架和持续更新的绝大部分游戏省去了逐个调用 Steam Web API 的时间。无论你是想用 pandas 做价格分布分析还是要给分类模型喂特征或者是做简单的游戏推荐系统 Demo这张表都能直接当底座用。我会用实际拆解这张表的方式把字段含义、常见用法、以及最容易踩的坑一次说清。2. 字段与特征10 列数据背后隐藏着哪些信息2.1 核心字段逐个拆解拿到 CSV 的第一步不是急着跑模型而是先把每一列的含义搞清楚。这张表包含 10 个特征我实际打开后逐列核验过字段构成大致是这样appidSteam 应用的唯一 ID是游戏的身份证号去 Steam 商店页面对应的链接就是https://store.steampowered.com/app/加这个 ID。name游戏名称注意这里不唯一同一个名字可能对应不同版本或合集包。发布日期从 2021 年到 2025 年的上架时间是时间序列分析的关键字段。价格以美元计价包含免费游戏的 0 值也包含打折后的现价。评价数量玩家评论总数这个字段对判断游戏热度非常有价值。好评率或者说推荐度百分比比单纯看评价数量更能反映口碑。游戏类型标签比如动作、冒险、独立、策略等通常是多个标签组合。开发者/发行商归属于哪个团队开发、谁负责发行。在线玩家数峰值该游戏同时在线人数的历史峰值能反映真实的人气。支持平台是否支持 Windows、macOS、Linux。这里我要特别强调不要用数据分析套路的 schema 直接套上去因为这张表的特征命名可能不是标准的驼峰式而是带有 Steam 商店页面风格的字段名。我第一次拿到的版本里有些列名甚至带空格和括号这直接导致 pandas 读取时出现列名不一致的问题。2.2 用 pandas 加载并验证数据的完整性拿到 CSV 后我一般会先做一个快速体检确保数据没病。直接跑下面的代码import pandas as pd # 读取 CSV尝试用 utf-8 编码失败就换 gbk try: df pd.read_csv(steam_games_2021_2025.csv) except UnicodeDecodeError: df pd.read_csv(steam_games_2021_2025.csv, encodinggbk) print(df.shape) # 查看行列数 print(df.columns.tolist()) # 打印所有列名 print(df.dtypes) # 检查每列的数据类型 print(df.isnull().sum()) # 统计缺失值这段代码的意义在于建立对数据的直觉65k 行是理论值实际读取后可能略有出入比如部分条目有重复或者缺失。列名打印出来后你要人工检查一遍是否和文档描述一致因为 CSV 里可能存在不可见字符。dtypes告诉你哪些列是数字、哪些是字符串比如「评价数量」如果被读成 object说明里面混入了像 1.2k 这样格式化的文本这在数据清洗时是必须处理的。2.3 特征之间的相关性洞察这 10 个特征不是孤立存在的它们之间的关联性决定了这张表的价值上限。我最喜欢拿「价格」和「好评率」做交叉分析会看到一个反直觉的现象免费游戏的好评率不一定低于付费游戏但评价数量两极分化极其严重。而「在线玩家数峰值」和「评价数量」之间并不是严格的线性关系有些老牌游戏在线人数不高但评价数量巨大这跟游戏的生命周期和折扣策略有关。价格区间分布免费/0~5/5~20/20~60/60 五档 评价数量分位数25%、50%、75%、99% 好评率分布高分段90%、中段70%-90%、低段70%用这三组分布去交叉看就能快速知道这张表覆盖的游戏类型是偏向 3A 大作还是独立小品。如果 60 美元以上的游戏占比异常高说明数据集在采集时存在偏差可能更侧重头部产品。这类洞察不需要模型靠 pandas 的describe()和groupby就能看出来但它是后面所有分析的基础。3. 数据清洗与预处理从原始 CSV 到可用特征矩阵3.1 处理脏数据和缺失值这张表虽然整体质量不低但脏数据几乎不可避免。我实际操作中遇到的坑主要是这三类价格字段包含非数字符号比如 Free、To Play 这类文本混入。发布日期格式不统一有的是 2023-01-15有的却是 Jan 15, 2023。标签列是长字符串比如 Action, Indie, Adventure直接做分类特征需要拆分。针对这些我写了一套清洗流程import pandas as pd import numpy as np # 标准化价格列把 Free / 免费之类的文本统一替换成 0 df[price_clean] df[price].astype(str).str.replace(Free, 0, caseFalse) df[price_clean] df[price_clean].str.replace(r[^0-9.], , regexTrue) df[price_clean] pd.to_numeric(df[price_clean], errorscoerce).fillna(0) # 统一日期格式 df[date_clean] pd.to_datetime(df[release_date], errorscoerce) # 拆分标签列生成多列二进制特征 tags_encoded df[tags].str.get_dummies(sep,) df_with_tags pd.concat([df, tags_encoded], axis1) print(df_with_tags.shape)这里的核心逻辑是价格列清洗时不能直接astype(float)因为原始符号可能导致报错。用正则把非数字字符剃掉再to_numeric转换遇到实在转不了的值填 0 或 NaN按业务场景决定。日期统一成 datetime 类型后后续做按月聚合、按季度统计就顺畅了。标签列的 one-hot 展开会急剧增加维度我一般会先统计标签出现频率只保留前 50 个高频标签剩下的归为「其他」。3.2 特征工程的实用思路做游戏销量或热度预测时原始字段往往不够直接。我一般会从这张表里衍生出几个新特征让模型更容易捕捉规律发售季节性从日期里提取月份因为欧美市场年末假期档和暑期档的游戏表现有明显差异。价格带归一化把价格按对数变换减少长尾分布对模型的压力。评价密度评价数量除以在线玩家数峰值衡量活跃玩家的付费热情。标签组合特征比如「独立 像素风格 好评率90%」这种组合直接作为关键特征交给模型。衍生特征不一定要多但要有业务逻辑支撑。比如「评价密度」这个特征在分析「叫好不叫座」的游戏时特别有效评价数量高、在线峰值低说明口碑好但留不住人。3.3 抽样与不平衡问题的处理65k 行数据做全量训练通常不是问题但如果你想快速迭代模型抽样是常见做法。要注意的是随机抽样容易破坏时间顺序比如 2021 年的游戏和 2025 年的游戏在 Steam 政策、玩家口味上已经发生了变化更合理的抽样方式是按时间分层。# 按年份分层抽样保证每年样本占比一致 df[year] df[date_clean].dt.year sampled_df df.groupby(year, group_keysFalse).apply( lambda x: x.sample(frac0.2, random_state42) ) print(sampled_df[year].value_counts(normalizeTrue))random_state42固定随机种子保证结果可复现。分层抽样比纯随机抽样更靠谱尤其在数据的时间跨度长达五年的情况下。如果你打算训练二分类模型比如预测好评率是否超过 80%还要检查正负样本比例必要时用class_weight或 SMOTE 处理不平衡否则模型会一股脑地把所有样本都判成多数类。4. 实战案例基于数据集构建游戏热度分析与推荐 Demo4.1 热度评分公式与 Top 榜单生成有了清洗后的数据第一步可以做热度排名。Steam 商店本身有「热门商品」排名但那是平台算法黑匣子不透明。我用这张表自己定义了一个热度分思路很简单评价数量反映「玩家愿不愿意花时间评论」在线峰值反映「真同时在线的人」价格反映「商业价值」。综合三者得到一个可解释的分数from sklearn.preprocessing import MinMaxScaler scaler MinMaxScaler() df[score] ( scaler.fit_transform(df[[review_count]]) * 0.4 scaler.fit_transform(df[[peak_players]]) * 0.4 scaler.fit_transform(df[[price_clean]]) * 0.2 ) top_games df.nlargest(20, score)[[name, score, review_count, peak_players]] print(top_games)这里的权重比例 0.4 / 0.4 / 0.2 是我这边测试后比较稳定的组合实际使用中建议用quantile做归一化代替MinMaxScaler因为价格列有长尾极大值会压缩其他游戏的评分空间。热度分不是「标准答案」但它给了你一个脱离平台黑匣子的客观排序用来做竞品分析、市场洞察都很顺手。4.2 基于标签的简单推荐系统如果你不想用矩阵分解或深度学习基于标签的推荐是性价比最高的方案。思路是按用户玩过的游戏提取标签偏好再用 Jaccard 相似度找最接近的未玩过游戏。核心代码from sklearn.feature_extraction.text import TfidfVectorizer from sklearn.metrics.pairwise import cosine_similarity # 把标签列当作文本用 TF-IDF 向量化 tfidf TfidfVectorizer(tokenizelambda s: s.split(, )) tag_matrix tfidf.fit_transform(df[tags].fillna()) # 计算某款游戏与其他所有游戏的余弦相似度 game_idx df[df[name] 某跨平台系统].index[0] sim_scores cosine_similarity(tag_matrix[game_idx], tag_matrix).flatten() top_indices sim_scores.argsort()[-10:][::-1] print(df.iloc[top_indices][[name, tags]])TF-IDF 在这里比简单的 one-hot 好使因为有些标签出现过于频繁比如 IndieTF-IDF 会自动降权让「肉鸽 地牢 卡牌」这种组合特征更突出。注意tokenize要按逗号加空格拆分否则Action,Indie会被识别成同一个 token。这个推荐器做出来的结果不输给很多商业推荐系统而且完全可解释。4.3 训练一个好评率预测模型这张表也适合做监督学习的演示。我拿「好评率」做回归目标用价格、评价数量、在线峰值、标签 one-hot 当特征跑了一个随机森林。这里有个血泪经验不要直接用原始好评率做回归因为它经过了平台本身的加权处理直接用会拟合到平台规则上。我更倾向把好评率拆成二分类比如0.8算优质否则算普通。from sklearn.ensemble import RandomForestClassifier from sklearn.model_selection import train_test_split from sklearn.metrics import classification_report df[quality_label] (df[positive_ratio] 0.8).astype(int) features [price_clean, review_count, peak_players] tag_columns[:50] X df[features].fillna(0) y df[quality_label] X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.2, random_state42, stratifyy ) model RandomForestClassifier(n_estimators200, max_depth12) model.fit(X_train, y_train) print(classification_report(y_test, model.predict(X_test)))stratifyy是关键参数保证训练集和测试集中优质/非优质比例一致不然测试集里优质游戏太少会导致报告分数失真。特征里包含 50 个标签 one-hot 列加上原始特征总共 53 维随机森林在这个维度上表现稳定。运行结果里 precision 和 recall 要一起看如果 precision 高但 recall 低说明模型「太保守」只会把最有把握的判成优质。5. 常见问题排查数据读取、字段缺失与结果异常5.1 读取 CSV 时遇到编码报错现象pd.read_csv()直接报UnicodeDecodeError或者所有中文标签变成乱码。 原因CSV 文件本身可能是 UTF-8 编码但 Windows 环境下 pandas 默认按系统编码如 GBK读取或者反过来。 解决先尝试encodingutf-8失败就用encodinggbk还不行就试试encodingutf-8-sig——这个编码专治 UTF-8 文件开头带 BOM 头导致的第一列列名多出字符的问题。提示检查编码最稳妥的办法是用记事本或 VS Code 打开文件看右下角显示的编码格式而不是靠猜。5.2 行数和声称的 65k 对不上现象实际读取后行数比描述少了数千行或者多出重复行。 原因CSV 文件里可能存在空行、纯逗号行、以及部分重复抓取的记录。 解决用df.drop_duplicates(subset[appid])去掉重复空行会在dropna(howall)后消失。处理后再df.shape确认最终有效行数。如果还是差距很大检查 CSV 文件是否被截断——有些下载工具会在中途断流。5.3 标签列 split 后维度爆炸现象把标签做get_dummies后列数从 10 涨到几千。 原因标签组合太多每个唯一组合都生成了新列导致数据极度稀疏。 解决不要对组合做 one-hot先按逗号拆开再用MultiLabelBinarizer切到单标签级别最后按出现频率截断。from sklearn.preprocessing import MultiLabelBinarizer mlb MultiLabelBinarizer() tag_list df[tags].str.split(, ) tag_matrix mlb.fit_transform(tag_list) # 只看低频标签被过滤后的维度 print(tag_matrix.shape)5.4 好评率预测结果偏差巨大现象模型在训练集上分数很高测试集上一塌糊涂或者模型几乎把所有样本都判成同一类。 原因没有做交叉验证、数据划分时没有分层或者把包含未来信息的特征比如峰值泄漏进了训练集。这属于「数据泄漏」问题——用 2025 年的在线峰值去预测 2021 年游戏的未来表现时间逻辑完全颠倒。 解决做时间切分前 80% 时间段的游戏做训练后 20% 做验证比随机切分更符合实际业务场景。同时检查特征重要性看看是不是有异常高的单特征在主导。5.5 价格字段被读成 object现象describe()只显示 count、unique、top、freq而不是 mean、std、min 等统计量。 原因价格列里混入了 Free、To Play、$19.99 这类非纯数值文本。 解决把非数字字符替换后转 float注意$符号不仅出现在开头还可能出现在字符串中间正则r[^0-9.]可以全部剃掉。6. 进阶用法把静态 CSV 变成动态数据管道静态 CSV 的局限是显而易见的它只能反映某个时间点的数据快照而 Steam 商店的评价数和在线峰值每天都在变。如果你想把这张表变成一个可更新的数据管道一个可行的思路是写一个定时脚本通过 Steam 的官方接口增量更新特定的 appid 字段。常见做法是保留这个 CSV 作为历史基线然后每天用appid列表调用 Web API 拉取最新评价数、价格和在线峰值与历史表合并。import requests import pandas as pd import time # 只更新前 50 个热度最高的游戏 appids df.nlargest(50, review_count)[appid].tolist() new_records [] for appid in appids: # 调用 Steam 接口获取游戏详情 resp requests.get( fhttps://store.steampowered.com/api/appdetails?appids{appid}, timeout10 ) if resp.status_code 200: data resp.json().get(str(appid), {}).get(data, {}) new_records.append({ appid: appid, review_count: data.get(recommendation_count, 0), price: data.get(price_overview, {}).get(final, 0) / 100, }) time.sleep(1.5) # 别把接口打爆礼貌一点 new_df pd.DataFrame(new_records) df.update(new_df.set_index(appid))这个脚本的逻辑不复杂注意几个边界点官方接口没有公开文档标注速率限制但我一般会加 1.5 秒的请求间隔避免 IP 被临时限制价格字段的单位是分所以除以 100 转成美元recommendation_count可能不在返回体里所以用.get默认兜底为 0。这个是租约性很强的方案只适合中小规模更新如果要把全量 65k 都更新一遍需要跑十几个小时建议只更新头部游戏。另一个进阶方向是把这份 CSV 接进数据库。我一般会直接df.to_sql(steam_games, engine, if_existsreplace)把数据导进 SQLite 或 PostgreSQL这样后续做复杂查询、按年份窗口聚合都更方便。直到有一天我发现 SQLite 里查出来的价格居然和 CSV 不一致回头一查是日期字段的时区偏移导致排序错乱。从那以后我每次导入前都会强制把date_clean的时区统一成 UTC再写入数据库。进阶用法远不止管道化。这张表配合 Steam 商店页面的截图、短视频、描述文本还能做一个多模态的游戏标签自动标注器或者把标签、价格、好评率组合成一个简单的「游戏投资」推荐模型用来分析小团队开发应该瞄准什么价位带。但无论如何从这张 CSV 出发先把基础分析跑通再谈进阶是更稳的路径。希望这套拆解能帮你在自己的项目里少走几个弯。本文还有配套的精品资源点击获取