房源数据分析
将租房网站租房数据作为参考,分析统计如下指标:
统计每个区域的房源总数量,并使用热力图分析房源位置分布情况。 使用条形图分析哪种户型的数量最多、更受欢迎。 统计每个区域的平均租金,并结合柱状图和折线图分析各区域的房源数量和租金情况。 统计面积区间的市场占有率,并使用饼图绘制各区间所占的比例。
导入需要包
import matplotlib. pyplot as plt
import numpy as np
import pandas as pd
import seaborn as sns
file_data = pd. read_csv( './data/房源数据.csv' )
file_data
区域 小区名称 户型 面积(㎡) 价格(元/月) 0 东城 万国城MOMA 1室0厅 59.11平米 10000 1 东城 北官厅胡同2号院 3室0厅 56.92平米 6000 2 东城 和平里三区 1室1厅 40.57平米 6900 3 东城 菊儿胡同 2室1厅 57.09平米 8000 4 东城 交道口北二条35号院 1室1厅 42.67平米 5500 ... ... ... ... ... ... 8218 顺义 怡馨家园 3室1厅 114.03平米 5500 8219 顺义 旭辉26街区 4房间2卫 59平米 5000 8220 顺义 前进花园玉兰苑 3室1厅 92.41平米 5800 8221 顺义 双裕小区 2室1厅 71.81平米 4200 8222 顺义 樱花园二区 1室1厅 35.43平米 2700
8223 rows × 5 columns
数据基本信息
file_data. shape
(8223, 5)
file_data. info( )
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 8223 entries, 0 to 8222
Data columns (total 5 columns):# Column Non-Null Count Dtype
--- ------ -------------- ----- 0 区域 8223 non-null object1 小区名称 8223 non-null object2 户型 8223 non-null object3 面积(㎡) 8223 non-null object4 价格(元/月) 8223 non-null int64
dtypes: int64(1), object(4)
memory usage: 321.3+ KB
file_data. describe( )
价格(元/月) count 8223.000000 mean 9512.297823 std 9186.752612 min 566.000000 25% 4800.000000 50% 6800.000000 75% 10000.000000 max 150000.000000
数据预处理
滤重
file_data. duplicated( )
0 False
1 False
2 False
3 False
4 False...
8218 False
8219 False
8220 False
8221 False
8222 False
Length: 8223, dtype: bool
file_data = file_data. drop_duplicates( )
file_data
区域 小区名称 户型 面积(㎡) 价格(元/月) 0 东城 万国城MOMA 1室0厅 59.11平米 10000 1 东城 北官厅胡同2号院 3室0厅 56.92平米 6000 2 东城 和平里三区 1室1厅 40.57平米 6900 3 东城 菊儿胡同 2室1厅 57.09平米 8000 4 东城 交道口北二条35号院 1室1厅 42.67平米 5500 ... ... ... ... ... ... 8218 顺义 怡馨家园 3室1厅 114.03平米 5500 8219 顺义 旭辉26街区 4房间2卫 59平米 5000 8220 顺义 前进花园玉兰苑 3室1厅 92.41平米 5800 8221 顺义 双裕小区 2室1厅 71.81平米 4200 8222 顺义 樱花园二区 1室1厅 35.43平米 2700
5773 rows × 5 columns
file_data. shape
(5773, 5)
处理空值
file_data = file_data. dropna( )
file_data. shape
(5773, 5)
滤重及处理空值后shape一致,说明没有空值
数据类型转换
面积转化为float
file_data[ "面积(㎡)" ] . values
array(['59.11平米', '56.92平米', '40.57平米', ..., '92.41平米', '71.81平米','35.43平米'], dtype=object)
data_new = np. array( [ ] ) area = file_data[ "面积(㎡)" ] . valuesfor i in area: data_new = np. append( data_new, np. array( i[ : - 2 ] ) )
data_new
array(['59.11', '56.92', '40.57', ..., '92.41', '71.81', '35.43'],dtype='<U32')
data_new = data_new. astype( np. float64)
file_data. loc[ : , "面积(㎡)" ] = data_new
file_data
区域 小区名称 户型 面积(㎡) 价格(元/月) 0 东城 万国城MOMA 1室0厅 59.11 10000 1 东城 北官厅胡同2号院 3室0厅 56.92 6000 2 东城 和平里三区 1室1厅 40.57 6900 3 东城 菊儿胡同 2室1厅 57.09 8000 4 东城 交道口北二条35号院 1室1厅 42.67 5500 ... ... ... ... ... ... 8218 顺义 怡馨家园 3室1厅 114.03 5500 8219 顺义 旭辉26街区 4房间2卫 59.00 5000 8220 顺义 前进花园玉兰苑 3室1厅 92.41 5800 8221 顺义 双裕小区 2室1厅 71.81 4200 8222 顺义 樱花园二区 1室1厅 35.43 2700
5773 rows × 5 columns
替换户型
house_data = file_data[ "户型" ]
house_data
0 1室0厅
1 3室0厅
2 1室1厅
3 2室1厅
4 1室1厅...
8218 3室1厅
8219 4房间2卫
8220 3室1厅
8221 2室1厅
8222 1室1厅
Name: 户型, Length: 5773, dtype: object
house_new = [ ]
for i in house_data:
new_info = i. replace( "房间" , "室" ) house_new. append( new_info) file_data. loc[ : , "户型" ] = house_new
file_data
区域 小区名称 户型 面积(㎡) 价格(元/月) 0 东城 万国城MOMA 1室0厅 59.11 10000 1 东城 北官厅胡同2号院 3室0厅 56.92 6000 2 东城 和平里三区 1室1厅 40.57 6900 3 东城 菊儿胡同 2室1厅 57.09 8000 4 东城 交道口北二条35号院 1室1厅 42.67 5500 ... ... ... ... ... ... 8218 顺义 怡馨家园 3室1厅 114.03 5500 8219 顺义 旭辉26街区 4室2卫 59.00 5000 8220 顺义 前进花园玉兰苑 3室1厅 92.41 5800 8221 顺义 双裕小区 2室1厅 71.81 4200 8222 顺义 樱花园二区 1室1厅 35.43 2700
5773 rows × 5 columns
图表分析
房源数量、位置分布分析
file_data[ "区域" ] . unique( )
array(['东城', '丰台', '亦庄开发区', '大兴', '房山', '昌平', '朝阳', '海淀', '石景山', '西城','通州', '门头沟', '顺义'], dtype=object)
new_df = pd. DataFrame( { "区域" : file_data[ "区域" ] . unique( ) , "数量" : [ 0 ] * 13 } )
new_df
区域 数量 0 东城 0 1 丰台 0 2 亦庄开发区 0 3 大兴 0 4 房山 0 5 昌平 0 6 朝阳 0 7 海淀 0 8 石景山 0 9 西城 0 10 通州 0 11 门头沟 0 12 顺义 0
area_count = file_data. groupby( by= "区域" ) . count( )
area_count
小区名称 户型 面积(㎡) 价格(元/月) 区域 东城 282 282 282 282 丰台 577 577 577 577 亦庄开发区 147 147 147 147 大兴 362 362 362 362 房山 180 180 180 180 昌平 347 347 347 347 朝阳 1597 1597 1597 1597 海淀 605 605 605 605 石景山 175 175 175 175 西城 442 442 442 442 通州 477 477 477 477 门头沟 285 285 285 285 顺义 297 297 297 297
new_df[ "数量" ] = area_count. values
new_df
区域 数量 0 东城 282 1 丰台 577 2 亦庄开发区 147 3 大兴 362 4 房山 180 5 昌平 347 6 朝阳 1597 7 海淀 605 8 石景山 175 9 西城 442 10 通州 477 11 门头沟 285 12 顺义 297
new_df. sort_values( by= "数量" , ascending= False )
区域 数量 6 朝阳 1597 7 海淀 605 1 丰台 577 10 通州 477 9 西城 442 3 大兴 362 5 昌平 347 12 顺义 297 11 门头沟 285 0 东城 282 4 房山 180 8 石景山 175 2 亦庄开发区 147
户型数量分析
统计市场中哪种户型的房源数量偏多,并筛选出数量大于50的户型
file_data
区域 小区名称 户型 面积(㎡) 价格(元/月) 0 东城 万国城MOMA 1室0厅 59.11 10000 1 东城 北官厅胡同2号院 3室0厅 56.92 6000 2 东城 和平里三区 1室1厅 40.57 6900 3 东城 菊儿胡同 2室1厅 57.09 8000 4 东城 交道口北二条35号院 1室1厅 42.67 5500 ... ... ... ... ... ... 8218 顺义 怡馨家园 3室1厅 114.03 5500 8219 顺义 旭辉26街区 4室2卫 59.00 5000 8220 顺义 前进花园玉兰苑 3室1厅 92.41 5800 8221 顺义 双裕小区 2室1厅 71.81 4200 8222 顺义 樱花园二区 1室1厅 35.43 2700
5773 rows × 5 columns
file_data. groupby( by= "户型" ) . count( ) . sort_values( by= "区域" , ascending= False ) . head( )
区域 小区名称 面积(㎡) 价格(元/月) 户型 2室1厅 2249 2249 2249 2249 1室1厅 844 844 844 844 3室1厅 766 766 766 766 3室2厅 489 489 489 489 2室2厅 265 265 265 265
groupby_house = file_data. groupby( by= "户型" ) . count( ) . sort_values( by= "区域" , ascending= False ) [ "区域" ]
groupby_house = groupby_house[ groupby_house > 50 ]
groupby_house
户型
2室1厅 2249
1室1厅 844
3室1厅 766
3室2厅 489
2室2厅 265
1室0厅 244
4室2厅 191
1室1卫 126
2室1卫 120
3室1卫 92
4室1厅 58
Name: 区域, dtype: int64
groupby_house. shape
(11,)
groupby_house. index
Index(['2室1厅', '1室1厅', '3室1厅', '3室2厅', '2室2厅', '1室0厅', '4室2厅', '1室1卫', '2室1卫','3室1卫', '4室1厅'],dtype='object', name='户型')
groupby_house. values
array([2249, 844, 766, 489, 265, 244, 191, 126, 120, 92, 58],dtype=int64)
house_size = groupby_house. index. sizeshow_houses = pd. DataFrame( { "户型" : [ groupby_house. index[ i] for i in range ( house_size) ] , "数量" : [ groupby_house. values[ i] for i in range ( house_size) ] } )
show_houses
户型 数量 0 2室1厅 2249 1 1室1厅 844 2 3室1厅 766 3 3室2厅 489 4 2室2厅 265 5 1室0厅 244 6 4室2厅 191 7 1室1卫 126 8 2室1卫 120 9 3室1卫 92 10 4室1厅 58
house_type = show_houses[ "户型" ]
house_type_num = show_houses[ "数量" ] plt. barh( range ( 11 ) , house_type_num) plt. yticks( range ( 11 ) , house_type)
plt. xlim( 0 , 2500 ) plt. title( "北京市各区域租房数量统计" )
plt. xlabel( "数量" )
plt. ylabel( "房屋类型" )
for x, y in enumerate ( house_type_num) : plt. text( y+ 0.5 , x- 0.2 , "%s" % y) plt. show( )
平均租金分析
分析各地区目前的平均租金情况
file_data
区域 小区名称 户型 面积(㎡) 价格(元/月) 0 东城 万国城MOMA 1室0厅 59.11 10000 1 东城 北官厅胡同2号院 3室0厅 56.92 6000 2 东城 和平里三区 1室1厅 40.57 6900 3 东城 菊儿胡同 2室1厅 57.09 8000 4 东城 交道口北二条35号院 1室1厅 42.67 5500 ... ... ... ... ... ... 8218 顺义 怡馨家园 3室1厅 114.03 5500 8219 顺义 旭辉26街区 4室2卫 59.00 5000 8220 顺义 前进花园玉兰苑 3室1厅 92.41 5800 8221 顺义 双裕小区 2室1厅 71.81 4200 8222 顺义 樱花园二区 1室1厅 35.43 2700
5773 rows × 5 columns
area_sum = file_data. groupby( by= "区域" ) . sum ( )
area_sum = area_sum. rename( columns= { '面积(㎡)' : '总面积' , '价格(元/月)' : '总金额' } )
area_sum
总面积 总金额 区域 东城 27353.99 3945550 丰台 50922.79 4404893 亦庄开发区 15995.53 1318400 大兴 35884.15 2286950 房山 15275.41 726750 昌平 35972.92 2521515 朝阳 166921.72 20281396 海淀 57210.39 7279350 石景山 13956.67 1156500 西城 37141.64 5636975 通州 46625.23 2719600 门头沟 20258.20 1048300 顺义 33668.97 2190900
area_sum[ "每平米租金(元)" ] = np. array( round ( area_sum[ "总金额" ] / area_sum[ "总面积" ] , 2 ) . values)
area_sum
总面积 总金额 每平米租金(元) 区域 东城 27353.99 3945550 144.24 丰台 50922.79 4404893 86.50 亦庄开发区 15995.53 1318400 82.42 大兴 35884.15 2286950 63.73 房山 15275.41 726750 47.58 昌平 35972.92 2521515 70.09 朝阳 166921.72 20281396 121.50 海淀 57210.39 7279350 127.24 石景山 13956.67 1156500 82.86 西城 37141.64 5636975 151.77 通州 46625.23 2719600 58.33 门头沟 20258.20 1048300 51.75 顺义 33668.97 2190900 65.07
之前创建的 new_df
对象(各区域房源数量)与area_sum
对象进行合并展示,由于这两个对象中都包含“区域”一列,所以这里可以采用主键的方式进行合并,也就是说通过 merge()函数来实现,具体代码如下。
area_sum = area_sum. reset_index( )
area_sum
区域 总面积 总金额 每平米租金(元) 0 东城 27353.99 3945550 144.24 1 丰台 50922.79 4404893 86.50 2 亦庄开发区 15995.53 1318400 82.42 3 大兴 35884.15 2286950 63.73 4 房山 15275.41 726750 47.58 5 昌平 35972.92 2521515 70.09 6 朝阳 166921.72 20281396 121.50 7 海淀 57210.39 7279350 127.24 8 石景山 13956.67 1156500 82.86 9 西城 37141.64 5636975 151.77 10 通州 46625.23 2719600 58.33 11 门头沟 20258.20 1048300 51.75 12 顺义 33668.97 2190900 65.07
df_merge = pd. merge( new_df, area_sum)
df_merge
区域 数量 总面积 总金额 每平米租金(元) 0 东城 282 27353.99 3945550 144.24 1 丰台 577 50922.79 4404893 86.50 2 亦庄开发区 147 15995.53 1318400 82.42 3 大兴 362 35884.15 2286950 63.73 4 房山 180 15275.41 726750 47.58 5 昌平 347 35972.92 2521515 70.09 6 朝阳 1597 166921.72 20281396 121.50 7 海淀 605 57210.39 7279350 127.24 8 石景山 175 13956.67 1156500 82.86 9 西城 442 37141.64 5636975 151.77 10 通州 477 46625.23 2719600 58.33 11 门头沟 285 20258.20 1048300 51.75 12 顺义 297 33668.97 2190900 65.07
num = df_merge[ "数量" ]
price = df_merge[ "每平米租金(元)" ]
lx = df_merge[ "区域" ]
l = [ i for i in range ( 13 ) ] fig = plt. figure( figsize= ( 10 , 8 ) , dpi= 100 )
ax1 = fig. add_subplot( 111 )
ax1. plot( l, price, "or-" , label= "价格" )
for i, ( _x, _y) in enumerate ( zip ( l, price) ) : plt. text( _x+ 0.2 , _y, price[ i] )
ax1. set_ylim( [ 0 , 160 ] )
ax1. set_ylabel( "价格" )
plt. legend( loc= "upper right" )
ax2 = ax1. twinx( )
plt. bar( l, num, label= "数量" , alpha= 0.2 , color= "green" )
ax2. set_ylabel( "数量" )
plt. legend( loc= "upper left" )
plt. xticks( l, lx) plt. show( )
从图中可以看出,西城区、东城区、海淀区、朝阳区的房租价格相对较高,这主要是因为东城区和西城区作为北京市的中心区,租金相比其他几个区域自然偏高一些,而海淀区租金较高的原因推测可能是海淀区名校较多,也是学区房最火热的地带,朝阳区内的中央商务区聚集了大量的世界500强公司,因此这四个区域的房租相对其他区域较高。
面积区间分析
下面我们将房屋的面积数据按照一定的规则划分成多个区间,看一下各面积区间的上情况,便于分析租房市场中哪种房屋类型更好出租,哪个面积区间的相房人数最多.
将数据划分为若干个区间,则可以使用Pame中的cut()函数来实现,首先,使用max()与min()方法分别计算出房屋面积的最大值和最小值,具体代码如下。
print ( '房屋最大面积是%d平米' % ( file_data[ '面积(㎡)' ] . max ( ) ) )
print ( '房屋最小面积是%d平米' % ( file_data[ '面积(㎡)' ] . min ( ) ) )
print ( '房租最高价格为每月%d元' % ( file_data[ '价格(元/月)' ] . max ( ) ) )
print ( '房屋最低价格为每月%d元' % ( file_data[ '价格(元/月)' ] . min ( ) ) )
房屋最大面积是1133平米
房屋最小面积是11平米
房租最高价格为每月150000元
房屋最低价格为每月566元
area_divide = [ 1 , 30 , 50 , 70 , 90 , 120 , 140 , 160 , 1200 ]
area_cut = pd. cut( list ( file_data[ "面积(㎡)" ] ) , area_divide)
area_cut
[(50, 70], (50, 70], (30, 50], (50, 70], (30, 50], ..., (90, 120], (50, 70], (90, 120], (70, 90], (30, 50]]
Length: 5773
Categories (8, interval[int64]): [(1, 30] < (30, 50] < (50, 70] < (70, 90] < (90, 120] < (120, 140] < (140, 160] < (160, 1200]]
area_cut_num = area_cut. describe( )
area_cut_num
counts freqs categories (1, 30] 41 0.007102 (30, 50] 710 0.122986 (50, 70] 1566 0.271263 (70, 90] 1094 0.189503 (90, 120] 1082 0.187424 (120, 140] 381 0.065997 (140, 160] 274 0.047462 (160, 1200] 625 0.108263
area_per = ( area_cut_num[ "freqs" ] . values) * 100 labels = [ '30平米以下' , '30-50平米' , '50-70平米' , '70-90平米' , '90-120平米' , '120-140平米' , '140-160平米' , '160平米以上' ] plt. figure( figsize= ( 20 , 8 ) , dpi= 100 )
plt. pie( x= area_per, labels= labels, autopct= "%.2f %%" ) plt. legend( )
plt. show( )