房价租金预测竞赛总结1:数据探索性分析

任务要求

比赛要求参赛选手根据给定的数据集,建立模型,预测房屋租金。
赛题连接:房价租金预测

数据概况

数据集中的数据类别包括租赁房源、小区、二手房、配套、新房、土地、人口、客户、真实租金等。

数据集字段说明

对于小区信息中,关于city、region、plate三者的关系:city>region>plate。
土地数据中,土地楼板面积是指在土地上建筑的房屋总面积。

评分指标

回归结果评价标准采用R-Square。
 score  = 1 − ∑ i = 1 m ( y ^ i − y i ) 2 ∑ i = 1 m ( y i − y ˉ ) 2 \text { score }=1-\frac{\sum_{i=1}^{m}\left(\widehat{y}_{i}-y_{i}\right)^{2}}{\sum_{i=1}^{m}\left(y_{i}-\bar{y}\right)^{2}}  score =1i=1m(yiyˉ)2i=1m(y iyi)2
其中, y i y_{i} yi表示真实值, y ^ i \widehat{y}_{i} y i表示预测值, y ˉ \bar{y} yˉ表示样本均值。得分越高拟合效果越好。
R 2 R^{2} R2用于度量因变量的变异中可由自变量解释部分所占的比例,取值范围是 0~1, R 2 R^{2} R2越接近1,表明回归平方和占总平方和的比例越大,回归线与各观测点越接近,用x的变化来解释y值变化的部分就越多,回归的拟合程度就越好。所以 R 2 R^{2} R2也称为拟合优度(Goodness of Fit)的统计量。

数据分析

导入数据分析所用的包

import warnings
warnings.filterwarnings('ignore')

import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns

总体情况

导入数据

# 载入数据
data_train = pd.read_csv('../data/train_data.csv')
data_train['Type'] = 'Train'
data_test = pd.read_csv('../data/test_a.csv')
data_test['Type'] = 'Test'
data_all = pd.concat([data_train, data_test], ignore_index=True)
# 总体情况一览
print(data_train.info())
print(data_train.describe())
print(data_train.head())

结果:

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 41440 entries, 0 to 41439
Data columns (total 52 columns):
ID                    41440 non-null int64
area                  41440 non-null float64
rentType              41440 non-null object
houseType             41440 non-null object
houseFloor            41440 non-null object
totalFloor            41440 non-null int64
houseToward           41440 non-null object
houseDecoration       41440 non-null object
communityName         41440 non-null object
city                  41440 non-null object
region                41440 non-null object
plate                 41440 non-null object
buildYear             41440 non-null object
saleSecHouseNum       41440 non-null int64
subwayStationNum      41440 non-null int64
busStationNum         41440 non-null int64
interSchoolNum        41440 non-null int64
schoolNum             41440 non-null int64
privateSchoolNum      41440 non-null int64
hospitalNum           41440 non-null int64
drugStoreNum          41440 non-null int64
gymNum                41440 non-null int64
bankNum               41440 non-null int64
shopNum               41440 non-null int64
parkNum               41440 non-null int64
mallNum               41440 non-null int64
superMarketNum        41440 non-null int64
totalTradeMoney       41440 non-null int64
totalTradeArea        41440 non-null float64
tradeMeanPrice        41440 non-null float64
tradeSecNum           41440 non-null int64
totalNewTradeMoney    41440 non-null int64
totalNewTradeArea     41440 non-null int64
tradeNewMeanPrice     41440 non-null float64
tradeNewNum           41440 non-null int64
remainNewNum          41440 non-null int64
supplyNewNum          41440 non-null int64
supplyLandNum         41440 non-null int64
supplyLandArea        41440 non-null float64
tradeLandNum          41440 non-null int64
tradeLandArea         41440 non-null float64
landTotalPrice        41440 non-null int64
landMeanPrice         41440 non-null float64
totalWorkers          41440 non-null int64
newWorkers            41440 non-null int64
residentPopulation    41440 non-null int64
pv                    41422 non-null float64
uv                    41422 non-null float64
lookNum               41440 non-null int64
tradeTime             41440 non-null object
tradeMoney            41440 non-null float64
Type                  41440 non-null object
dtypes: float64(10), int64(30), object(12)
memory usage: 16.4+ MB
None
                 ID          area  ...       lookNum    tradeMoney
