Advertisement

特征工程——数据清洗——字符串数值特征提取(1)

阅读量:

近月重点研习了特征工程相关的数据清洗工作的核心内容。在实际操作过程中遇到了以往从未见过的问题,并且只是自己刚开始接触这方面的知识,对于Python相关知识掌握还不够熟练。

数据来自于某数据集——北京房价预测的数据清洗实践。

导入数据集,并看数据信息,变量,数据类型等。

复制代码
 data = pd.read_csv('houseInfo_2018_09_10.csv')

    
 bj_data = data[data['region'] == 'bj']
    
 print(bj_data.info())
    
 print(bj_data.head())
复制代码
 Int64Index: 48324 entries, 418423 to 627466

    
 Data columns (total 22 columns):
    
 introduction_house    48324 non-null object
    
 community_house       48324 non-null object
    
 href_house            48324 non-null object
    
 unit_house            48324 non-null object
    
 size_house            48324 non-null object
    
 direction_house       48324 non-null object
    
 decoration_house      48313 non-null object
    
 elevator_house        47437 non-null object
    
 type_house            48324 non-null object
    
 years_house           48311 non-null object
    
 area_house            48324 non-null object
    
 interests_house       48324 non-null object
    
 watch_times           48324 non-null object
    
 submit_period         0 non-null float64
    
 years_period          39804 non-null object
    
 tax_free              45673 non-null object
    
 total_price           48324 non-null float64
    
 smeter_price          48324 non-null object
    
 region                48324 non-null object
    
 info_cluster          0 non-null object
    
 info_flood            0 non-null object
    
 info_follow           0 non-null object
    
  
    
  introduction_house community_house                                           href_house unit_house size_house direction_house decoration_house elevator_house type_house years_house area_house interests_house watch_times  submit_period years_period tax_free  total_price smeter_price region info_cluster info_flood info_follow
    
 418423  长城脚下,精装修别墅,满五唯一,业主诚意出售。           清凉盛景   https://bj.lianjia.com/ershoufang/101103236018.html       5室3厅   269.93平米             南 北               精装            NaN    底层(共2层)        暂无数据       延庆其它            3人关注        0次带看            NaN          NaN    房本满五年        998.0  单价36973元/平米     bj          NaN        NaN         NaN
    
 418424  商品房  满五年  家庭名下一套住房  环境好           清凉盛景   https://bj.lianjia.com/ershoufang/101102750912.html       4室2厅   269.93平米             南 北               精装            NaN         2层  2010年建暂无数据       延庆其它           14人关注        0次带看            NaN          NaN    房本满五年       1250.0  单价46309元/平米     bj          NaN        NaN         NaN
    
 418425           湖南小区 2室1厅 179万           湖南小区   https://bj.lianjia.com/ershoufang/101103256056.html       2室1厅    71.45平米             南 北               其他            NaN   中楼层(共6层)  1996年建暂无数据       延庆其它            8人关注        0次带看            NaN          NaN    房本满五年        179.0  单价25053元/平米     bj          NaN        NaN         NaN
    
 418426          清凉盛景 4室2厅 1180万           清凉盛景   https://bj.lianjia.com/ershoufang/101103166425.html       4室2厅   252.16平米             南 北               精装            NaN    底层(共2层)  2010年建暂无数据       延庆其它            0人关注        0次带看            NaN          NaN    房本满五年       1180.0  单价46796元/平米     bj          NaN        NaN         NaN
    
 424545        君山别墅 边户独栋 391平毛坯房           君山别墅   https://bj.lianjia.com/ershoufang/101101025128.html       3室2厅   391.86平米             南 北               毛坯            NaN    底层(共2层)  2011年建暂无数据       密云其它          107人关注        1次带看            NaN        房本满两年    房本满五年       1000.0  单价25520元/平米     bj          NaN        NaN         NaN

观察结果表明

进一步审视数据中的缺失情况后发现

