京公网安备 11010802034615号
经营许可证编号:京B2-20210330
(干货)数据分析案例--以上海二手房为例
如果你手上有一批数据,你可能应用统计学、挖掘算法、可视化方法等技术玩转你的数据,但你没有数据的时候,我该怎么玩呢?接下来就带着大家玩玩没有数据情况下的数据分析。
本文从如下几个目录详细讲解数据分析的流程:
1、数据源的获取;
2、数据探索与清洗;
3、模型构建(聚类算法和线性回归);
4、模型预测;
5、模型评估;
一、数据源的获取
正如本文的题目一样,我要分析的是上海二手房数据,我想看看哪些因素会影响房价?哪些房源可以归为一类?我该如何预测二手房的价格?可我手上没有这样的数据样本,我该如何回答上面的问题呢?
互联网时代,网络信息那么发达,信息量那么庞大,随便找点数据就够喝一壶了。前几期我们已经讲过了如何从互联网中抓取信息,采用Python这个灵活而便捷的工具完成爬虫,例如:
通过Python抓取天猫评论数据
使用Python实现豆瓣阅读书籍信息的获取
使用Python爬取网页图片
当然,上海二手房的数据仍然是通过爬虫获取的,爬取的平台来自于链家,页面是这样的:

我所需要抓取下来的数据就是红框中的内容,即上海各个区域下每套二手房的 小区名称、户型、面积、所属区域、楼层、朝向、售价及单价 。先截几张Python爬虫的代码,源代码和数据分析代码写在文后的链接中,如需下载可以到指定的百度云盘链接中下载。

上面图中的代码是构造所有需要爬虫的链接。
上面图中的代码是爬取指定字段的内容。
爬下来的数据是长这样的(总共28000多套二手房):

二、数据探索与清洗(一下均以R语言实现)
当数据抓下来后,按照惯例,需要对数据做一个探索性分析,即了解我的数据都长成什么样子。
1、户型分布
# 户型分布
library(ggplot2)
type_freq <- data.frame(table(house$户型))
# 绘图
type_p <- ggplot(data = type_freq, mapping = aes(x = reorder(Var1, -Freq),y = Freq)) + geom_bar(stat = 'identity', fill = 'steelblue') + theme(axis.text.x = element_text(angle = 30, vjust = 0.5)) + xlab('户型') + ylab('套数')
type_p

我们发现只有少数几种的户型数量比较多,其余的都非常少,明显 属于长尾分布类型(严重偏态) ,所以,考虑将1000套一下的户型统统归为一类。
# 把低于一千套的房型设置为其他
type <- c('2室2厅','2室1厅','3室2厅','1室1厅','3室1厅','4室2厅','1室0厅','2室0厅')
house$type.new <- ifelse(house$户型 %in% type, house$户型,'其他')
type_freq <- data.frame(table(house$type.new))
# 绘图
type_p <- ggplot(data = type_freq, mapping = aes(x = reorder(Var1, -Freq),y = Freq)) + geom_bar(stat = 'identity', fill = 'steelblue') + theme(axis.text.x = element_text(angle = 30, vjust = 0.5)) + xlab('户型') + ylab('套数')
type_p

2、二手房的面积和房价的分布
# 面积的正态性检验
norm.test(house$面积)

# 房价的正态性检验
norm.test(house$价格.W.)
上面的norm.test函数是我自定义的函数 ,函数代码也在下文的链接中,可自行下载。从上图可知, 二手房的面积和价格均不满足正态分布,那么就不能直接对这样的数据进行方差分析或构建线性回归模型 ,因为这两种统计方法,都要求正态性分布的前提假设,后面我们会将讲解如何处理这样的问题。
3、二手房的楼层分布
原始数据中关于楼层这一变量,总共有151种水平,如地上5层、低区/6层、中区/11层、高区/40层等,我们觉得有必要将这151种水平设置为低区、中区和高区三种水平,这样做有助于后面建模的需要。
# 把楼层分为低区、中区和高区三种
house$floow <- ifelse(substring(house$楼层,1,2) %in% c('低区','中区','高区'), substring(house$楼层,1,2),'低区')
# 各楼层类型百分比分布
percent <- paste(round(prop.table(table(house$floow))*100,2),'%',sep = '')
df <- data.frame(table(house$floow))
df <- cbind(df, percent)
df
可见,三种楼层的分布大体相当,最多的为高区,占了36.1%。
4、上海各地区二手房的均价
# 上海各区房价均价
avg_price <- aggregate(house$单价.平方米., by = list(house$区域), mean)
#绘图
p <- ggplot(data = avg_price, mapping = aes(x = reorder(Group.1, -x), y = x, group = 1)) + geom_area(fill = 'lightgreen') + geom_line(colour = 'steelblue', size = 2) + geom_point() + xlab('') + ylab('均价')
p