count  4.144000e+04  41440.000000  ...  41440.000000  4.144000e+04
mean   1.001221e+08     70.959409  ...      0.396260  8.837074e+03
std    9.376566e+04     88.119569  ...      1.653932  5.514287e+05
min    1.000000e+08      1.000000  ...      0.000000  0.000000e+00
25%    1.000470e+08     42.607500  ...      0.000000  2.800000e+03
50%    1.000960e+08     65.000000  ...      0.000000  4.000000e+03
75%    1.001902e+08     90.000000  ...      0.000000  5.500000e+03
max    1.003218e+08  15055.000000  ...     37.000000  1.000000e+08

[8 rows x 40 columns]

ID    area rentType houseType  ... lookNum   tradeTime tradeMoney   Type
0  100309852   68.06     未知方式    211...       0  2018/11/28     2000.0  Train
1  100307942  125.55     未知方式    322...       1  2018/12/16     2000.0  Train
2  100307764  132.00     未知方式    322...       1  2018/12/22    16000.0  Train
3  100306518   57.00     未知方式    111...       9  2018/12/21     1600.0  Train
4  100305262  129.00     未知方式    323...       0  2018/11/18     2900.0  Train

[5 rows x 52 columns]

该数据集一共包括41400个样本,共有51个特征,其中50个特征是自变量变量,因变量是tradeMoeny。该问题属于典型的回归问题。
目标变量(因变量)是float型数据,自变量大多数数据都是int或float型;有部分字段是object型,即文本型中文或英文的,如rentType字段。

类别特征和数值特征

通过数据信息能够看出类别型特征一共有11个

categorical_feas = ['rentType','houseType','houseFloor','region','plate',
                    'houseToward','houseDecoration','communityName','city',
                    'buildYear','tradeTime']

连续型特征(包括因变量)一共有40个

numerical_feas=['ID','area','totalFloor','saleSecHouseNum','subwayStationNum',
    'busStationNum','interSchoolNum','schoolNum','privateSchoolNum','hospitalNum',
    'drugStoreNum','gymNum','bankNum','shopNum','parkNum','mallNum','superMarketNum',
    'totalTradeMoney','totalTradeArea','tradeMeanPrice','tradeSecNum','totalNewTradeMoney',
    'totalNewTradeArea','tradeNewMeanPrice','tradeNewNum','remainNewNum','supplyNewNum',
    'supplyLandNum','supplyLandArea','tradeLandNum','tradeLandArea','landTotalPrice',
    'landMeanPrice','totalWorkers','newWorkers','residentPopulation','pv','uv',
    'tradeMoney','lookNum']

缺失值分析

# 缺失值分析
def missing_values(df):
    alldata_na = pd.DataFrame(df.isnull().sum(),columns={'missingNum'})
    alldata_na['existNum'] = len(df) - alldata_na['missingNum']
    alldata_na['sum'] = len(df)
    alldata_na['missingRatio'] = alldata_na['missingNum']/len(df)
    alldata_na['dtype'] = df.dtypes
    # ascending:默认True升序排列,False降序排列
    alldata_na = alldata_na[alldata_na['missingNum']>0].reset_index().sort_values(by=['missingNum','index'],ascending=[False,True])
    alldata_na.set_index('index',inplace=True)
    return alldata_na

alldata_na = missing_values(data_train)

结果

       missingNum  existNum    sum  missingRatio    dtype
index                                                    
pv             18     41422  41440      0.000434  float64
uv             18     41422  41440      0.000434  float64

通过编写函数确定训练集中的那些特征存在缺失值,分别缺失了多少数据,缺失的比例有多大,以及这些缺失数据是否是随机缺失还是存在某种联系。
简要分析,在该训练集中,只有两个特征存在缺失值分别是’pv’和’uv’,并且分别缺失了18个数据,分别占总数据的0.043%,通过查看原始数据得知缺失的数据来自同一个小区。该后续的分析中可以考虑先剔除这两个特征或者剔除这18个样本,先进行分析。

单调特征列分析

# 单调特征列分析
def increasing(vals):
    cnt = 0
    len_ = len(vals)
    for i in range(len_-1):
        if vals[i+1] > vals[i]:
            cnt += 1
    return cnt

fea_cols = [col for col in data_train.columns]
for col in fea_cols:
    cnt = increasing(data_train[col].values)
    if cnt / data_train.shape[0] >= 0.55:
        print('单调特征:', col)
        print('单调特征值个数:', cnt)
        print('单调特征值比例:', cnt/data_train.shape[0])

