ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Airbnb数据集全解析:获取、清洗、价格预测与自建数据实践

2026/9/17 7:25:55 拓冰建站 浏览量
Airbnb数据集全解析:获取、清洗、价格预测与自建数据实践 Airbnb数据集是我做了这么多年数据分析后依然觉得最值得反复拿出来讲的公开数据之一。如果你搜过“Airbnb 数据集”八成会先碰到Kaggle上的New York、Seattle、Boston这几个经典版本但很多人下载完就懵了因为里面是一堆带“$”符号的价格、各种命名不一致的区域字段、还有三张表之间搞不清怎么关联。这篇文章会把Airbnb数据集的获取、清洗、建模、自建数据集的完整链路都过一遍不绕弯子直接用我在实际项目中验证过的方案。适合正在学数据分析、打算拿真实数据集做项目、或者想自己爬一份民宿数据练手的朋友。1. 先搞清楚这个数据集到底长什么样1.1 Airbnb数据集从哪里来有哪些经典版本大家平时说的Airbnb数据集绝大部分来自两个渠道Inside Airbnb和Kaggle的开放数据版本。Inside Airbnb是一个非官方项目持续抓取Airbnb公开页面上的房源信息按城市整理成结构化文件免费供研究者下载数据更新频率高。Kaggle上的版本则大多基于Inside Airbnb的数据二次整理比如“New York City Airbnb Open Data”“Seattle Airbnb Open Data”区别在于有人把字段做了删减、表结构做了合并甚至改过列名导致同一个城市在不同来源里字段对不上。初次接触的话我更推荐直接用Kaggle上的版本。理由很简单有讨论区、有别人跑过的kernel可以参考遇到字段解释不清楚的地方能查到很多经验。如果做的分析对时间跨度有要求比如想看价格随季节怎么波动那就要去Inside Airbnb拉多期快照自己合并因为Kaggle上大多数版本只是某一个时间点的截图没有连续时间面板。我自己的建议是从New York版本入手。原因也很朴素样本量大listings表通常在4.5万行左右、字段丰富、社区讨论多。Boston和Seattle的数据量偏小作为快速验证没问题但要做复杂特征工程时容易过拟合。数据量决定你能玩出什么花样对练手项目来说尽量选样本量充足的城市。1.2 三张核心表listings / calendar / reviewsKaggle上常见的Airbnb数据集会拆成三张表很多人只用了listings这其实是浪费。三张表的核心结构如下listings房源静态信息表一行一个房源。包括房源ID、名称、房东ID、经纬度、价格、房间类型、最少住宿天数、评论数、评分等。这是最常用来做价格预测的表。calendar日历表一行代表一个房源在某一天的可订状态。核心字段是日期、是否可订、当天价格。这张表能算出来每个房源全年的可预订率也能观察节日期间的价格波动。reviews评论表一行一条评论。包含评论ID、房源ID、评论者ID、评论日期、评论内容。做文本分析时这张表价值极高。三张表通过listing_id关联。这种结构特别像电商系统的订单与商品表理解了Airbnb的表关系之后再去看其他业务数据会觉得都是一套模式。listings是主表calendar和reviews都是围绕它的明细表。分析时如果只盯着listings就看不到供给侧的真实供给节奏也看不到用户反馈中最细节的东西。1.3 字段清单里藏着哪些坑字段名在不同版本里差异很大但核心字段如下字段类别典型字段常见问题标识字段id、listing_url、host_idid在部分版本是整数部分版本带前缀文本join前先统一类型价格字段price、cleaning_fee、extra_people几乎都是字符串带$符号和千分位逗号必须清洗位置字段latitude、longitude、neighbourhood_cleansed区域命名大小写和空格不一致坐标精度需要核对房源属性property_type、room_type、accommodates类别多存在同义不同名的情况评价字段number_of_reviews、review_scores_rating大量房源为0且缺失不是随机的时间字段last_review、first_review常见为object类型需要转datetime这里特别说下neighbourhood_cleansed。这个字段是Airbnb官方的清洗后区域名比原始字段干净但不同版本里的区域名仍然会有大小写和空格差异。比如“Williamsburg”和“williamsburg”如果不统一分组统计时就会被拆成两行。我的习惯是在清洗阶段统一做一次全字段的strip、lower、去重音符号金额和坐标字段直接转成floatID字段统统转成字符串再做任何聚合或关联。这些事看起来很琐碎但能帮你少踩一半的坑。2. 拿到数据后第一件事清洗与预处理2.1 价格字段是最经典的脏数据Airbnb的price字段长这样“$1,000.00”。pandas读进来之后是object类型也就是字符串。很多新手直接执行df[price].mean()要么报错要么得到一串无法解释的数字。这是因为字符串拼接或隐式转换把价格搅成一锅粥。标准清洗方式我用了一段代码你可以直接照抄import pandas as pd df pd.read_csv(listings.csv) df[price_clean] ( df[price] .astype(str) .str.replace($, , regexFalse) .str.replace(,, , regexFalse) .str.replace( , , regexFalse) .astype(float) )但这里有个更稳妥的写法不要把强制astype(float)放在链式操作最后因为某些版本里价格可能含有特殊字符比如“—”“nan”或者多语言格式。更好的做法是先把字符串清理干净再用pd.to_numeric加上errorscoerce参数df[price_clean] pd.to_numeric(df[price_clean_raw], errorscoerce)这一步能把所有无法解析的字符串直接变成NaN后面统一用缺失值策略处理。另外要补一个容易忽略的点有的数据集把每周、每月的价格也放在price字段里。分析前最好先检查价格分布的分位数如果出现“$6000”这种明显偏离区域均价的值要确认一下是不是周价格混进来了。跨城市对比时更要检查币种是否一致否则任何价格结论都是错的。2.2 缺失值和离群点的处理策略listings表的缺失值主要集中在name、host_name、last_review、review_scores系列字段。这些字段的缺失含义完全不一样不能都拿“填0”来对付。name和host_name缺失大概率是房源被下架或数据抓取不完整数量通常很少直接删除影响不大。last_review缺失则和number_of_reviews等于0高度重合说明这套缺失本质是“从没收到过评价”不是随机缺失。处理时应该保留一个“是否有过评价”的标识变量而不是简单填0。review_scores_rating缺失原因类似我习惯单独设一个unrated标记列。离群点上纽约版本价格分布在5到1000美元之间都比较常见但真实数据里出现过标价99999美元或者0美元的情况。0美元通常是测试房源或抓取错误直接剔除超高价时要结合accommodates和property_type判断它是真实豪宅还是录入错误。我常用的方法是分位数加业务规则双重筛选比如把价格超过99%分位数但又不符合“可住10人以上”条件的样本单独标出来等分析时再决定是否剔除而不是一上来就删掉。2.3 时间变量与类别变量的转换Airbnb数据里的时间字段有两类。一类是listings表的first_review、last_review记录房源收到第一和最后一条评论的时间另一类是calendar表的date是逐日数据用于时间序列分析。df[last_review] pd.to_datetime(df[last_review], errorscoerce) df[first_review] pd.to_datetime(df[first_review], errorscoerce) df[review_span_days] (df[last_review] - df[first_review]).dt.daysreview_span_days这个衍生字段非常有用它表示房源获得评论的时间跨度比单纯看评论数更能反映房源的稳定运营时间。category字段方面room_type是预测价格最重要的类别特征之一包含“Entire home/apt”“Private room”“Shared room”“Hotel room”四个主流值。要注意有的版本中同一个含义可能有前后空格或大小写不同先用.strip().lower()统一一下。property_type则复杂得多常见有30多种取值如果直接one-hot编码维度会爆炸我建议按业务含义合并成几个大类公寓、独立屋、联排、特色类型甚至直接分“整栋”和“合住”两类模型效果差异不大但特征数量少很多。3. Airbnb数据能回答什么问题核心分析实操3.1 探索性数据分析纽约房源价格长什么样清洗完成后先做一轮EDA搞清楚基本盘。我自己习惯的顺序是单变量分布、分组对比、相关性热力图、地理散点。拿纽约版本举例第一件值得做的事是看价格分布。价格明显右偏大部分房源在50到250美元/晚这个区间少数豪华房源把均值拉得很高。这个结论直接决定了后面建模用MAE还是RMSE作为主评估指标也决定了要不要对价格取log。正常的价格回归任务里对价格做log变换几乎是必做步骤因为它能大幅压缩离群值对模型的影响。第二件是room_type对价格的影响。整租均价比单间高出50%到100%曼哈顿的整租均价远超其他区。这个差距在按neighbourhood分组后会更加明显。第三件是地理可视化用散点图把经纬度画出来能看到曼哈顿核心区价格明显高出一截布鲁克林部分区域形成了第二梯队。地理信息在Airbnb数据里特别值钱但要用好它核心在于坐标字段的精度。原始经纬度通常在小数点后6位如果清洗时被某些工具截断空间分析就没法做了。所以坐标字段在动手处理前一定要先备份一份原值。3.2 从“特征与标签的有机集合”角度看价格预测任务“数据集是特征与标签的有机集合”这句话放在Airbnb场景里特别容易理解。listings表的每一行就是一个样本price就是标签其余的accommodates、room_type、neighbourhood、review_scores系列都是特征。什么叫“有机”我理解有三层意思。一是特征与标签存在业务因果联系比如面积和床位数决定了能住几人能住几人直接影响房东定价二是特征之间互相约束比如room_type是Private room的房源accommodates通常不超过4三是样本不是孤立的同一个房东旗下多个房源存在相关性同一个地理位置附近的房源也存在强烈的空间相关性。这些关系如果不理解后面做特征工程就是瞎试。做价格预测任务时我通常把特征分成三类直接价格因子accommodates、bedrooms、bathrooms、room_type、property_type。间接价格因子review_scores_rating、number_of_reviews、review_span_days、availability_365。空间因子neighbourhood_cleansed、经纬度聚类标签。另外可以构造一个“是否可立即订房”的布尔特征这个特征有时比直接用availability_365数值更能反映房源热度因为数值型字段在不同租金档位的分布差异很大切成布尔后反而更干净。3.3 基线模型搭建与效果评估很多朋友一上来就上XGBoost其实跑一个线性回归作为基线更有意义。用MAE、RMSE、R²三个指标一方面看模型整体做得好不好另一方面给后续复杂模型设一个参照线。代码就是标准流程但我把关键部分写出来from sklearn.model_selection import train_test_split from sklearn.linear_model import LinearRegression from sklearn.metrics import mean_absolute_error, mean_squared_error, r2_score import numpy as np df_model df.dropna(subset[price_clean]) features [accommodates, bedrooms, bathrooms, number_of_reviews, availability_365] X df_model[features].fillna(0) y df_model[price_clean] X_train, X_test, y_train, y_test train_test_split(X, y, test_size0.2, random_state42) model LinearRegression() model.fit(X_train, y_train) y_pred model.predict(X_test) print(MAE:, mean_absolute_error(y_test, y_pred)) print(RMSE:, np.sqrt(mean_squared_error(y_test, y_pred))) print(R2:, r2_score(y_test, y_pred))第一次跑的R²能到0.35就算不错了因为影响价格的核心变量是位置和房源质量现在这个特征列表里位置信息基本没进去。这时候把neighbourhood_cleansed做one-hot把价格取log再跑一次模型提升会非常明显。这个现象也解释了为什么Kaggle比赛里特征工程对价格预测的提升远大于调参。数据的信息结构决定了模型天花板参数只是逼近这个天花板的手段。到了这个阶段“特征与标签的有机集合”就体现得非常具体不加区域特征模型只知道房源大小不知道它在曼哈顿还是皇后区不加评论特征模型不知道房源口碑。预测任务能不能做好本质上就看特征和标签之间的业务关联是否被有效编码进模型。3.4 calendar和reviews这两张表怎么用listings表做价格预测是常规操作但如果只盯着这张表就浪费了Airbnb数据集最有趣的部分。calendar表是逐日粒度能计算每个房源的可预订率、每个区域不同季节的供给与价格变化reviews表则能做文本情感分析提取用户痛点。我拿calendar表举个例子# 假设 calendar 表已经读进来列名为 listing_id, date, available calendar[date] pd.to_datetime(calendar[date]) calendar[available] calendar[available].map({t: 1, f: 0}) availability calendar.groupby(listing_id)[available].sum().rename(annual_available_days) df df.merge(availability, left_onid, right_indexTrue, howleft)这样得到的annual_available_days就成了一条新特征表示这一年里有多少天能被预订。这个字段比listings里自带的availability_365更贴近真实运营状态因为后者可能只是抓取当天的快照值。评论数据里则可以抽取评论长度、情感分数、提到“干净”“位置”等关键词的次数作为补充特征。多表合并的价值在这里体现得淋漓尽致。4. 进阶自己采集并构建Airbnb数据集4.1 为什么公开数据可能不够用公开数据集适合学习和做通用分析但真到了产品需求上会遇到三个问题时间不是最新的、空间粒度不满足要求、字段定义与自己的业务对不上。比如想分析某个城市最新一个月短租市场的变化Kaggle旧版本完全帮不上忙想按街道级别分析公开数据只有区级字段没法直接用。这时候就得考虑自己构建数据集。很多朋友听到“构建数据集”就联想到爬虫实际上构建一套可用的数据集核心工作不是写爬虫而是定义schema、规范数据质量、形成可重复的更新流程。这一点和做目标检测的同学准备“YOLO训练自己的数据集”有很强的共通之处数据来自哪里、怎么标注、怎么质检、怎么管理版本这些步骤比跑通代码更重要。数据质量决定了模型上限这句话在图像数据集里成立在Airbnb这类结构化数据里同样成立。推荐学习一下“数据集质量要求及评价方法”这类标准你会发现任何数据集都要回答三个问题完整性、一致性、可用性。4.2 从需求出发设计schema自己构建Airbnb数据集第一件事不是抓数据而是画数据字典。我一般从业务问题倒推要分析什么、需要哪些字段、字段类型是什么、更新频率多久。比如要分析“新上线房源的特征”listings快照就需要至少每周抓一次每次抓取时保存抓取时间和房源当时的状态。这样一来日后才能区分“房源上线于11月”和“11月房源价格发生变化”。schema设计时建议加三个公用的技术字段抓取时间、数据来源、批次号。以后排查数据质量问题时这三个字段能很快定位问题是哪一批数据导致的。同时存储上我强烈推荐用快照表加主数据表的双层结构。快照表记录每次抓到的全量字段主数据表只保留每个房源的最新状态。这样既保留历史追溯能力又不至于在每次分析时重复清洗全量数据。4.3 抓取、清洗与质检的注意点如果决定自建数据理论上可以基于Airbnb公开页面的接口来抓但接口和页面结构会变所以代码必须把“解析逻辑”和“存储逻辑”分离避免页面改版后全盘重写。清洗阶段和前面讲的一致但自建数据还要处理去重和增量更新。同一个房源ID在不同批次爬下来价格和评论数都可能变了所以更新时要用业务主键加抓取时间做唯一性约束不能简单覆盖。质检环节要形成自动检查脚本至少做这几件事字段缺失率、行数波动、关键字段的类型、价格字段的取值范围、区域字段的枚举值数量。如果某批次抓取的区域枚举值数量比上一批少了几个先别急着高兴很可能是页面结构变化导致部分字段解析失败。一个能重复生产、可追溯、能自动质检的数据集才配叫做“数据集”否则只能算一次性的下载文件。5. 实操中常见的坑与我的排查记录5.1 编码和字段名混乱不同来源的CSV编码不一致有时是UTF-8有时是latin1直接用pd.read_csv会出现乱码或者解析错误。最稳妥的做法是尝试两种编码try: df pd.read_csv(listings.csv, encodingutf-8) except UnicodeDecodeError: df pd.read_csv(listings.csv, encodinglatin1)字段名方面不同版本对于“价格”到底对应price还是local_price各执一词有的版本甚至有几十个列名雷同的字段。所以load完先打印columns列表人眼确认一遍再动手清洗不要上来就找固定列名写代码。5.2 价格符号与多币种问题公开数据集中有的版本价格带美元符号有的版本把cleaning_fee单独列出来还有的版本extra_people字段是0或是空值。分析时必须确定总价口径不能只盯着price一个字段。我习惯把“房价加清洁费”作为总价参与模型这样更接近用户实际支付金额。如果做多城市合并务必先检查币种再统一汇率口径否则跨城市对比毫无意义。5.3 评论数据的时间跨度不均衡reviews表的时间范围往往横跨好几年有的房源上线早、评论多有的上线晚、评论少直接用评论数做特征会带来严重的幸存者偏差。比如一个上线6年、只有30条评论的房源和一个上线3个月、只有10条评论的房源评论数的含义完全不同。比较公允的做法是计算“平均每月评论数”之类的时间衰减特征把上线时长这个分母考虑进去而不是死盯着number_of_reviews原值。5.4 实践下来的经验沉淀这套数据玩久了之后真正值得花时间的是三件事把字段语义弄清楚把多表连接逻辑搞对把评估指标和业务问题对应起来。Airbnb数据集的经典问题“价格预测”看起来简单但每一种特征选择背后都有业务假设。数据质量决定了模型上限这句话在这个项目里不是空话。清洗时保留处理过程分析时说明处理逻辑比直接丢一个模型结果更让人信服。最后再分享一个我自己踩过很多次坑的细节划分训练集和测试集时一定要固定random_state并且把整个处理流程整理成脚本。很多人模型效果不错但代码不可复现因为随机种子没固定或者中途手动改过数据。做任何数据集项目可复现性永远值得排在前面。Airbnb数据集最大的价值在于它足够真实字段足够杂能让你在一个人畜无害的练手项目里提前体验工业级数据分析里最磨人的那些环节。