数据分析——房源分析项目

导入模块

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib as mpl
%matplotlib inline
import seaborn as sns
from IPython.display import display
plt.style.use("fivethirtyeight")
sns.set_style({'font.sans-serif':['simhei','Arial']})

ps:数据已上传至 github 请点击下载


数据规整

lf_df = pd.read_csv('./lianjia.csv')
lf_df.head()
DirectionDistrictElevatorFloorGardenIdLayoutPriceRegionRenovationSizeYear
0东西灯市口NaN6锡拉胡同21号院1011026470433室1厅780.0东城精装75.01988
1南北东单无电梯6东华门大街1011026509782室1厅705.0东城精装60.01988
2南西崇文门有电梯16新世界中心1011026727433室1厅1400.0东城其他210.01996
3崇文门NaN7兴隆都市馨园1011025774101室1厅420.0东城精装39.02004
4陶然亭有电梯19中海紫御公馆1011025746962室2厅998.0东城精装90.02010
# 获取所有数据列信息
lf_df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 23677 entries, 0 to 23676
Data columns (total 12 columns):
Direction     23677 non-null object
District      23677 non-null object
Elevator      15440 non-null object
Floor         23677 non-null int64
Garden        23677 non-null object
Id            23677 non-null int64
Layout        23677 non-null object
Price         23677 non-null float64
Region        23677 non-null object
Renovation    23677 non-null object
Size          23677 non-null float64
Year          23677 non-null int64
dtypes: float64(2), int64(3), object(7)
memory usage: 2.2+ MB
# 拷贝一份数据,不对原始数据 进行 修改
df = lf_df.copy()
df.head()
DirectionDistrictElevatorFloorGardenIdLayoutPriceRegionRenovationSizeYear
0东西灯市口NaN6锡拉胡同21号院1011026470433室1厅780.0东城精装75.01988
1南北东单无电梯6东华门大街1011026509782室1厅705.0东城精装60.01988
2南西崇文门有电梯16新世界中心1011026727433室1厅1400.0东城其他210.01996
3崇文门NaN7兴隆都市馨园1011025774101室1厅420.0东城精装39.02004
4陶然亭有电梯19中海紫御公馆1011025746962室2厅998.0东城精装90.02010
# 计算 每一平米的价格
# 总价 / 总面积
df['PerPrice'] = df['Price'] / df['Size']
df.head()
DirectionDistrictElevatorFloorGardenIdLayoutPriceRegionRenovationSizeYearPerPrice
0东西灯市口NaN6锡拉胡同21号院1011026470433室1厅780.0东城精装75.0198810.400000
1南北东单无电梯6东华门大街1011026509782室1厅705.0东城精装60.0198811.750000
2南西崇文门有电梯16新世界中心1011026727433室1厅1400.0东城其他210.019966.666667
3崇文门NaN7兴隆都市馨园1011025774101室1厅420.0东城精装39.0200410.769231
4陶然亭有电梯19中海紫御公馆1011025746962室2厅998.0东城精装90.0201011.088889
# 重新摆放列的位置
columns = ['Region','District','Garden','Layout','Floor','Year','Size',
           'Elevator','Direction','PerPrice','Price']
# 第一种方法
df.loc[:,columns]
# 第二种方法
df = pd.DataFrame(df,columns=columns)
display(df.head(2))
RegionDistrictGardenLayoutFloorYearSizeElevatorDirectionPerPricePrice
0东城灯市口锡拉胡同21号院3室1厅6198875.0NaN东西10.40780.0
1东城东单东华门大街2室1厅6198860.0无电梯南北11.75705.0

数据分析

地区特征分析

对二手房区域分组,对比各个地区二手房数量和每平米房价
各个地区二手房数量
# count()统计数量,
# sort_values(ascending=True)升序排列
# to_frame()将series转换为dataframe
df_house_count = df.groupby('Region')['Size']\
.count()\
.sort_values(ascending=True)\
.to_frame()
# 修改列名称
df_house_count = df_house_count.reset_index()\
.rename({'Region':'地区','Size':'数量'},axis=1)\
.set_index('地区')
df_house_count
数量
地区
密云12
怀柔15
平谷41
亦庄开发区469
门头沟496
石景山882
顺义1221
房山1442
东城1533
通州1602
大兴2115
西城2130
昌平2811
丰台2952
朝阳2973
海淀2983

各地区 每平米房价对比