结果

单调特征: tradeTime
单调特征值个数: 24085
单调特征值比例: 0.5812017374517374

通过编写函数确定存在单调递增的特征,即是否存在一列数据单调递增。

单调特征为什么采用这种判断方法,如果入局之间被随机打乱,那这种方式不就失败了吗?
结果显示,存在一个单调递增的特征:tradeTime,为时间列。
时间列在特征工程的时候,不同的情况下能有很多的变种形式,比如按年月日分箱,或者按不同的维度在时间上聚合分组,等等

特征unique分析

# 特征unique分布
print('特征unique分布')        
for feature in categorical_feas:
    print(feature + "的特征分布如下:")
    print(data_train[feature].value_counts())
    

结果

rentType的特征分布如下:
未知方式    30759
整租       5472
合租       5204
--          5
Name: rentType, dtype: int64
houseType的特征分布如下:
1119805
2118512
2216783
3113992
3222737
4111957


9251
3251
5451
7131
Name: houseType, Length: 104, dtype: int64
houseFloor的特征分布如下:
中    154581406611916
Name: houseFloor, dtype: int64
region的特征分布如下:
RG00002    11437
RG00005     5739
RG00003     4186
RG00010     3640
RG00012     3368
RG00004     3333
RG00006     1961
RG00007     1610
RG00008     1250
RG00013     1215
RG00001     1157
RG00014     1069
RG00011      793
RG00009      681
RG00015        1
Name: region, dtype: int64
plate的特征分布如下:
BK00031    1958
BK00033    1837
BK00045    1816
BK00055    1566
BK00056    1516

BK00044      98
BK00016      40
BK00036      33
BK00058      15
BK00032       3
BK00001       1
Name: plate, Length: 66, dtype: int64
houseToward的特征分布如下:
南       34377
南北       22542043
暂无数据      963
东南        655552
西         264
西南        250
西北         58
东西         24
Name: houseToward, dtype: int64
houseDecoration的特征分布如下:
其他    29040
精装    10918
简装     1171
毛坯      311
Name: houseDecoration, dtype: int64
communityName的特征分布如下:
XQ01834    358
XQ01274    192
XQ02273    188
XQ03110    185
XQ02337    173
XQ01389    166

XQ03838      1
XQ04064      1
XQ00112      1
XQ01385      1
XQ03573      1
XQ01911      1
Name: communityName, Length: 4236, dtype: int64
city的特征分布如下:
SH    41440
Name: city, dtype: int64
buildYear的特征分布如下:
1994    2851
暂无信息    2808
2006    2007
2007    1851
2008    1849
2005    1814
2010    1774

1961       2
1926       2
1951       1
1962       1
1950       1
Name: buildYear, Length: 80, dtype: int64
tradeTime的特征分布如下:
2018/3/3      543
2018/3/4      487
2018/3/11     410
2018/3/10     400
2018/3/24     341
2018/3/18     339

2018/1/4       14
2018/1/18      14
2018/1/2        5
2018/2/13       4
2018/2/20       2
2018/2/19       1
2018/2/17       1
Name: tradeTime, Length: 361, dtype: int64

用自带函数value_counts() 来得到每个类别型变量的 种类 分布;并且简单画出柱状图直观地显示各变量的种类分布。

通过统计数字和柱状图,可以发现:
rentType:4种,且绝大多数是无用的未知方式;
houseType:104种,绝大多数在3室及以下;
houseFloor:3种,分布较为均匀;
region: 15种;
plate: 66种;
houseToward: 10种;
houseDecoration: 4种,一大半是其他;
buildYear: 80种;
communityName: 4236种,且分布较为稀疏;

此步骤是为之后数据处理和特征工程做准备,先理解每个字段的含义以及分布,之后需要根据实际含义对分类变量做不同的处理。

统计特征值频次大于100的特征

# 统计特征值频次大于100的特征
print('统计特征值频次大于100的特征')
for feature in categorical_feas:
    df_value_counts = pd.DataFrame(data_train[feature].value_counts())
    df_value_counts = df_value_counts.reset_index()
    df_value_counts.columns = [feature,'counts']  # 改变列名
    print(df_value_counts[df_value_counts['counts']>=100])

结果

  rentType  counts
0     未知方式   30759
1       整租    5472
2       合租    5204
   houseType  counts