复制代码
 stats = []

    
 for col in bj_data.columns:
    
     stats.append((col, bj_data[col].nunique(), bj_data[col].isnull().sum() * 100 / bj_data.shape[0],
    
     bj_data[col].value_counts(normalize=True, dropna=False).values[0] * 100, bj_data[col].dtype))
    
  
    
 stats_df = pd.DataFrame(stats, columns=['Feature', 'Unique_values', 'Percentage of missing values',
    
                                     'Percentage of values in the biggest category', 'type'])
    
 print(stats_df.sort_values('Percentage of missing values', ascending=False)[:23])
复制代码
            Feature  Unique_values  Percentage of missing values  Percentage of values in the biggest category     type

    
 21         info_follow              0                    100.000000                                    100.000000   object
    
 13       submit_period              0                    100.000000                                    100.000000  float64
    
 20          info_flood              0                    100.000000                                    100.000000   object
    
 19        info_cluster              0                    100.000000                                    100.000000   object
    
 14        years_period              1                     17.630991                                     82.369009   object
    
 15            tax_free              1                      5.485887                                     94.514113   object
    
 7       elevator_house              6                      1.835527                                     62.018873   object
    
 9          years_house            210                      0.026902                                      3.186822   object
    
 6     decoration_house             15                      0.022763                                     49.163976   object
    
 18              region              1                      0.000000                                    100.000000   object
    
 17        smeter_price          35405                      0.000000                                      0.066220   object
    
 16         total_price           1804                      0.000000                                      1.338879  float64
    
 0   introduction_house          47779                      0.000000                                      0.014486   object
    
 12         watch_times             93                      0.000000                                     33.451287   object
    
 1      community_house           5674                      0.000000                                      0.360070   object
    
 10          area_house            235                      0.000000                                      3.029551   object
    
 8           type_house            291                      0.000000                                      8.718235   object
    
 5      direction_house            207                      0.000000                                     45.348067   object
    
 4           size_house          15283                      0.000000                                      0.091052   object
    
 3           unit_house             79                      0.000000                                     36.845046   object
    
 2           href_house          48323                      0.000000                                      0.004139   object
    
 11     interests_house            638                      0.000000                                      2.460475   object

如果某个特征的数据缺失率(percentage of missing values)过高(达到或超过70%),则应予以删除;而当其数据缺失率达到或超过90%,同样也可予以删除。具体情况下,该特征对因变量的影响程度如何将直接影响模型性能。在筛选阶段需减少特征数量时,在本例中我们还需进一步清理一些非相关数据项(例如网站链接、别墅类信息等),这些问题均由网络爬虫遗留所致。

依然搬轮子,并打印看看。

复制代码
 bj_data.drop(['info_follow', 'submit_period', 'info_flood',

    
           'introduction_house','community_house','region',
    
           'info_cluster','href_house'], axis=1, inplace=True)
    
 print(bj_data.shape)
    
 print(bj_data.head())
复制代码
 (48324, 14)

    
    unit_house size_house direction_house decoration_house elevator_house type_house years_house area_house interests_house watch_times years_period tax_free  total_price smeter_price
    
 418423       5室3厅   269.93平米             南 北               精装            NaN    底层(共2层)        暂无数据       延庆其它            3人关注        0次带看          NaN    房本满五年        998.0  单价36973元/平米
    
 418424       4室2厅   269.93平米             南 北               精装            NaN         2层  2010年建暂无数据       延庆其它           14人关注        0次带看          NaN    房本满五年       1250.0  单价46309元/平米
    
 418425       2室1厅    71.45平米             南 北               其他            NaN   中楼层(共6层)  1996年建暂无数据       延庆其它            8人关注        0次带看          NaN    房本满五年        179.0  单价25053元/平米
    
 418426       4室2厅   252.16平米             南 北               精装            NaN    底层(共2层)  2010年建暂无数据       延庆其它            0人关注        0次带看          NaN    房本满五年       1180.0  单价46796元/平米
    
 424545       3室2厅   391.86平米             南 北               毛坯            NaN    底层(共2层)  2011年建暂无数据       密云其它          107人关注        1次带看        房本满两年    房本满五年       1000.0  单价25520元/平米