df_mean_house = df.groupby('Region')['PerPrice'].mean()\
.to_frame().reset_index()\
.rename({'Region':'地区','PerPrice':'每平米房价'},axis=1)\
.set_index('地区')
df_mean_house
每平米房价
地区
东城9.864243
丰台6.098628
亦庄开发区4.696853
大兴5.414790
密云2.392645
平谷2.749869
怀柔3.934458
房山3.948686
昌平4.402832
朝阳7.317792
海淀8.847025
石景山5.535677
西城10.688348
通州5.240839
门头沟4.017825
顺义4.974990

各地区房价和数量信息可视化

fig = plt.figure(figsize=(12,9))
ax1 = fig.add_subplot(5,1,1)
sns.barplot(x = df_mean_house.index,
            y = '每平米房价',
            palette = 'Blues_d',
            data = df_mean_house,
            ax = ax1)
# 修改 x轴的字体大小
ax1.set_xlabel('地区',{'size':14})
# 修改 y轴的字体大小
ax1.set_ylabel('每平方米房价',{'size':14})
# 设置刻度字体大小
ax1.tick_params(labelsize=10)
# 设置子图的标题
_ = ax1.set_title('北京各地区二手房每平米单价对比',fontsize=14)
# 第二个子图
ax2 = fig.add_subplot(5,1,3)

sns.barplot(x=df_house_count.index,
            y=df_house_count['数量'],
            data = df_house_count,
            palette='Greens_d',
            ax=ax2,
           )
# 修改 x轴的字体大小
ax2.set_xlabel('地区',{'size':14})
# 修改 y轴的字体大小
ax2.set_ylabel('数量',{'size':14})
# 设置刻度字体大小
ax2.tick_params(labelsize=10)
# 设置子图的标题
_ = ax2.set_title('北京各地区二手房数量',fontsize=14)

# 第三个子图,箱型图
ax3 = fig.add_subplot(5,1,5)
sns.boxplot(x='Region',y='Price',data=df,ax=ax3)
_ = ax3.set_title("北京各大区二手房房屋总价",fontsize=14)
ax3.set_xlabel("区域")
_ = ax.set_ylabel("房屋总价")

房屋面积特征分析

fig = plt.figure(figsize=(15,9))
ax1 = fig.add_subplot(1,2,1)
# 画出直方图,查看房屋面积特征分布
sns.distplot(df['Size'],bins=100,ax=ax1,color='r',kde=True)
ax2 = fig.add_subplot(1,2,2)
# 房屋面积和价格的关系
sns.regplot(x='Size',y='Price',data=df,ax=ax2)

size分布

通过 distplot绘制的柱状图观察size特征的分布情况,属于长尾类型的分布
所谓的长尾分布,就是说明有一些面积很大超出正差范围的二手房

Size和Price的关系

通过 regplot绘制的线性图,发现Size特征基本于Price呈线性关系。
符合常识,面积越大,价格越高。
但是有两组明显的异常点:

  1. 面积很小,不到10平米,但价格却贵的离谱
  2. 有一个面积超过了1000平米,价格却特别低
# 筛选出面积小于10平米所有的房屋
condition = df['Size'] < 10
df[condition]
RegionDistrictGardenLayoutFloorYearSizeElevatorDirectionPerPricePrice
1168房山长阳世茂维拉叠拼别墅520155.0毛坯240.97平米216.0000001080.0
1458房山长阳世茂维拉叠拼别墅520155.0毛坯242.78平米220.0000001100.0
1797房山长阳世茂维拉叠拼别墅520155.0精装242.96平米196.000000980.0
2268顺义顺义其它龙湖好望山叠拼别墅420144.0精装295.88平米250.0000001000.0
2274顺义顺义其它鹭峯国际叠拼别墅420145.0精装295.01平米290.0000001450.0
2276顺义顺义其它龙湖好望山叠拼别墅320144.0毛坯292.31平米215.000000860.0
2432顺义顺义其它龙湖好望山叠拼别墅520136.0精装294.42平米163.333333980.0
4078大兴西红门鸿坤林语墅叠拼别墅320154.0精装427.5平米787.5000003150.0
4079大兴西红门鸿坤林语墅叠拼别墅420154.0精装361.8平米595.0000002380.0
4761大兴西红门鸿坤林语墅叠拼别墅320155.0精装386.83平米540.0000002700.0
7533昌平回龙观龙城花园N区叠拼别墅419972.0简装107.93平米310.000000620.0
8765通州通州其它旭辉御锦叠拼别墅620145.0毛坯195.32平米156.000000780.0
9020通州通州其它旭辉御锦叠拼别墅620144.0精装259.87平米280.0000001120.0
9080通州通州其它旭辉御锦叠拼别墅620144.0毛坯259.76平米262.5000001050.0
9203通州通州其它旭辉御锦叠拼别墅620144.0精装260.07平米262.5000001050.0
9254通州通州其它旭辉御锦叠拼别墅620144.0毛坯264.6平米275.0000001100.0
11531丰台丽泽西宸原著叠拼别墅620164.0毛坯335.51平米1000.0000004000.0
14298海淀西山中间建筑一区叠拼别墅320078.0精装266.61平米168.7500001350.0
15334海淀西山西山美墅馆F区叠拼别墅420044.0简装203.73平米550.0000002200.0
17311朝阳大望路首府官邸叠拼别墅520075.0精装523.4平米900.0000004500.0