很明显,上海二手房价格最高的三个地区为:静安、黄埔和徐汇,均价都在7.5W以上,价格最低的三个地区为:崇明、金山和奉贤。
5、房屋建筑时间缺失严重

建筑时间这个变量有6216个 缺失,占了总样本的22% 。虽然缺失严重,但我也不能简单粗暴的把该变量扔掉, 所以考虑到按各个区域分组,实现众数替补法 。这里构建了两个自定义函数:
library(Hmisc)
# 自定义众数函数
stat.mode <- function(x, rm.na = TRUE){
if (rm.na == TRUE){
y = x[!is.na(x)]
}
res = names(table(y))[which.max(table(y))]
return(res)
}
# 自定义函数,实现分组替补
my.impute <- function(data, category.col = NULL,
miss.col = NULL, method = stat.mode){
impute.data = NULL
for(i in as.character(unique(data[,category.col]))){
sub.data = subset(data, data[,category.col] == i)
sub.data[,miss.col] = impute(sub.data[,miss.col], method)
impute.data = c(impute.data, sub.data[,miss.col])
}
data[,miss.col] = impute.data
return(data)
}
# 将建筑时间中空白字符串转换为缺失值
house$建筑时间[house$建筑时间 == ''] <- NA
#分组替补缺失值,并对数据集进行变量筛选
final_house <- subset(my.impute(house, '区域', '建筑时间'),select = c(type.new,floow,面积,价格.W.,单价.平方米.,建筑时间))
#构建新字段,即建筑时间与当前2016年的时长
final_house <- transform(final_house, builtdate2now = 2016-as.integer(substring(as.character(建筑时间),1,4)))
#删除原始的建筑时间这一字段
final_house <- subset(final_house, select = -建筑时间)
最终完成的干净数据集如下:
接下来就可以针对这样的干净数据集,作进一步的分析,如聚类、线性回归等。
三、模型构建
这么多的房子,我该如何把它们分分类呢?即应该把哪些房源归为一类?这就要用到聚类算法了, 我们就使用简单而快捷的k-means算法实现聚类的工作 。但聚类前,我需要掂量一下我该聚为几类?根据 聚类原则:组内差距要小,组间差距要大 。我们绘制不同类簇下的组内离差平方和图,聚类过程中,我们选择面积、房价和单价三个数值型变量:
tot.wssplot <- function(data, nc, seed=1234){
#假设分为一组时的总的离差平方和
tot.wss <- (nrow(data)-1)*sum(apply(data,2,var))
for (i in 2:nc){
#必须指定随机种子数
set.seed(seed)
tot.wss[i] <- kmeans(data, centers=i, iter.max = 100)$tot.withinss
}
plot(1:nc, tot.wss, type="b", xlab="Number of Clusters",
ylab="Within groups sum of squares",col = 'blue',
lwd = 2, main = 'Choose best Clusters')
}
# 绘制不同聚类数目下的组内离差平方和
standrad <- data.frame(scale(final_house[,c('面积','价格.W.','单价.平方米.')]))
myplot <- tot.wssplot(standrad, nc = 15)
当把所有样本当作一类时,离差平方和达到最大,随着聚类数量的增加,组内离差平方和会逐渐降低,直到极端情况,每一个样本作为一类,此时组内离差平方和为0。从上图看,聚类数量在5次以上,组内离差平方降低非常缓慢,可以把拐点当作5,即聚为5类。
# 将样本数据聚为5类
set.seed(1234)
clust <- kmeans(x = standrad, centers = 5, iter.max = 100)
table(clust$cluster)

