Loading [MathJax]/jax/input/TeX/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >链家网 爬虫+数据分析 实战案例

链家网 爬虫+数据分析 实战案例

作者头像
龙哥
发布于 2019-07-31 07:39:13
发布于 2019-07-31 07:39:13
2K00
代码可运行
举报
文章被收录于专栏:Python绿色通道Python绿色通道
运行总次数:0
代码可运行

上周有某高校老师来我们公司进行培训,公司安排我上了两天课。最后一天是一个数据分析的小案例,这里记录分享一下,比较适合刚入门的小白练手。

大概的逻辑是这样的:利用Scrapy爬取了链家的2900余条成都二手房的数据,然后基于这些数据做了一些关于房屋价格、区域、户型、房屋数量等方面的分析。

在分析之前呢,数据已经爬取好了,存到了Excel当中,所以这里就不演示爬虫部分,只进行分析部分的说明。但是需要看一下爬取的都是哪些字段

接下来就正式进入分析部分。首先导入必要的库,并做一部分设置:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import re
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt

# 指定画布风格
plt.style.use("fivethirtyeight")

# Mac环境下设置中文字体
plt.rcParams['font.family'] = ['Arial Unicode MS'] #用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False #用来正常显示负号
sns.set_style({'font.sans-serif':['Arial Unicode MS','Arial']})

# Windows环境下设置中文字体
# sns.set_style({'font.sans-serif':['simhei','Arial']})

# 如果代码不在jupyter中执行,可以删掉
%matplotlib inline

我用的IDE是jupyter lab,分析部分主要使用pandas库,绘图部分用到了matplotlib和seaborn,在后面进行数据预处理部分我们需要用到正则表达式,所以同时导入re模块。

接下来为了美化图片我们统一设置了画布风格,同时为了在图片中正常显示中文做了字体设置。

然后就可以导入我们的数据了。需要说明的是我是将爬取的数据保存在同级目录下名为house.xlsx的文件中。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
house_df = pd.read_excel('house.xlsx')
# 看一下数据长什么样子
house_df.head()

输出:

因为字段太多,所以字段显示不完整,但是可以大概了解一下。

查看一下缺失值的情况

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# 查看确实值情况
house_df.info()

输出:

我们可以看到有些字段是2993行,有些字段是2895行,甚至还有2890行。这说明我们的数据中有缺失值存在,我们需要做的就是过滤掉缺失值。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
house_df.dropna(inplace=True)
house_df.info()

过滤掉缺失值之后,再看一下

现在所有字段都是2886行,可以进行下一步了。

由于目前的数据中,很多字段都是带单位的字符串类型,我们需要做的是将它们转换为不带单位的字符串类型,这样的话有助于我们后续的分析。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# 做一部分预处理
house_df['houseTotalMoney'] = house_df['houseTotalMoney'].apply(lambda x: float(x.replace('万', '')))
house_df['houseSinglePrice'] = house_df['houseSinglePrice'].apply(lambda x: float(x.replace('元/平米', '')))
house_df['houseDownPayment'] = house_df['houseDownPayment'].apply(lambda x: float(x.replace('万', '')))
house_df['houseBuildingArea'] = house_df['houseBuildingArea'].apply(lambda x: float(x.replace('㎡', '')))
house_df['totalFloor'] = house_df['houseFloor'].apply(lambda x:re.search('\d+', x).group())

在上面的代码中,我们去掉了houseTotalMoney、houseSinglePrice、houseDownPayment、houseBuildingArea四个字段的单位,并将其转换为float类型。最后一行中我们提取了houseFloor字段中的数字来表示房屋总楼层,保存到house_df的totalFloor列中。

然后我们再做一个小处理,从houseLocation字段中提取行政区信息,然后保存到Region列中。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# houseLocation字段表示区域,我们取前两个字,然后方便分区统计
house_df['Region'] = house_df['houseLocation'].apply(lambda x:x.split('/')[0])

看一下整体统计信息

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# 再次观察有异常值
house_df.describe() # houseNumber为房屋编号 不用管

输出:

我们看到总价的平均值是143.65万,最便宜的是32万(有可能是老房子、公寓之类的,正常),最贵的是1100万。单价方面,均价是15685元/平米,最便宜的是5129元/平米,最贵的是44846元/平米。