可以看出数据集中的特征减少情况已经显现出来。进一步发现,在这些特征中有大量数据存在于文本内容中,并且需要从文本内容中首先提取相关信息。

数据清洗的核心原则是"早抛早回收";其中的主要做法是优先获取数值型数据,并尽可能在早期进行处理。

为了更好地从文本中提取出一系列数字特征,请问您具体指的是哪些?包括watch-times、size-house等指标。具体方法是通过应用正则表达式或者字符串切片的方法来获取这些数值,并将这些数值转换为数值型数据。

首先关注字符串切片的方法(例如size-house),它位于一列中其主要目的在于从该列中提取房屋尺寸的数据。例如269.93平方米这个数值即提取269.93这个数值自然会想到遍历该列中的所有元素放于一个新的列表中,并对这些字符串中的数字进行数值装换。

复制代码
 size_house0 = []

    
 for sh1 in bj_data['size_house']:
    
     size_house0.append(sh1[-8:-2])

但print size-house发现,这个切片sh1[-8:-2],根据结果有如下,

复制代码
    '281.64', '4室', '281.64', '280.65', '4室', '146.3'

基于索引的位置并不理想, 因为数据集中该特征存在错误. 实在糟糕极了. 因此之后我们采用正则化方法提取数值特征.

复制代码
 from funtools import reduce

    
 def str2float(s):
    
   return reduce(lambda x,y:x+int2dec(y),map(str2int,s.split('.')))
    
 def char2num(s):
    
   return {'0':0,'1':1,'2':2,'3':3,'4':4,'5':5,'6':6,'7':7,'8':8,'9':9}[s]
    
 def str2int(s):
    
   return reduce(lambda x,y:x*10+y,map(char2num,s))
    
 def intLen(i):
    
   return len('%d'%i)
    
 def int2dec(i):
    
   return i/(10**intLen(i))
    
 size_house0 = []
    
 for sh1 in bj_data['size_house']:
    
     size_house0.append(str2float(''.join(re.findall(r"\d+\.?\d*",sh1))))
    
 print(size_house0)
    
  
    
  
    
 结果:269.93, 269.93, 71.45, 252.16, 391.86, 96.65···

又增添了另一个步骤,在遍历过程中识别出相应的数值。然而这些数值是以字符串形式存在的接下来将其转换为数值型数据。然后将其整合进数据集可以选择替换原有的数据集但由于新手不太熟悉操作流程所以采取了一种较为繁琐的手动方法。

复制代码
 bj_data.insert(2,'size_house1',size_house0)

    
 bj_data.drop('size_house',axis=1, inplace=True)
    
 print(bj_data.info())
    
 print(bj_data.head())
    
  
    
  
    
 结果:
    
  ········
    
 total_price         48324 non-null float64
    
 smeter_price        48324 non-null object
    
 dtypes: float64(2), object(12)
    
 memory usage: 5.5+ MB
    
 None
    
    unit_house  size_house1 direction_house decoration_house elevator_house type_house years_house area_house interests_house watch_times years_period tax_free  total_price smeter_price
    
 418423       5室3厅       269.93             南 北               精装            NaN    底层(共2层)        暂无数据       延庆其它            3人关注        0次带看          NaN    房本满五年        998.0  单价36973元/平米
    
 418424       4室2厅       269.93             南 北               精装            NaN         2层  2010年建暂无数据       延庆其它           14人关注        0次带看          NaN    房本满五年       1250.0  单价46309元/平米
    
 418425       2室1厅        71.45             南 北               其他            NaN   中楼层(共6层)  1996年建暂无数据       延庆其它            8人关注        0次带看          NaN    房本满五年        179.0  单价25053元/平米
    
 418426       4室2厅       252.16             南 北               精装            NaN    底层(共2层)  2010年建暂无数据       延庆其它            0人关注        0次带看          NaN    房本满五年       1180.0  单价46796元/平米
    
 424545       3室2厅       391.86             南 北               毛坯            NaN    底层(共2层)  2011年建暂无数据       密云其它          107人关注        1次带看        房本满两年    房本满五年       1000.0  单价25520元/平米