# 按照聚类的结果,查看各类中的区域分布
table(final_house$区域,clust$cluster)

# 各户型的平均面积
aggregate(final_house$面积, list(final_house$type.new), mean)

# 按聚类结果,比较各类中房子的平均面积、平均价格和平均单价
aggregate(final_house[,3:5], list(clust$cluster), mean)

从平均水平来看,我大体可以将28000多套房源合成为如下几种说法:
a、大户型(3室2厅、4室2厅),属于第2类。 平均面积都在130平以上,这种大户型的房源主要分布在青浦、黄埔、松江等地(具体可从 各类中的区域分布图可知 )。
b、地段型(房价高),属于第1类。 典型的区域有黄埔、徐汇、长宁、浦东等地(具体可从 各类中的区域分布图可知 )。
c、大众蜗居型(面积小、价格适中、房源多),属于第4和5类。 典型的区域有宝山、虹口、闵行、浦东、普陀、杨浦等地
d、徘徊型(大户型与地段型之间的房源),属于第3类。 典型的区域有奉贤、嘉定、青浦、松江等地。这些地区也是将来迅速崛起的地方。
# 绘制面积与单价的散点图,并按聚类进行划分
p <- ggplot(data = final_house[,3:5], mapping = aes(x = 面积,y = 单价.平方米., color = factor(clust$cluster)))
p <- p + geom_point(pch = 20, size = 3)
p + scale_colour_manual(values = c("red","blue", "green", "black", "orange"))

接下来我想 借助于已有的数据(房价、面积、单价、楼层、户型、建筑时长、聚类水平)构建线性回归方程 ,用于房价因素的判断及预测。由于数据中有离散变量,如户型、楼层等,这些变量入模的话需要对其 进行哑变量处理 。
# 构造楼层和聚类结果的哑变量
# 将几个离散变量转换为因子,目的便于下面一次性处理哑变量
final_house$cluster <- factor(clust$cluster)
final_house$floow <- factor(final_house$floow)
final_house$type.new <- factor(final_house$type.new)
# 筛选出所有因子型变量
factors <- names(final_house)[sapply(final_house, class) == 'factor']
# 将因子型变量转换成公式formula的右半边形式
formula <- f <- as.formula(paste('~', paste(factors, collapse = '+')))
dummy <- dummyVars(formula = formula, data = final_house)
pred <- predict(dummy, newdata = final_house)
head(pred)

# 将哑变量规整到final_house数据集中
final_house2 <- cbind(final_house,pred)
# 筛选出需要建模的数据
model.data <- subset(final_house2,select = -c(1,2,3,8,17,18,24))
# 直接对数据进行线性回归建模
fit1 <- lm(价格.W. ~ .,data = model.data)
summary(fit1)

从体看上去还行,只有建筑时长和2室0厅的房型参数不显著,其他均在0.01置信水平下显著。 不要赞赞自喜 ,我们说,使用线性回归是有假设前提的,即因变量满足正态或近似于正态分布,前面说过,房价明显在样本中是偏态的,并不服从正态分布,所以这里 使用COX-BOX变换处理 。根据COX-BOX变换的lambda结果,我们针对y变量进行转换,即:
# Cox-Box转换
library(car)
powerTransform(fit1)