现在正式进入可视化阶段。

首先我们看一下单价、房屋数量、总价和行政区的关系

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# 按区域分析数量和价格
df_house_count = house_df.groupby('Region')['houseId'].count().sort_values(ascending=False).to_frame().reset_index().reindex(['Region', 'Count'], axis=1)
df_house_mean = house_df.groupby('Region')['houseSinglePrice'].mean().sort_values(ascending=False).to_frame().reset_index()

f, [ax1, ax2, ax3] = plt.subplots(3, 1, figsize=(12, 18))
sns.barplot(x='Region', y='houseSinglePrice', palette='Blues_d', data=df_house_mean, ax=ax1)
ax1.set_title('成都各区二手房每平米单价对比')
ax1.set_xlabel('区域')
ax1.set_ylabel('每平米单价')

sns.barplot(x='Region', y='Count', palette='Greens_d', data=df_house_count, ax=ax2)
ax2.set_title('成都各区二手房数量对比')
ax2.set_xlabel('区域')
ax2.set_ylabel('数量')

sns.boxplot(x='Region', y='houseTotalMoney', data=house_df, ax=ax3)
ax3.set_title('成都各区二手房房屋总价')
ax3.set_xlabel('区域')
ax3.set_ylabel('房屋总价')

plt.savefig('images/img1')
plt.show()

输出:

看一下房屋面积的分布情况,还有面积和总价的相关性

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
f, [ax1,ax2] = plt.subplots(1, 2, figsize=(16, 6))
# 房屋面积
sns.distplot(house_df['houseBuildingArea'], ax=ax1, color='r')
sns.kdeplot(house_df['houseBuildingArea'], shade=True, ax=ax1)
ax1.set_xlabel('面积')

# 房屋面积和价格的关系
sns.regplot(x='houseBuildingArea', y='houseTotalMoney', data=house_df, ax=ax2)
ax2.set_xlabel('面积')
ax2.set_ylabel('总价')

plt.savefig('images/img2')
plt.show()

输出:

看一下户型的数量情况

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
f, ax1 = plt.subplots(figsize=(12,12))
sns.countplot(y='houseType', data=house_df, ax=ax1)
ax1.set_title('房屋户型', fontsize=15)
ax1.set_xlabel('数量')
ax1.set_ylabel('户型')

plt.show()

输出:

看一下装修情况

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
f, [ax1,ax2,ax3] = plt.subplots(1, 3, figsize=(20, 5))
sns.countplot(house_df['houseDecoration'], ax=ax1)
sns.barplot(x='houseDecoration', y='houseTotalMoney', data=house_df, ax=ax2)
sns.boxplot(x='houseDecoration', y='houseTotalMoney', data=house_df, ax=ax3)

plt.savefig('images/img4')
plt.show()

输出:

看一下电梯的情况

统计电梯信息之前我们先做一下词频统计:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
house_df['houseElevator'].value_counts()

输出:

我们看到有179套是“暂无数据”,对于这种情况我们就需要处理一下了。具体的处理方法有很多种,要根据不同的场景去选择,我们这里只是为了学习,可以粗暴一点,直接过滤掉,不让其参与计算。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
elevator_df = house_df[house_df['houseElevator'] != '暂无数据']
elevator_df['houseElevator'].value_counts()

输出:

开始绘图:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
f, [ax1, ax2] = plt.subplots(1, 2, figsize=(16, 8))
sns.countplot(elevator_df['houseElevator'], ax=ax1)
ax1.set_title('有无电梯数量对比', fontsize=15)
ax1.set_xlabel('是否有电梯')
ax1.set_ylabel('数量')

sns.barplot(x='houseElevator', y='houseSinglePrice', data=elevator_df, ax=ax2)
ax2.set_title('有无电梯房价对比')
ax2.set_xlabel('是否有电梯')
ax2.set_ylabel('单价')

plt.savefig('images/img5')
plt.show()

输出:

最后来看一下总楼层的数量情况

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
f, ax1 = plt.subplots(figsize=(20,5))
sns.countplot(x='totalFloor', data=house_df, ax=ax1)
ax1.set_title('房屋楼层',fontsize=15)
ax1.set_xlabel('总楼层')
ax1.set_ylabel('数量')