此时输出用会发现float多一列,说明是成功的。

使用相同的策略来提取特征interests_house、watch_times以及smeter_price中的数值信息。

复制代码
 intertest_house0 =[]

    
 for ih in bj_data['interests_house']:
    
     intertest_house0.append(str2float(''.join(re.findall(r"\d+\.?\d*",ih))))
    
 # print(intertest_house0)
    
 bj_data.insert(2,'interests_house1',intertest_house0)
    
 bj_data.drop('interests_house',axis=1, inplace=True)
    
 watch_times0 = []
    
 for wt in bj_data['watch_times']:
    
     watch_times0.append(str2float(''.join(re.findall(r"\d+\.?\d*",wt))))
    
 # print(watch_times0)
    
 bj_data.insert(2,'watch_times1',watch_times0)
    
 bj_data.drop('watch_times',axis=1, inplace=True)
    
 smeter_price0 = []
    
 for sp in bj_data['smeter_price']:
    
     smeter_price0.append(str2float(''.join(re.findall(r"\d+\.?\d*",sp))))
    
 # print(watch_times0)
    
 bj_data.insert(2,'smeter_price1',smeter_price0)
    
 bj_data.drop('smeter_price',axis=1, inplace=True)
    
  
    
 结果:
    
 ····
    
  unit_house  size_house1  smeter_price1  watch_times1  interests_house1 direction_house decoration_house elevator_house type_house years_house area_house years_period tax_free  total_price
    
 418423       5室3厅       269.93          36973             0                 3             南 北               精装            NaN    底层(共2层)        暂无数据       延庆其它          NaN    房本满五年        998.0
    
 418424       4室2厅       269.93          46309             0                14             南 北               精装            NaN         2层  2010年建暂无数据       延庆其它          NaN    房本满五年       1250.0
    
 418425       2室1厅        71.45          25053             0                 8             南 北               其他            NaN   中楼层(共6层)  1996年建暂无数据       延庆其它          NaN    房本满五年        179.0
    
 418426       4室2厅       252.16          46796             0                 0             南 北               精装            NaN    底层(共2层)  2010年建暂无数据       延庆其它          NaN    房本满五年       1180.0
    
 424545       3室2厅       391.86          25520             1               107             南 北               毛坯            NaN    底层(共2层)  2011年建暂无数据       密云其它        房本满两年    房本满五年       1000.0

看见相关数字都背提取出来了。

随后运用相同的方法对unit_house执行数值提取操作。其结果构成一个嵌套列表结构,在此过程中需要将5室3厅划分为三个独立特征维度。即构建新的特征维度:房屋所拥有的房间数量为5间;卧室数量为3间;总卧室数量则为8间。在此阶段自然需要对该列表进行解构处理以获取所需数据信息;然而经过多种尝试后仍未能达到预期效果

复制代码
 bedroom = []

    
 for bd in bj_data['unit_house']:
    
     bedroom.append(re.findall(r"\d+\.?\d*",bd))
    
 print(bedroom)
    
  
    
  
    
 结果:
    
 ···
    
 [['5', '3'], ['4', '2'], ['2', '1'], ['4', '2'],···]

采用将该列表展平,并结合以下方式处理:遍历每个房间中的物品(i for j in bedroom for i in j),随后使用/t.extend(i)将其展平;同时在处理多维数组时需注意以下几点:例如,在访问bedroom[0][0]或x[1](其中x遍历bedroom)时可能会遇到索引越界等问题。目前尝试的方法尚未找到理想解决方案。(欢迎大神提出改进方案建议!小白在此表示期待中!谢谢)