根据结果显示, 0.23非常接近上表中的0值,故考虑将二手房的价格进行对数变换。
fit2 <- lm(log(价格.W.) ~ .,data = model.data)
summary(fit2)
这次的结果就明显比fit1好很多 ,仅有楼层的中区在0.1置信水平下显著,其余变量均在0.01置信水平下显著, 而且调整的R方值也提高到了94.3% ,即这些自变量对房价的解释度达到了94.3%。
最后我们再看一下,关于最终模型的诊断结果:
# 使用plot方法完成模型定性的诊断
opar <- par(no.readonly = TRUE)
par(mfrow = c(2,2))
plot(fit2)
par(opar)
从上图看,基本上满足了线性回归模型的几个假设,即:残差项服从均值为0(左上),标准差为常数(左下)的正态分布分布(右上)。基于这样的模型,我们就可以有针对性的预测房价啦~
数据分析咨询请扫描二维码
若不方便扫码,搜微信号:CDAshujufenxi
【核心关键词】贷款、报表、课程、专业、建模、缺失值、营销、互联网、银行、办公自动化、数据分析、数据预处理、特征工程、贷 ...
2026-06-05在数据库数据查询、业务报表统计、多表关联分析中,LEFT JOIN左连接是使用率最高的SQL关联查询语句。其核心特性是保留左表全部数 ...
2026-06-05 很多数据分析师能熟练地写SQL、做透视表、算描述性统计,但当被问到“如何预测用户流失概率”“如何归因销量下滑的关键因素 ...
2026-06-05任何一款产品从诞生、普及到最终退出市场,都会遵循一套固定的发展规律,这就是产品生命周期理论。在市场竞争日益激烈、产品迭代 ...
2026-06-04在Excel数据分析、办公统计、业务报表制作场景中,数据透视表是数据汇总、分类统计、快速复盘的核心工具,能够高效完成海量原始 ...
2026-06-04 很多数据分析师拿到数据就开始清洗、建模,但当被问到“这批数据属于什么类型——结构化还是非结构化?分类变量还是数值变量 ...
2026-06-04在问卷调查与社会科学数据分析中,卡方检验是最常用、最基础的非参数检验方法,广泛应用于市场调研、用户分析、行为统计、满意度 ...
2026-06-03【核心关键词】贷款、报表、课程、专业、建模、缺失值、营销、互联网、银行、办公自动化、数据分析、数据预处理、特征工程、贷 ...
2026-06-03 很多数据分析师画过趋势图、做过业绩预测,但当被问到“这个月销售额增长20%,到底是长期趋势自然增长,还是促销活动的短期 ...
2026-06-03逻辑回归是数据分析、机器学习、统计建模中应用最广泛的二分类预测模型,常用于风险判断、行为预测、归因分析等场景。在SPSS、Py ...
2026-06-02数字经济时代,市场竞争日趋同质化,用户消费需求愈发个性化、多元化,传统依托经验、粗放式、广撒网的营销模式弊端日益凸显。长 ...
2026-06-02 很多数据分析师做过按月份的销售额趋势图,画过按天的流量折线图,但当被问到“时间序列和普通数据有什么本质区别”“季节性 ...
2026-06-02在市场竞争日趋饱和、用户需求不断细分的当下,企业创业创新、产品迭代与市场拓展不再依赖经验决策,而是需要系统化、工具化的商 ...
2026-06-01【核心关键词】调度、岗位、数据库、企业、报表、培训、程序、数据分析、数据加工、业务部门、企业数据、调度工具、业务指标、 ...
2026-06-01 很多数据分析师能熟练地计算指标、搭建标签体系,但当被问到“画像到底在解决什么问题”“画像和标签是什么关系”“画像如何 ...
2026-06-01在数据统计分析、数据清洗、异常值识别与数据分布研究中,箱型图是最直观、高效、专业的可视化分析工具。相较于柱状图、折线图仅 ...
2026-05-29Tkinter是Python内置的标准GUI图形界面库,具备无需额外安装、调用简单、兼容性强、轻量化高效等优势,是Python快速开发桌面小程 ...
2026-05-29 很多分析师在设计标签时思路清晰,但真到落地环节却面临“数据在手,不知如何转化为可用标签”的困境:或因加工方式选择不当 ...
2026-05-29【核心关键词】大数据、经理、专业、金融、客户、传统、建模、数据产品、互联网金融、产品经理、数据分析、金融行业、数据模型 ...
2026-05-28 很多分析师每天和数据打交道,但当被问到“标签是什么”“标签和指标有什么区别”“标签体系如何设计”时,却常常答不上来。 ...
2026-05-28