所有面积小于10的数据全部都是别墅,数据出现异常的原因是由于别墅的结构
比较特殊,字段定义与二手商品放不太一样导致爬虫爬取数据错位。
将这些别墅房移除。

# 筛选出面积大于1000的房屋
condition = df['Size']>1000
df[condition]
RegionDistrictGardenLayoutFloorYearSizeElevatorDirectionPerPricePrice
8754通州通州其它新华联科技大厦1房间0卫820091019.0有电梯1.6683021700.0

结果发现,房屋面积大于1000的不是普通的民用房屋
而是商业用房,这个也需要移除

condition = (df['Layout'] != '叠拼别墅') & ( df['Size'] <1000)
df = df[condition]

重新可视化后,就没异常数据了

fig = plt.figure(figsize=(15,9))
ax1 = fig.add_subplot(1,2,1)
# 画出直方图,查看房屋面积特征分布
sns.distplot(df['Size'],bins=100,ax=ax1,color='r',kde=True)
ax2 = fig.add_subplot(1,2,2)
# 房屋面积和价格的关系
sns.regplot(x='Size',y='Price',data=df,ax=ax2)

户型特征分析

plt.figure(figsize=(15,15))
sns.countplot(y='Layout',data=df)
_ = plt.title('房屋户型',fontsize=15)
plt.xlabel('数量')
plt.ylabel('户型')
plt.show()

# 找出户型特征最多的五个
df['Layout'].value_counts().sort_values(ascending=False).head()
2室1厅    9485
3室1厅    3999
3室2厅    2765
1室1厅    2681
2室2厅    1671
Name: Layout, dtype: int64

户型特征的厅室搭配花样太多了,各种奇怪的结构,需要进行特征处理

可以看出,最多的是二室一厅

现在假设,两室一厅、三室两厅为精装房

三室一厅、二室二厅为简装房

一室0厅、二室0厅为毛胚房

剩余的划分为 其它

# 条件
map_dict = {
    '2室1厅':'精装房',
    '2室2厅':'简装房',
    '3室1厅':'简装房',
    '1室0厅':'毛胚房',
    '2室0厅':'毛胚房',
    '3室1厅':'精装房',
}
# 增加一列,作为户型类别
df.loc[:,'Renovation'] = df.Layout.map(map_dict)
df.loc[:,'Renovation']=df['Renovation'].fillna('其它')
df.head()
RegionDistrictGardenLayoutFloorYearSizeElevatorDirectionPerPricePriceRenovation
0东城灯市口锡拉胡同21号院3室1厅6198875.0NaN东西10.400000780.0精装房
1东城东单东华门大街2室1厅6198860.0无电梯南北11.750000705.0精装房
2东城崇文门新世界中心3室1厅161996210.0有电梯南西6.6666671400.0精装房
3东城崇文门兴隆都市馨园1室1厅7200439.0NaN10.769231420.0其它
4东城陶然亭中海紫御公馆2室2厅19201090.0有电梯11.088889998.0简装房

对 Renovation 特征分析

df['Renovation'].value_counts()
精装房    13484
其它      7952
简装房     1671
毛胚房      549
Name: Renovation, dtype: int64
fig = plt.figure(figsize=(20,5))
ax1 = fig.add_subplot(1,3,1)
# 统计各类房的数量
sns.countplot(df['Renovation'],ax=ax1)

