2020链家杭州二手房数据分析(截止到2020年09月07日)
1 项目背景
通过python爬去链家杭州二手房的数据,网址为:https://hz.lianjia.com/ershoufang/。可以发现,链家把杭州分为15个区域。其中,截止到2020年09月07日,桐庐和建德区域数据为0条,大江东数据为2两条,淳安数据共32条。和其他区域相比,这几个区域数据量太小,因此在后续爬去过去中略去。
通过requests
和BeautifulSoup
库爬取和解析,代码就不放了,很简陋。注意每次爬取后设置随机间隔时间,做个简单的反反爬虫,不然会被封IP。我设置的间隔时间为random.randint(0,2) + random.random()
。最终,一共获得了31, 230条记录。
2 理解数据
数据含义如下:
字段名 | 字段含义 |
---|---|
postion | 具体位置 |
Layout | 房屋布局 |
Size | 房屋面积 |
Directioin | 房屋朝向 |
Renovation | 装修情况 |
Floor | 楼层 |
Structure | 房屋结构(板楼、塔楼) |
totalPrice | 总价格 |
unitPrice | 单价 |
District | 所在区县 |
3 探索数据
3.1 数据查看
通过pandas导入数据df = pd.read_excel('lz_hangzhou-copy.xlsx')
后,使用df.head(10)
简单查看前10行数据。结果如下:
3.2 数据清洗
3.2.1 缺失值
再看看有没有缺失值:df.isnull().sum().sort_values()
,没有发现缺失值。数据维护的挺好。
3.2.2 unitPrice列
接下来,处理unitPrice列。需要吧汉字去除和‘/’去掉。观察一下,可以使用正则表达式找出其中的数字。
df['unitPrice'] = df['unitPrice'].apply(lambda x: str(x)).str.findall("(\d+)").str[0].astype("float")
3.2.3 Floor列
然后处理Floor列。在这一列,数据可以分为两部分:a. 楼层位置(高、低、中); b. 层数。两部分可以由’()'分开。我们需要将这两部分新建两列,代替原来的Floor列。
首先,我们看一下不符合这个形式的记录共有多少行。df.shape[0]-df['Floor'].str.contains('\(').sum()
,返回结果是1741
,占总数据的5.6%。那我们将把这些记录删掉,df = df.loc[df['Floor'].str.contains('\(')]
。然后把Floor列拆分成floorType和totalFloor两列,分别表示楼层位置和总层数,再删除原来的Floor列。代码如下:
df['floorType'] = df['Floor'].str.split('(').str[0]
df['totalFloor'] = df['Floor'].str.split('(').str[1].str.\
findall('\d+').str[0].astype('int')
df.drop('Floor', axis=1, inplace=True)
看一下现在的数据:df.head()
3.2.4 Structure列
首先,看看Structure列的数据构成:df['Structure'].unique()
.
array([' 板楼', ' 塔楼', ' 板塔结合', ' 暂无数据'], dtype=object)
我们需要把每个类型名称中的空格去除,然后删掉’暂无数据’的记录。代码如下:
df['Structure'] = df['Structure'].str.strip()
df = df[df['Structure'] != '暂无数据']
3.2.5 Renovation列
同样,该列的数据中也有空格:
array([' 精装 ', ' 简装 ', ' 毛坯 '], dtype=object)
换一种方式去除空格。
def reno(x):
if '精装' in x: return '精装'
if '简装' in x: return '简装'
if '毛坯' in x: return '毛坯'
df['Renovation'] = df['Renovation'].apply(reno)
3.2.6 Direction列
这一列的数据构成比较多样:
array([' 南 ', ' 东 南 北 ', ' 南 北 ', ' 南 西 ', ' 东 ', ' 北 南 ', ' 东 南 ',
' 东南 ', ' 南 西 北 ', ' 西 ', ' 西南 ', ' 北 ', ' 西 北 ', ' 西北 ',
' 南 西南 北 ', ' 东南 南 '], dtype=object)
仔细观看可以发现以下几种情况:
- 单一朝向:’ 东 ', ‘ 南 ’, ‘ 西 ’, ‘ 北 ’, ‘ 西南 ’, ‘ 西北 ’,‘ 东南 ’
- 两种朝向:’ 南 北 ', ’ 南 西 ', ’ 北 南 ', ’ 东 南 ',
- 三种朝向:’ 东 南 北 ‘,’ 西 西南 南 ‘,’ 南 西 北 ',等等。
针对单一朝向的,直接去除空格。而对于多种朝向,为了后续分析方便,则简化为单种朝向,并将最终值赋予Orientation列。
def direct(x):
if "东南" in x:
if x.count("南") > 1:
if ("西南" in x) & ("南" not in x):
return "东南"
else:
return "南"
else:
return "东南"
elif "西南" in x:
if x.count("南") >1:
return "南"
else:
return "西南"
elif "东北" in x:
return "东北"
elif "西北" in x:
return "西北"
elif "东" in x:
return "东"
elif "西" in x:
return "西"
elif "南" in x:
return "南"
elif "北" in x:
return "北"
df['Orientation'] = df['Direction'].apply(direct)
df.drop('Direction', axis=1, inplace=True)
3.2.6 Size列
观察可以发现,面积都是浮点数,用正则表达式提取即可。
df['Size'] = df['Size'].str.findall('[\d,.]+').str[0].astype('float')
3.2.7 Layout列
这一列的信息为房屋格局,如3室2厅,把室的信息和厅的信息提取出来,分别存储。
df['Room'] = df['Layout'].str.findall('(\d)室(\d)厅').str[0].str[0].astype('int')
df['Hall'] = df['Layout']