據集CSV:10特征清洗分析與推薦實踐)
簡介面向2021至2025年Steam游戲市場的公開數(shù)據資源包含65,521款游戲條目適合游戲行業(yè)分析人員、市場研究者及對數(shù)字發(fā)行趨勢感興趣的學習者。數(shù)據來自官方Steam網頁API覆蓋appid、名稱、發(fā)行日期、美元價格、類型、類別、開發(fā)者、出版商及用戶推薦數(shù)共10個字段可用于分析市場趨勢、類型熱度、定價策略與獨立游戲表現(xiàn)。資源包共2個文件以7z壓縮包形式提供內含一個Python采集腳本與一個CSV數(shù)據文件整體大小約1.93MB。其中CSV為核心數(shù)據表Python腳本可用于數(shù)據更新或采集流程復現(xiàn)。已有349人瀏覽學習便于快速獲取結構化數(shù)據進行二次分析或可視化。該數(shù)據集時間跨度完整兼顧已發(fā)售作品與計劃于2025年發(fā)布的未來作品能為行業(yè)觀察與量化分析提供基礎支撐。1. 2021-2025 Steam游戲數(shù)據集10特征65k個獨立條目CSV想研究游戲市場從這張表開始拿到這份 2021-2025 Steam游戲數(shù)據集10特征65k個獨立條目CSV最值得做的不是急著畫圖而是先想清楚一個問題這 65k 條記錄能幫你驗證什么假設Steam 游戲列表本身并不稀缺稀缺的是把時間跨度、定價、評價、類型、標簽壓縮到一張表里讓你能快速回答“疫情后獨立游戲是不是更多了”“免費游戲的評分是不是真的更分化”“2024 年哪些品類發(fā)行量在漲”這類問題。它適合四類人想入門數(shù)據分析的新手、做推薦系統(tǒng)的算法工程師、寫 Steam 相關爬蟲或應用的后端開發(fā)以及做游戲市場研究的從業(yè)者。CSV 格式意味著你不需要任何數(shù)據庫pandas 就能直接讀但在開始之前先別把“特征數(shù)”當成“列數(shù)”理解下面我會從一個最常用的 10 列結構展開講清楚。2. 先看清楚 10 個特征再動手字段語義、讀取參數(shù)和第一眼檢查2.1 一份 Steam 游戲 CSV 常見的 10 個特征是什么我接觸過不少 Steam 游戲類 CSV列名很少完全一致但核心信息通常是同一批游戲唯一標識、名稱、發(fā)布日期、價格、開發(fā)者/發(fā)行商、類型、標簽、好評數(shù)、差評數(shù)、好評率。把這些列湊齊正好是 10 個特征特征名類型說明app_idint/strSteam 應用唯一 ID去重和關聯(lián)外部數(shù)據的鑰匙namestr游戲名注意可能有重名和空格release_datestr/datetime發(fā)行日期常見格式為 YYYY-MM-DDpricefloat當前價格美元免費游戲常為 0developersstr開發(fā)者多個用逗號或豎線分隔genresstr主類型如 Action、Indie、Strategytagsstr社區(qū)標簽通常用豎線分隔數(shù)量較多positive_reviewsint好評數(shù)量negative_reviewsint差評數(shù)量positive_ratiofloat好評率取值 0~100注意單位是百分比還是 0~1前面幾列一眼就能看懂真正影響后續(xù)分析的是positive_ratio的單位和tags的分隔符。如果你直接拿positive_ratio去乘 100或者把tags當成單個字符串去匹配“多人”或“單機”后面所有統(tǒng)計都會翻車。拿到 CSV 的第一件事不是訓練模型而是用一個標準流程確認字段類型和取值分布。2.2 用 pandas 讀取 CSVencoding 和 dtype 是兩個省內存開關讀取一張 65k 行、10 列的表文件本身可能只有幾 MB 到幾十 MB但如果你不做任何處理pandas 會默認把每一列都讀成對象或 64 位整數(shù)內存翻兩三倍很常見。我一般會在讀取時就指定dtype避免事后才發(fā)現(xiàn)app_id被讀成了 float。import pandas as pd df pd.read_csv( steam_games_2021_2025.csv, encodingutf-8, dtype{ app_id: int32, price: float32, positive_reviews: int32, negative_reviews: int32, positive_ratio: float32, }, parse_dates[release_date], low_memoryFalse, ) print(df.shape) print(df.head()) print(df.info(memory_usagedeep))這段代碼里最值得注意的兩個參數(shù)是dtype和parse_dates。dtype讓數(shù)字列用更小的整型和浮點型存儲65k 行看不出明顯差異但后面一旦要合并 Steam 爬蟲或外部評分數(shù)據這個習慣能省下幾十 MB。parse_dates會把發(fā)行日期在讀取階段就轉成datetime64避免你之后用pd.to_datetime再去遍歷一遍。low_memoryFalse是為了防止 pandas 在分塊讀取時因為列類型推斷不一致而給出潛在類型警告。讀取完成后不要急著 head()先跑一下df.isna().sum()看空值列在哪些特征上。很多由爬蟲生成的 CSV 會在tags、developers上留下空值這些空值不是簡單的“沒有”可能是爬蟲沒有抓取到也可能是獨立游戲確實沒有填寫標簽處理方式完全不同。2.3 從特征到業(yè)務問題哪些列可以組合使用10 個特征不是 10 個獨立變量組合起來才能回答更具體的問題。比如release_date加genres可以看類型發(fā)行量隨年份的變化price加positive_ratio可以看定價區(qū)間與口碑的關系tags加positive_reviews可以找出“EA 測試但評價不錯”的小眾產品。我習慣在清洗之前先做一遍“假設映射”也就是把業(yè)務問題拆成特征組合否則很可能會多洗掉不少有價值的數(shù)據。比如positive_ratio如果缺失不要立刻刪行而是看positive_reviews和negative_reviews是否存在存在的話完全可以用后者手工計算好評率。3. 數(shù)據清洗把 10 個特征變成可供模型使用的干凈寬表3.1 日期、價格、空值三個最先翻車的字段幾乎所有 Steam 類 CSV 都逃不過這三個坑日期格式不統(tǒng)一、價格字段混入 “Free to Play” 或 “免費” 等文本、空值分布在多個列。直接dropna()會把 65k 刪到 30k屬于最粗暴的解法。我更傾向于按列清洗先讓每一列都能被正確解釋再決定是否刪除行。import pandas as pd # 日期不強制格式讓 pandas 自動解析解析失敗的置為 NaT df[release_date] pd.to_datetime(df[release_date], errorscoerce) # 價格先統(tǒng)一轉成字符串處理再轉數(shù)值 df[price] df[price].astype(str).str.strip().str.lower() df.loc[df[price].str.contains(free, naFalse), price] 0 df[price] pd.to_numeric(df[price], errorscoerce) # 空值只對關鍵列刪除缺失 df df.dropna(subset[app_id, name, release_date]) print(df.shape) print(df[df[price].isna()][[name, price]].head())這段代碼的邏輯分三步走。第一步把release_date統(tǒng)一成 datetimeerrorscoerce會把類似 “2025-01-15” 和 “2025/1/15” 都解析掉但純年份或 “Coming Soon” 會變成NaT后續(xù)再單獨處理。第二步處理價格這里容易踩的細節(jié)是astype(str)之后整列變成字符串str.contains(free, naFalse)才能安全過濾空值最后再轉數(shù)值。第三步只對主鍵列刪除缺失價格缺失可以先保留后面用 0 或中位數(shù)填充。我在實際處理中會把解析失敗的日期單獨列出來看而不是直接刪掉。很多時候失敗信息里能看到 “TBA” 或 “2025” 這樣的短格式它們可以單獨歸為一類“即將發(fā)行”或“年份未知”不需要完全丟棄。3.2 好評率、發(fā)行年份、標簽拆分的特征工程原始 10 個特征對機器學習來說太原始了至少要構造出年份、歸一化好評率、標簽列表三個新變量。這里有一個經驗positive_ratio即使已經給定我仍然會重算一遍因為少數(shù)行的positive_ratio可能是爬蟲算錯的用positive_reviews / (positive_reviews negative_reviews)校驗一下更穩(wěn)妥。# 發(fā)行年份 df[year] df[release_date].dt.year # 好評率用好評數(shù)重新計算避免原字段單位不統(tǒng)一 review_total df[positive_reviews] df[negative_reviews] df[positive_ratio_calc] df[positive_reviews] / review_total.replace(0, pd.NA) df.loc[review_total 0, positive_ratio_calc] pd.NA # 標簽拆分為列表方便后續(xù)做多標簽分析 df[tags_list] df[tags].fillna().str.split(|) # 把拆分后的標簽展開成長表 tags_expanded df[[app_id, tags_list]].explode(tags_list) tags_expanded tags_expanded.dropna(subset[tags_list]) print(df[[name, year, positive_ratio, positive_ratio_calc]].head()) print(tags_expanded.head())這里最值得關注的是explode這一步。它把一行包含多個標簽的游戲拆成多行好處是后續(xù)做“哪個標簽平均好評率最高”的聚合變得非常直接壞處是如果直接讓訓練集爆炸會引入大量重復樣本。所以我在實際工程里通常會保留兩份數(shù)據一份是原始寬表df用于建模一份是長表tags_expanded用于統(tǒng)計和標簽特征。兩個表用app_id來做映射避免在長表上反復展開和合并。review_total.replace(0, pd.NA)也是一種常見防御寫法沒有評論的游戲不應被當成 0% 好評而應視為未知。后面填充時我會單獨把positive_ratio_calc填為一個中心值比如 0.6而不是 0。這個細節(jié)直接影響推薦系統(tǒng)里冷啟動策略。3.3 清洗后的質量校驗為什么別直接用 groupby 出結論清洗后最常犯的錯是直接df.groupby(year).size()然后開始畫圖結果發(fā)現(xiàn)某一年數(shù)量異常。原因很可能是在release_date解析階段把很多無效值歸到了同一年或者存在重復下載導致的重復行。# 1. 檢查重復主鍵 dup_count df[app_id].duplicated().sum() print(fduplicated app_id: {dup_count}) # 2. 檢查年份分布是否合理 year_dist df[year].value_counts().sort_index() print(year_dist) # 3. 檢查價格是否有極端值 print(df[price].describe()) # 4. 清洗完成校驗保存前確認主鍵唯一 df df.drop_duplicates(subset[app_id], keepfirst) df.to_csv(steam_clean.csv, indexFalse)我一般在剔重前會先問自己一句這個數(shù)據集是從單一 API 拿的還是多個爬蟲拼的如果是多源合并重復不一定是同一款游戲可能是某個 DLC 或測試版占了多個條目。此時app_id唯一不一定合理需要先看name是否完全相同。如果構建推薦系統(tǒng)我會保留最全的那條記錄如果只做市場統(tǒng)計則應該把重復項單獨標記而不是默默刪掉。4. 用 10 個特征回答三個業(yè)務問題趨勢、定價與口碑4.1 2021-2025 發(fā)行數(shù)量與類型遷移清洗完成后第一個值得驗證的問題是2021 到 2025 年Steam 游戲的發(fā)行量到底在漲還是跌如果把release_date拆成年份再疊加上genres分組看會發(fā)現(xiàn)“類型遷移”比總量更有意思某些年份動作射擊類數(shù)量下滑模擬經營和生存類上升。這背后可能是市場偏好變化也可能是爬蟲采集范圍變化所以在得出結論前要給構圖留一個交叉驗證步驟。import pandas as pd df pd.read_csv(steam_clean.csv, parse_dates[release_date]) df[year] df[release_date].dt.year # 按年份統(tǒng)計發(fā)行量 trend df.groupby(year).size().reset_index(namegame_count) # 按年份類型統(tǒng)計 genre_trend df.dropna(subset[genres]).copy() genre_trend[main_genre] genre_trend[genres].str.split(,).str[0].str.strip() genre_trend genre_trend.groupby([year, main_genre]).size().reset_index(namecount) pivot genre_trend.pivot(indexyear, columnsmain_genre, valuescount).fillna(0) print(pivot.head(10))這段代碼里有一個手動選主類型的動作str.split(,).str[0]會把多重類型里的第一個當作主類型因為它最接近游戲的核心分類。這樣處理可以讓pivot后的表列數(shù)不會爆炸到幾十個。如果某些行genres是空值dropna(subset[genres])會丟棄這部分但注意這會減少統(tǒng)計總量單獨畫個餅圖看缺失占比更穩(wěn)妥。4.2 定價策略免費游戲、付費區(qū)間與好評率的關系價格和口碑的關系在游戲行業(yè)里一直是熱門話題。免費游戲因為基礎用戶量大好評率往往高于預期低價獨立游戲則容易陷入“好評但沒銷量”的困境。要驗證這個先把價格分成幾個區(qū)間再看每個區(qū)間的好評率中位數(shù)效果比散點圖直觀得多。bins [-0.01, 0, 9.99, 19.99, 29.99, 59.99, float(inf)] labels [free, under_10, 10_20, 20_30, 30_60, above_60] df[price_range] pd.cut(df[price], binsbins, labelslabels, rightFalse) # 好評率中位數(shù)和游戲數(shù)量 price_group df.dropna(subset[positive_ratio_calc]) \ .groupby(price_range, observedFalse)[positive_ratio_calc] \ .agg([median, count]) print(price_group)pd.cut的rightFalse很關鍵它保證 9.99 被歸到 “under_10” 而不是 “10_20”。另外observedFalse是我們處理 category 類型時防止 pandas 3.0 警告的標準寫法。如果你用過老版本 pandas這里可能會踩到 category 的坑下面一節(jié)會專門講。4.3 把結論沉淀成一張可以直接用的寬表分析完之后我一般會把聚合結果導出成一個更小的寬表用于后續(xù)可視化或前端展示而不是讓其他人直接操作 65k 行的原始表。summary df.groupby(year, as_indexFalse).agg( game_count(app_id, count), mean_price(price, mean), median_ratio(positive_ratio_calc, median), total_positive(positive_reviews, sum), ) summary.to_csv(steam_yearly_summary.csv, indexFalse) print(summary)as_indexFalse讓year保留為列而不是變成索引這樣導出 CSV 后其他人可直接導入 Excel 或做 BI 圖表不用再 reset_index。這張表已經足夠回答經常被問的“這幾年 Steam 游戲整體是不是變貴了”這類問題。5. 常見問題與踩坑處理 Steam 游戲 CSV 時最常翻車的 5 個瞬間5.1 現(xiàn)象讀取 CSV 后 app_id 變成 float后面合并全部錯位原因CSV 里有空行或爬蟲把 app_id 寫成了科學計數(shù)法pandas 自動推斷列類型時把它當成浮點型。此時df[app_id]里的值從amp55變成5.5e05最直接的后果就是 join 外部數(shù)據時能匹配上的一般不足 10%。解決讀取時強制指定dtype{app_id: str}并在讀取后檢查是否存在形如730.0的字符串。如果已發(fā)生用df[app_id] df[app_id].astype(str).str.replace(r\.0$, , regexTrue)清理。5.2 現(xiàn)象release_date 中混入 “2025.1.5” 和 “2025-01-05” 后pd.to_datetime 解析出現(xiàn)不同年月原因Steam 數(shù)據源存在多套格式部分抓取工具會把點號或下劃線當成日期分隔符自動解析會誤以為 “5” 是月份。解決不要信任自動解析。我把release_date先轉成字符串用正則統(tǒng)一替換分隔符為-再指定format或使用errorscoerce配合后續(xù)手工校驗。更穩(wěn)妥的是拿到數(shù)據時就先做一輪strftime標準化而不是等建模前再處理。5.3 現(xiàn)象CSV 里某列出現(xiàn)換行符read_csv 后行數(shù)比預期多幾百行原因游戲簡介或 tags 字段里含有\(zhòng)n如果生成 CSV 時沒有套用 CSV 引號規(guī)則pandas 默認按換行切分導致單行斷成多行。解決讀取時使用quotingcsv.QUOTE_ALL或至少enginepython。如果文件已經損壞可以用csv模塊逐行恢復但更建議從源頭爬蟲端修好寫入時用csv.writer(row)并用quotechar不要手工用逗號拼接字段。5.4 現(xiàn)象清洗后只剩 3 萬行數(shù)據量腰斬原因一次性dropna()把所有有缺失的列全部過濾開發(fā)者、標簽、好評率任一缺失都會刪掉整行。解決改變清洗順序先對主鍵列去重再對參與建模的核心列release_date、price做局部dropna其余缺失列用中位數(shù)、眾數(shù)或專門標記填充。比如developers缺失可以填unknownpositive_ratio_calc缺失可以填 50 分位而不是丟數(shù)據。5.5 現(xiàn)象用外部 Steam 數(shù)據去補 CSV 時按名稱匹配成功率不到一半原因同一游戲在不同來源中的名稱可能差一個空格、年份或副標題比如 “Dota 2” 和 “Dota2” 表現(xiàn)不一致名稱匹配天然不可靠。解決不要直接用name作 key統(tǒng)一通過app_id關聯(lián)。如果外部接口沒有返回 ID先做一個歸一化函數(shù)轉小寫、去空格、統(tǒng)一全半角再生成一個slug列用于模糊匹配。這么做之后匹配率會從 40% 提到 90% 以上。補充數(shù)據時還容易觸發(fā) Steam 側連接失敗或限流提示解決辦法是加隨機延時、按app_id升序遍歷、失敗自動跳過而不是一次性并發(fā)請求。6. 繼續(xù)往前走用清洗后的 CSV 跑一個最小推薦并建立更新習慣6.1 基于類型和標簽做內容推薦的最小實現(xiàn)當字段清洗到genres和tags_list都能干凈使用時最值得做的進階嘗試是內容推薦。對 65k 條游戲做近鄰搜索并不需要復雜的圖模型TF-IDF 加余弦相似度已經能給出不錯的效果而且代碼很短from sklearn.feature_extraction.text import TfidfVectorizer from sklearn.metrics.pairwise import cosine_similarity df[_text] ( df[genres].fillna() df[tags].fillna().astype(str).str.replace(|, , regexFalse) ) vec TfidfVectorizer(min_df2, max_features5000) mat vec.fit_transform(df[_text]) sim cosine_similarity(mat) # 找一個具體游戲做演示 demo_idx df.index[df[name] Dota 2] if len(demo_idx) 0: top5 sim[demo_idx[0]].argsort()[::-1][1:6] print(df.iloc[top5][[name, genres, positive_ratio_calc]])min_df2表示出現(xiàn)次數(shù)低于 2 的標簽直接忽略避免稀碎標簽影響相似度max_features5000是控制詞表規(guī)模防止 65k 行 幾十萬標簽導致矩陣過大。如果你發(fā)現(xiàn)結果里全是類型相似的換皮游戲可以手動調大min_df或給tags更大的權重。我在實際項目里還會把流行度和差評率作為后過濾條件避免推薦“極其相似但評價很差”的作品。6.2 新數(shù)據進來之后怎么維護一年后再看這份 2021-2025 數(shù)據集里面可能已經少了新上線的游戲。常見做法是寫一個定時拉取腳本通過 Steam 官方開發(fā)者接口增量抓新增 app_id再把新數(shù)據concat到原表上進行清洗和去重。new_df pd.read_csv(steam_latest_2026.csv) merged pd.concat([df, new_df], ignore_indexTrue) merged merged.drop_duplicates(subset[app_id], keeplast) merged.to_parquet(steam_games.parquet, indexFalse)這里我會刻意把清洗后的結果存成 Parquet 而不是繼續(xù)存 CSV因為 Parquet 支持類型、壓縮比高隨后的查詢速度更快。如果后續(xù)要接入上層的 Web 服務再多一步to_sql寫入 SQLite 或 PostgreSQL 即可。數(shù)據庫導入 CSV 文件這個操作只有在數(shù)據量小、一次性分析時才建議直接使用一旦進入持續(xù)更新階段還是讓程序寫庫更可控。以前我拿到一個新數(shù)據集總急著跑模型后來發(fā)現(xiàn)特征里的時間、價格、空值全在騙人?,F(xiàn)在我給自己定了一條規(guī)矩先畫分布、后寫 schema、再進模型。這份 2021-2025 Steam 游戲數(shù)據集正好是練手的好目標希望這些經驗能幫到你。本文還有配套的精品資源點擊獲取