plt.savefig('images/img6')
plt.show()

输出:

以上只是一个学习用的简单例子,如果要在生产环境中使用的话还需要做一部分改动。比如涉及到两次缺失值的处理问题,要根据具体的情况去选择相应的方法;比如对于统计的图表选择也要根据具体的业务场景去选择;而且我们这个案例中是没有涉及到异常值的处理,实际上房屋价格是存在异常值的——20多万的房子肯定是不存在的,我怀疑是车位的交易信息。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-07-30,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Python绿色通道 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
初识Linux · 信号保存
前文我们已经介绍了信号产生,在时间的学习线上,信号的学习分为预备知识,信号产生,信号保存,信号处理,本文我们学习信号保存,在前言部分,我们介绍几个信号保存中的概念。
_lazy
2024/11/19
2240
初识Linux · 信号保存
【Linux】信号的保存
我们也介绍了core term两种默认操作,core在执行信号后会形成一份core文件(默认是关闭的,因为原本core文件的后缀是pid,运行出错后会创建core文件,导致磁盘空间不足),该文件里存储了出错原因,可以再gdb调试时进行使用。
叫我龙翔
2024/06/23
2900
【Linux】信号的保存
Linux进程信号【信号保存】
信号从产生到执行,并不会被立即处理,这就意味着需要一种 “方式” 记录信号是否产生,对于 31 个普通信号来说,一个 int 整型就足以表示所有普通信号的产生信息了;信号还有可能被 “阻塞”,对于这种多状态、多结果的事物,操作系统会将其进行描述、组织、管理,这一过程称为 信号保存 阶段
北 海
2023/07/01
5390
Linux进程信号【信号保存】
Linux信号的保存和处理
每一个信号都有着三张表:block、pending、handler。 两张位图+一张函数指针数组=进程识别信号
南桥
2024/07/26
1750
Linux信号的保存和处理
【Linux进程信号】Linux信号机制深度解析:保存与处理技巧
🔍前言:在Linux操作系统的广阔天地中,信号机制无疑是一个充满挑战与机遇的领域。信号,作为进程间通信的一种重要方式,不仅承载着丰富的信息,还扮演着进程控制与管理的重要角色。然而,对于许多初学者而言,信号的保存与处理往往是一个难以逾越的障碍
Eternity._
2024/10/15
2210
【Linux进程信号】Linux信号机制深度解析:保存与处理技巧
【Linux】进程信号的发送和保存
通过指令man -7 signal查看信号的手册,然后往下翻翻可以看到普通信号发出后对应的操作,以及它们的信号编号,和详细描述信息
s-little-monster
2025/04/01
860
【Linux】进程信号的发送和保存
信号初相识:Linux 内核的 “隐形使者”
在 Linux 系统的广袤世界里,信号(Signal)宛如一位神秘的隐形使者,默默地在后台发挥着至关重要的作用。它是一种异步通信机制,如同古代的烽火台,当特定事件发生时,便会燃起 “烽火”,通知进程做出相应的反应。信号可以来自硬件异常,如内存访问错误、除零错误;也能由软件条件触发,像是用户按下特定的按键组合,或者程序主动调用系统函数发送信号 。
用户11396661
2025/02/28
960
【linux学习指南】详解Linux进程信号保存
如果在进程解除对某信号的阻塞之前这种信号产⽣过多次,将如何处理?POSIX.1允许系统递送该信 号⼀次或多次。Linux是这样实现的:常规信号在递达之前产⽣多次只计⼀次,⽽实时信号在递达之 前产⽣多次可以依次放在⼀个队列⾥。本章不讨论实时信号。
学习起来吧
2024/12/01
1450
【linux学习指南】详解Linux进程信号保存
【Linux】信号保存与信号捕捉处理
那么在学习信号保存之前,我们先了解一下信号的发送,我们知道普通信号一共有31个,如下:
YoungMLet
2024/03/01
2580
【Linux】信号保存与信号捕捉处理
【linux】信号的保存和递达处理
        上节我们了解到了预备(信号是什么,信号的基础知识)再到信号的产生(四种方式)。今天我们了解信号的保存。信号产生,进程不一定立马就去处理,而是等合适的时间去处理,那么在这段时间内,进程就需要保存信号,到了合适时间再去执行!
