news 2026/10/22 7:12:57

65k+ Steam游戏数据集实战:从CSV数据清洗到热度预测

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
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 个特征,我实际打开后逐列核验过,字段构成大致是这样:

  • appid:Steam 应用的唯一 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', encoding='gbk') 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', case=False) df['price_clean'] = df['price_clean'].str.replace(r'[^0-9.]', '', regex=True) df['price_clean'] = pd.to_numeric(df['price_clean'], errors='coerce').fillna(0) # 统一日期格式 df['date_clean'] = pd.to_datetime(df['release_date'], errors='coerce') # 拆分标签列,生成多列二进制特征 tags_encoded = df['tags'].str.get_dummies(sep=',') df_with_tags = pd.concat([df, tags_encoded], axis=1) 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_keys=False).apply( lambda x: x.sample(frac=0.2, random_state=42) ) print(sampled_df['year'].value_counts(normalize=True))

random_state=42固定随机种子,保证结果可复现。分层抽样比纯随机抽样更靠谱,尤其在数据的时间跨度长达五年的情况下。如果你打算训练二分类模型(比如预测好评率是否超过 80%),还要检查正负样本比例,必要时用class_weight或 SMOTE 处理不平衡,否则模型会一股脑地把所有样本都判成多数类。

4. 实战案例:基于数据集构建游戏热度分析与推荐 Demo

4.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(tokenize=lambda 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 好使,因为有些标签出现过于频繁(比如 Indie),TF-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_size=0.2, random_state=42, stratify=y ) model = RandomForestClassifier(n_estimators=200, max_depth=12) model.fit(X_train, y_train) print(classification_report(y_test, model.predict(X_test)))

stratify=y是关键参数,保证训练集和测试集中优质/非优质比例一致,不然测试集里优质游戏太少会导致报告分数失真。特征里包含 50 个标签 one-hot 列,加上原始特征总共 53 维,随机森林在这个维度上表现稳定。运行结果里 precision 和 recall 要一起看,如果 precision 高但 recall 低,说明模型「太保守」,只会把最有把握的判成优质。

5. 常见问题排查:数据读取、字段缺失与结果异常

5.1 读取 CSV 时遇到编码报错

现象:pd.read_csv()直接报UnicodeDecodeError,或者所有中文标签变成乱码。 原因:CSV 文件本身可能是 UTF-8 编码,但 Windows 环境下 pandas 默认按系统编码(如 GBK)读取,或者反过来。 解决:先尝试encoding='utf-8',失败就用encoding='gbk',还不行就试试encoding='utf-8-sig'——这个编码专治 UTF-8 文件开头带 BOM 头导致的第一列列名多出字符的问题。

提示:检查编码最稳妥的办法是用记事本或 VS Code 打开文件,看右下角显示的编码格式,而不是靠猜。

5.2 行数和声称的 65k+ 对不上

现象:实际读取后行数比描述少了数千行,或者多出重复行。 原因:CSV 文件里可能存在空行、纯逗号行、以及部分重复抓取的记录。 解决:用df.drop_duplicates(subset=['appid'])去掉重复,空行会在dropna(how='all')后消失。处理后再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( f'https://store.steampowered.com/api/appdetails?appids={appid}', timeout=10 ) 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_exists='replace'),把数据导进 SQLite 或 PostgreSQL,这样后续做复杂查询、按年份窗口聚合都更方便。直到有一天我发现 SQLite 里查出来的价格居然和 CSV 不一致,回头一查是日期字段的时区偏移导致排序错乱。从那以后我每次导入前都会强制把date_clean的时区统一成 UTC,再写入数据库。

进阶用法远不止管道化。这张表配合 Steam 商店页面的截图、短视频、描述文本,还能做一个多模态的游戏标签自动标注器;或者把标签、价格、好评率组合成一个简单的「游戏投资」推荐模型,用来分析小团队开发应该瞄准什么价位带。但无论如何,从这张 CSV 出发,先把基础分析跑通,再谈进阶,是更稳的路径。希望这套拆解能帮你在自己的项目里少走几个弯。

本文还有配套的精品资源,点击获取

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

LSTM-SVR组合预测核心:权重优化方法与避坑指南

简介&#xff1a;这份资源提供基于长短期记忆网络&#xff08;LSTM&#xff09;与支持向量回归&#xff08;SVR&#xff09;的组合预测方案&#xff0c;核心思路是对两种模型的权重进行协同优化&#xff0c;适用于多输入单输出的时间序列或特征回归任务&#xff0c;适合希望提高…

作者头像 李华
网站建设 2026/10/13 22:01:28

Java Point类设计详解:setPoint方法、坐标精度与面试核心考点

1. 从一个看似简单的Java题目说起第一次看到这个题目的时候&#xff0c;很多人会觉得它平平无奇——不就是写一个Point类描述平面坐标吗&#xff1f;构造函数、getter、setter&#xff0c;三下五除二就能搞定。但真正动手写的时候&#xff0c;问题就来了&#xff1a;setPoint方…

作者头像 李华
网站建设 2026/10/15 6:14:30

claude-mem 记忆系统实战:三层架构与检索注入策略

1. 项目缘起与核心定位第一次看到claude-mem这个名字&#xff0c;我的直觉是&#xff1a;这大概率是一个围绕 Claude 生态做“记忆层”的项目。事实也确实如此。它要解决的是一个所有长期使用大模型的人都会遇到的痛点——模型没有持久记忆。每次开新会话&#xff0c;之前聊过的…

作者头像 李华
网站建设 2026/10/12 19:52:03

数据字典工具:构建数据库契约驱动的协作中枢

简介&#xff1a;这是一款面向数据库开发人员、DBA及IT项目文档工程师的自动化数据字典生成工具&#xff0c;专为解决手动编写和维护数据库文档耗时易错、版本不一致等痛点而设计。工具支持MySQL、SQL Server、Oracle等主流数据库&#xff0c;可一键扫描表结构、字段类型、约束…

作者头像 李华
网站建设 2026/10/19 20:26:13

VOC+YOLO双格式282张公路落石数据集,小样本目标检测训练实战

简介&#xff1a;面向智能交通与目标检测开发者&#xff0c;专门提供公路落石场景的标注数据集&#xff0c;支持Pascal VOC与YOLO两种主流格式&#xff0c;适用于训练落石识别模型、验证检测算法及自动驾驶风险预警研究。压缩包共849个文件&#xff0c;包含283张jpg图像、282个…

作者头像 李华
网站建设 2026/10/15 13:35:42

垃圾短信文本识别系统:BERT微调与数据清洗完整方案

简介&#xff1a;本资源面向计算机相关专业学生、科研人员及行业开发者&#xff0c;提供一套基于BERT模型的垃圾短信文本识别完整方案&#xff0c;源自CCF大数据竞赛实践&#xff0c;可用于毕业设计、课程设计、项目立项演示或技术研究。压缩包共47个文件&#xff0c;约8.46MB&…

作者头像 李华