# 柱状图
ax2 = fig.add_subplot(1,3,2)
# 使用的是平均值
sns.barplot(x='Renovation',y='Price',data=df,ax=ax2)
# 箱型图
ax3 = fig.add_subplot(1,3,3)
sns.boxplot(x='Renovation',y='Price',data=df,ax=ax3)

电梯特征分析

之前的处理阶段,我们能发现,Elevator特征是存在着大量的缺失值
所以需要进行一些处理

# 查看缺失值数量
condition = df['Elevator'].isnull()
len(df[condition])
8237

常见的处理缺失值方法有:平均数、中位数填补/删除缺失值

拉格朗日中值法等等,但是有无电梯并不是具体的数据。根本不存在平均数、中位数这一说

可以换一种思路,当楼层大于等于6层就要有电梯,小于六层就没有

df.head()
RegionDistrictGardenLayoutFloorYearSizeElevatorDirectionPerPricePriceRenovation
0东城灯市口锡拉胡同21号院3室1厅6198875.0NaN东西10.400000780.0精装房
1东城东单东华门大街2室1厅6198860.0无电梯南北11.750000705.0精装房
2东城崇文门新世界中心3室1厅161996210.0有电梯南西6.6666671400.0精装房
3东城崇文门兴隆都市馨园1室1厅7200439.0NaN10.769231420.0其它
4东城陶然亭中海紫御公馆2室2厅19201090.0有电梯11.088889998.0简装房
def ModifyElevator(x):
    # 由于 np.nan为flaot对象
    if isinstance(x['Elevator'],float):
        if x.Floor >6:
            return '有电梯'
        else:
            return '无电梯'
    return x['Elevator']
df['Elevator']= df.apply(ModifyElevator,axis=1)

电梯特征可视化

fig = plt.figure(figsize=(20,10))
ax1 = fig.add_subplot(1,2,1)
sns.countplot(x='Elevator',data=df,ax=ax1)
ax2 = fig.add_subplot(1,2,2)
sns.barplot(x='Elevator',y='Price',data=df,ax=ax2)

年份特征分析

grid = sns.FacetGrid(
            df,
            row='Elevator',
            col='Renovation',
            palette='seismic',aspect=2)
grid.map(plt.scatter,'Year','Price')
grid.add_legend()

整个二手房房价趋势是随着时间增长而增长的

毛胚房的价格稳定

简装房主要是在 1980年之后

1980年之前几乎不存在电梯二手房数据,说明1980年之前还没有大面积安装电梯

楼层特征分析

fig = plt.figure(figsize=(12,9))
ax1 = fig.add_subplot(1,1,1)
sns.countplot(x='Floor',data=df,ax=ax1)
_ = ax1.set_xlabel('楼层',fontsize=20)
_ =ax1.set_ylabel('数量',fontsize=20)

可以看到,6层二手房数量最多,但是单独的楼层特征没有什么意义,因为每个小区

住房的总楼层都一样,我们需要知道楼层的相对意义。

此外,楼层与文化也紧密联系在一次,中国人喜欢6不喜欢4

喜欢七层不喜欢八层,也不喜欢十八层

这些复杂的条件结合起来,就使得楼层变成一个非常复杂的特征。

特征工程

特征工程包括的内容很多,有特征的清洗,预处理、监控等,而预处理根据单一特征

或多特征又分很多种方法,如归一化、降维,特征选择,特征筛选等等。

这么多方法,为的是什么呢?其目的就是让这些特征更友好的作为模型输入

处理数据的好坏会严重影响模型的性能,而好的特征工程有的时候甚至比建模调参更重要

之前我们处理一些数据,就是我们常说的特征工程,如下几个例子:

'''
    特征工程
'''

# 1. 移除结构类型异常值和房屋大小异常值
# condition = (df['Layout'] != '叠拼别墅') & ( df['Size'] <1000)
# df = df[condition]

# 2. 填补 Elevator缺失值
# def ModifyElevator(x):
#     # 由于 np.nan为flaot对象
#     if isinstance(x['Elevator'],float):
#         if x.Floor >6:
#             return '有电梯'
#         else:
#             return '无电梯'
#     return x['Elevator']
# df['Elevator']= df.apply(ModifyElevator,axis=1)

# 3. 只考虑 “室” 和 “厅”,将其它少数“房间” 和 “卫” 移除
# 3室1厅
df = df[(df['Layout']\
         .str.extract('^\d(.*?)\d.*?') == '室')[0]]