0     1119805
1     2118512
2     2216783
3     3113992
4     3222737
5     4111957
6     3211920
7     1011286
8     121933
9     222881
10    422435
11    201419
12    423273
13    511197
14    212155
15    323149
16    312135
  houseFloor  counts
015458
114066
211916
     region  counts
0   RG00002   11437
1   RG00005    5739
2   RG00003    4186
3   RG00010    3640
4   RG00012    3368
5   RG00004    3333
6   RG00006    1961
7   RG00007    1610
8   RG00008    1250
9   RG00013    1215
10  RG00001    1157
11  RG00014    1069
12  RG00011     793
13  RG00009     681
      plate  counts
0   BK00031    1958
1   BK00033    1837
2   BK00045    1816
3   BK00055    1566
4   BK00056    1516
5   BK00052    1375
6   BK00017    1305
7   BK00041    1266
8   BK00054    1256
9   BK00051    1253
10  BK00046    1227
11  BK00035    1156
12  BK00042    1137
13  BK00009    1016
14  BK00050     979
15  BK00043     930
16  BK00026     906
17  BK00047     880
18  BK00034     849
19  BK00013     834
20  BK00053     819
21  BK00028     745
22  BK00040     679
23  BK00060     671
24  BK00010     651
25  BK00029     646
26  BK00062     618
27  BK00022     614
28  BK00018     613
29  BK00064     590
30  BK00005     549
31  BK00003     523
32  BK00014     500
33  BK00019     498
34  BK00061     477
35  BK00011     455
36  BK00037     444
37  BK00012     412
38  BK00038     398
39  BK00024     397
40  BK00020     384
41  BK00002     357
42  BK00065     348
43  BK00027     344
44  BK00039     343
45  BK00063     281
46  BK00057     278
47  BK00015     253
48  BK00006     231
49  BK00021     226
50  BK00007     225
51  BK00066     219
52  BK00030     219
53  BK00049     211
54  BK00008     210
55  BK00004     189
56  BK00048     165
57  BK00025     157
58  BK00023     127
59  BK00059     122
  houseToward  counts
034377
1          南北    2254
22043
3        暂无数据     963
4          东南     655
5552
6           西     264
7          西南     250
  houseDecoration  counts
0              其他   29040
1              精装   10918
2              简装    1171
3              毛坯     311
   communityName  counts
0        XQ01834     358
1        XQ01274     192
2        XQ02273     188
3        XQ03110     185
4        XQ02337     173
5        XQ01389     166
6        XQ01658     163
7        XQ02789     152
8        XQ01561     151
9        XQ00530     151
10       XQ01339     132
11       XQ00826     122
12       XQ01873     122
13       XQ02296     121
14       XQ01232     119
15       XQ01401     118
16       XQ02441     117
17       XQ00196     115
18       XQ01207     109
19       XQ02365     109
20       XQ01410     108
21       XQ00852     105
22       XQ01672     103
23       XQ02072     103
  city  counts
0   SH   41440
   buildYear  counts
0       1994    2851
1       暂无信息    2808
2       2006    2007
3       2007    1851
4       2008    1849
5       2005    1814
6       2010    1774
7       1995    1685
8       1993    1543
9       2011    1498
10      2004    1431
11      2009    1271
12      2014    1238
13      2003    1156
14      1997    1125
15      2002    1120
16      2012    1049
17      1996     991
18      2000     925
19      2001     898
20      2015     840
21      1999     822
22      1998     733
23      2013     714
24      1987     632
25      1983     612
26      1991     545
27      1984     493
28      1980     452
29      1990     431
30      1988     423
31      1989     419
32      1985     359
33      1982     344
34      1986     320
35      1992     308
36      1976     251
37      1957     227
38      1981     221
39      1956     153
40      1977     153
41      2016     140
42      1978     133
43      1958     122
44      1979     116
45      1954     101
      tradeTime  counts