通过以上的实践经验可以看出,在完成了数据预处理后才能继续后续分析流程

但这也是一项具有挑战性的尝试;这也是我们团队首次涉及的数据处理工作。后续需要我们对上文中指出的问题进行改进和完善。

在这个过程中, 数据清理的主要目标是尽可能地提取数字特征, 最终会获得一个数值型的多维列表, 并将其导入到算法计算中。后续将学习如何处理类别数据, 时间、地理位置以及相关属性的数据清理学习

程序的编写需通过编写代码来实现特定功能。然而,在开始编码之前,请先明确目标并了解所需实现的功能。这条路依然漫长且充满挑战。

(继续实践)

在使用x[1] for x in bedroom时出现了数组越界问题,在Python中发现这是由于数据量过大导致的内存不足情况。具体表现为数组索引超出范围或者内存溢出等问题。这方面的底层机制尚不明确。虽然在网络上找到一些解决方案但实际效果并不理想因此也打算尝试将该方法应用于本项目以便更好地了解其运行机制之后再进行优化操作。另外通过将bedroom的数据保存至本地CSV文件并在读取时避免直接处理整个数组的方式能够有效缓解相关性能问题随后计划从CSV文件中导入数据并构建新的特征字段rooms并将其与原有特征进行融合从而提升模型的整体表现效果

复制代码
 temp=pd.DataFrame(data=bedroom)

    
 temp.to_csv('1.csv',encoding='utf-8')
    
 data1 = pd.read_csv('1.csv')
    
  
    
 bedroom1 = []
    
 for b in data1['0']:
    
     bedroom1.append(b)
    
 #print(bedroom1)
    
 bj_data.insert(2,'bedroom',bedroom1)
    
  
    
 living_room1 = []
    
 for l in data1['1']:
    
     living_room1.append(l)
    
 #print(living_room1)
    
 bj_data.insert(2,'living_room',living_room1)
    
  
    
 rooms1 = [bedroom1[i] +living_room1[i] for i in range(0,len(living_room1))]
    
 #print(rooms1)
    
 bj_data.insert(2,'rooms',rooms1)
    
 bj_data.drop('unit_house',axis=1, inplace=True)
    
  
    
 结果·······
    
  size_house1  rooms  living_room  bedroom  smeter_price1  watch_times1  interests_house1 direction_house decoration_house elevator_house type_house years_house area_house years_period tax_free  total_price
    
 418423       269.93    8.0          3.0      5.0          36973             0                 3             南 北               精装            NaN    底层(共2层)        暂无数据       延庆其它          NaN    房本满五年        998.0
    
 418424       269.93    6.0          2.0      4.0          46309             0                14             南 北               精装            NaN         2层  2010年建暂无数据       延庆其它          NaN    房本满五年       1250.0
    
 418425        71.45    3.0          1.0      2.0          25053             0                 8             南 北               其他            NaN   中楼层(共6层)  1996年建暂无数据       延庆其它          NaN    房本满五年        179.0
    
 418426       252.16    6.0          2.0      4.0          46796             0                 0             南 北               精装            NaN    底层(共2层)  2010年建暂无数据       延庆其它          NaN    房本满五年       1180.0
    
 424545       391.86    5.0          2.0      3.0

观察到新增了三列数据。但该方法存在一个需要注意的问题:在原始列表中可能存在缺失值。如果发现有缺失值,则应在处理前进行填补;否则会导致索引失配,并可能导致计算后的结果与因变量的数据关系出现偏差。即使如此,在每个缺失值处也需要谨慎处理

接下来的重点是对**categorical data类型的变量进行处理,例如房子朝向.此外还涉及到了更为复杂的文本类型数据的处理.

(未完待续)

全部评论 (0)

还没有任何评论哟~