df.head()
RegionDistrictGardenLayoutFloorYearSizeElevatorDirectionPerPricePriceRenovation
0东城灯市口锡拉胡同21号院3室1厅6198875.0无电梯东西10.400000780.0精装房
1东城东单东华门大街2室1厅6198860.0无电梯南北11.750000705.0精装房
2东城崇文门新世界中心3室1厅161996210.0有电梯南西6.6666671400.0精装房
3东城崇文门兴隆都市馨园1室1厅7200439.0有电梯10.769231420.0其它
4东城陶然亭中海紫御公馆2室2厅19201090.0有电梯11.088889998.0简装房
# 4. 提取 “室” 和 “厅”创建新特征
df.loc[:,'Layout_roomNum'] = df['Layout'].str.extract(r'(\d)室')[0]
df.loc[:,'Layout_hallNum'] = df['Layout'].str.extract(r'\d.*(\d).*')[0]
df.head()
RegionDistrictGardenLayoutFloorYearSizeElevatorDirectionPerPricePriceRenovationLayout_roomNumLayout_hallNum
0东城灯市口锡拉胡同21号院3室1厅6198875.0无电梯东西10.400000780.0精装房31
1东城东单东华门大街2室1厅6198860.0无电梯南北11.750000705.0精装房21
2东城崇文门新世界中心3室1厅161996210.0有电梯南西6.6666671400.0精装房31
3东城崇文门兴隆都市馨园1室1厅7200439.0有电梯10.769231420.0其它11
4东城陶然亭中海紫御公馆2室2厅19201090.0有电梯11.088889998.0简装房22
# 5. 根据已有特征创造新特征

df.loc[:,'Layout_total_num'] = df['Layout_roomNum'].astype(np.int16) + \
    df['Layout_hallNum'].astype(np.int16)
df.head()
RegionDistrictGardenLayoutFloorYearSizeElevatorDirectionPerPricePriceRenovationLayout_roomNumLayout_hallNumLayout_total_num
0东城灯市口锡拉胡同21号院3室1厅6198875.0无电梯东西10.400000780.0精装房314
1东城东单东华门大街2室1厅6198860.0无电梯南北11.750000705.0精装房213
2东城崇文门新世界中心3室1厅161996210.0有电梯南西6.6666671400.0精装房314
3东城崇文门兴隆都市馨园1室1厅7200439.0有电梯10.769231420.0其它112
4东城陶然亭中海紫御公馆2室2厅19201090.0有电梯11.088889998.0简装房224
# 6. 按中位数对 “year” 特征进行分箱
df.loc[:,'Year'] = pd.qcut(df['Year'],q=8,precision=0)
df.head()
RegionDistrictGardenLayoutFloorYearSizeElevatorDirectionPerPricePriceRenovationLayout_roomNumLayout_hallNumLayout_total_num
0东城灯市口锡拉胡同21号院3室1厅6(1949.0, 1990.0]75.0无电梯东西10.400000780.0精装房314
1东城东单东华门大街2室1厅6(1949.0, 1990.0]60.0无电梯南北11.750000705.0精装房213
2东城崇文门新世界中心3室1厅16(1990.0, 1997.0]210.0有电梯南西6.6666671400.0精装房314
3东城崇文门兴隆都市馨园1室1厅7(2003.0, 2004.0]39.0有电梯10.769231420.0其它112
4东城陶然亭中海紫御公馆2室2厅19(2007.0, 2010.0]90.0有电梯11.088889998.0简装房224
# 7. 删除无用特征
df.drop(['Garden','PerPrice'],axis=1,inplace=True)
df.head()
RegionDistrictLayoutFloorYearSizeElevatorDirectionPriceRenovationLayout_roomNumLayout_hallNumLayout_total_num
0东城灯市口3室1厅6(1949.0, 1990.0]75.0无电梯东西780.0精装房314
1东城东单2室1厅6(1949.0, 1990.0]60.0无电梯南北705.0精装房213
2东城崇文门3室1厅16(1990.0, 1997.0]210.0有电梯南西1400.0精装房314
3东城崇文门1室1厅7(2003.0, 2004.0]39.0有电梯420.0其它112
4东城陶然亭2室2厅19(2007.0, 2010.0]90.0有电梯998.0简装房224

end …

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

aa.1735803

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值