The sky
2023/10/17
2200
【linux】信号的保存和递达处理
一文搞懂Linux信号【下】
在观看本博客之前,建议大家先看一文搞懂Linux信号【上】。由于上一篇博客篇幅太长,为了更好的阅读体验,我拆成了两篇博客。那么接下来,在上一篇的基础上,我们继续学习Linux信号部分。本篇我们主要谈论信号保存和信号处理。
破晓的历程
2024/06/24
1530
一文搞懂Linux信号【下】
Linux信号
在生活中也有诸多信号,这些信号通常不是由我们发起的,而是我们接收以后对对应的信号做处理;最常见的莫过于红绿灯了,当红绿灯发出信号时(红灯,绿灯,黄灯);我们会有对应的行为,比如绿灯我们知道当前可以行走,红灯的时候我们需要等一等。对信号产生以后我们知道该做什么,这是因为我们曾经接受了对于这些信号的教育,知道当这些信号产生以后我们需要做什么。
始终学不会
2023/10/17
4410
Linux信号
【Linux】进程信号——信号保存和信号捕捉
信号递达:指 操作系统 将一个信号(Signal)从内核传递到目标进程 的过程。它是 信号处理机制 中的关键步骤。 信号未决:信号从产生到递达之间的状态 信号阻塞 进程或线程可以暂时屏蔽某些信号,使它们在阻塞期间不会递达和处理。一旦解除阻塞,信号会被递达并处理。
用户11305458
2025/03/05
3820
【Linux】进程信号——信号保存和信号捕捉
Linux进程信号总结
不难看出上面的死循环在代码层面是永远无法结束程序的,那是否还有别的办法?对于死循环来说,最好的方式就是使用Ctrl+C对其进行终止。
咬咬
2024/07/20
1290
Linux进程信号总结
linux系统编程之信号(三):信号的阻塞与未决
一、信号在内核中的表示 实际执行信号的处理动作称为信号递达(Delivery),信号从产生到递达之间的状态,称为信号未决(Pending)。进程可以选择阻塞(Block)某个信号,SIGKILL 和
s1mba
2017/12/28
2.3K0
linux系统编程之信号(三):信号的阻塞与未决
【Linux】进程信号(中)
为什么除0就报错了呢? 当代码除0时,程序运行后就崩溃了,程序运行变为进程,进程运行代码时出现了非法代码,进程退出了
lovevivi
2023/10/16
3370
【Linux】进程信号(中)
Linux系统-进程信号
注:阻塞和忽略是不同的,只要信号被阻塞就不会递达,而忽略是在递达之后可选的一种处理动作
用户9645905
2022/11/15
3.6K0
Linux系统-进程信号
【进程信号】五、信号集操作接口详解
​ 还记得我们上面讲过的 sigset_t 类型吗,sigset_t 类型对于每种信号用一个 bit 表示 “有效” 或 “无效” 状态,至于这个类型内部如何存储这些 bit 则依赖于系统实现,从使用者的角度是不必关心的,因为不同的操作系统可能对 sigset_t 变量的定义不一样,有的可能是变量,有的可能是数组,有的可能是封装在结构体内等等。
利刃大大
2025/04/20
860
【进程信号】五、信号集操作接口详解
Linux进程信号(产生、保存、处理)/可重入函数概念/volatile理解/SIGCHLD信号
首先区分一下Linux信号跟进程间通信中的信号量,它们的关系就犹如老婆跟老婆饼一样,没有一毛钱的关系。
二肥是只大懒蓝猫
2023/03/30
1.4K0
Linux进程信号(产生、保存、处理)/可重入函数概念/volatile理解/SIGCHLD信号
进程信号
kill命令是调用kill函数实现的。kill函数可以给一个指定的进程发送指定的信号。raise函数可以给当前进程发送指定的信号(自己给自己发信号)。
ljw695
2024/11/21
1210
进程信号
相关推荐
初识Linux · 信号保存
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验