0      2018/3/3     543
1      2018/3/4     487
2     2018/3/11     410
3     2018/3/10     400
4     2018/3/24     341
5     2018/3/18     339
6      2018/3/1     332
7     2018/3/17     328
8      2018/3/5     296
9     2018/2/25     292
10     2018/3/8     291
11    2018/3/25     283
12     2018/3/2     276
13     2018/3/9     272
14    2018/3/12     260
15    2018/3/31     258
16     2018/3/7     252
17    2018/6/10     250
18    2018/8/19     234
19     2018/3/6     229
20    2018/7/29     225
21    2018/2/28     223
22     2018/7/1     221
23    2018/8/26     220
24    2018/3/15     218
25    2018/5/20     218
26    2018/5/27     217
27    2018/7/14     210
28    2018/4/22     210
29    2018/6/23     209
..          ...     ...
154    2018/6/1     106
155  2018/11/24     106
156   2018/8/16     106
157   2018/6/29     106
158   2018/12/1     105
159   2018/8/29     105
160    2018/8/2     105
161    2018/6/7     105
162   2018/4/24     104
163   2018/6/13     104
164   2018/5/18     104
165  2018/11/11     104
166   2018/6/15     104
167   2018/4/12     103
168   2018/4/23     103
169   2018/9/24     103
170    2018/5/4     102
171    2018/5/2     102
172    2018/5/7     102
173   2018/4/11     102
174   2018/4/20     102
175   2018/7/10     102
176   2018/9/13     101
177   2018/4/28     101
178   2018/8/27     101
179    2018/7/4     100
180   2018/5/25     100
181  2018/11/25     100
182    2018/9/6     100
183    2018/9/3     100

[184 rows x 2 columns]

此步骤和特征nunique分布结合步骤结合起来看,有一些小于100的是可以直接统一归类为其他的

label分布

# label分布
print('label分布')
fig,axes = plt.subplots(2,3,figsize=(20,5))
fig.set_size_inches(20,12)
sns.distplot(data_train['tradeMoney'],ax=axes[0][0])
sns.distplot(data_train[(data_train['tradeMoney']<20000)]['tradeMoney'],ax=axes[0][1])

sns.distplot(data_train[(data_train['tradeMoney']>=20000) & 
                       (data_train['tradeMoney']<50000)]['tradeMoney'],ax=axes[0][2])
    
sns.distplot(data_train[(data_train['tradeMoney']>=50000) & 
                        (data_train['tradeMoney']<100000)]['tradeMoney'],ax=axes[1][0])
    
sns.distplot(data_train[(data_train['tradeMoney']>=100000)]['tradeMoney'],ax=axes[1][1])

print("money<=10000",len(data_train[(data_train['tradeMoney']<=10000)]['tradeMoney']))
print("10000<money<=20000",len(data_train[(data_train['tradeMoney']>10000)&(data_train['tradeMoney']<=20000)]['tradeMoney']))
print("20000<money<=50000",len(data_train[(data_train['tradeMoney']>20000)&(data_train['tradeMoney']<=50000)]['tradeMoney']))
print("50000<money<=100000",len(data_train[(data_train['tradeMoney']>50000)&(data_train['tradeMoney']<=100000)]['tradeMoney']))
print("100000<money",len(data_train[(data_train['tradeMoney']>100000)]['tradeMoney']))

结果
在这里插入图片描述

money<=10000 38964
10000<money<=20000 1985
20000<money<=50000 433
50000<money<=100000 39
100000<money 19

将目标变量tradeMoney分组,并查看每组间的分布;
可以看出绝大多数都是集中在10000元以内的,并且从图中可以看到该分布是右偏的。

编码问题

对11种类别型变量分别考虑进行编码,
rentType:对出租方式来讲,除了“未知方式”、“整租”、“合租”,还有一种"–",只有5个,样本量较少,而且在测试集数据中也没有该种类型的出租方式,因此可以将其作为异常值处理。
‘houseType’:房屋类型,用于说明几室几厅几卫,具有大小关系,因此采用分别给室厅卫赋予权重,进行加权。

‘houseFloor’: 房屋楼层只有高中低三种,而且具有大小关系,可以设为3,2,1。

‘houseToward’:房屋朝向有10种类型,其中有一种是“未知类型”,类型之间没有大小关系,因此可以采用onehat编码。

‘houseDecoration’:房屋装修有四种类型:“其它”、“精装”、“简装”、“毛坯”,之间有等级关系,但存在其它,可以默认为“其它”应该介于“毛坯”和“简装”之间,因此四者关系设为2,4,3,1。
‘communityName’, 小区名称,一共4236个,认为小区名称与ID类似,因此这个特征不参与训练。

‘city’:与ID类似。

‘region’:与ID 类似。

‘plate’:与ID类似。

‘buildYear’:建筑年份,转换为数值型,需要归一化处理。

’tradeTime’:交易时间,建议转换为年月日。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值