特征工程系列:
什么是派生属性呢?派生属性就是从原始数据中得到的一些属性,比如上一节从Age属性经过Factorize得到的Age_bin属性就是一个派生属性,当然这种派生只是非常简单的派生。为什么要对这些属性做各种各样的统计和处理呢,这其实是特征工程的一部分,先构建足够多可能会对结果有意义的属性,然后再从这些候选集中选择我们想要的特征。特征工程非常繁琐,但是对数据挖掘非常重要,一般来说,做一个数据挖掘项目,百分之八十的努力要用在特征工程上。除了基本的转换和interaction属性,我们也要创造性的从原始属性中发现新属性。比如电话号码,可以从中提取出来国家和区域特征。
一 研究业务逻辑提取特征
Titanic的数据集相对较为简单,但是对于一些字符串类型的属性,比如Name我们可以从中提取出来一些可以揭示其社会地位的称号。
名字的长度也会代表一个人的社会地位,社会地位高的人可能会更容易得到救生船。
1 df[‘Names‘] = df[‘Name‘].map(lambda x: len(re.split(‘ ‘,x)))
对于名字中间的爵位,可以看到称号有Mr Mrs Master等,经过统计可以看到有以下几种称号:
这些称号有法语还有英语,需要依据当时的文化环境将其归类,如何将其归类可以参考这篇文章trevorstephens.com/post/73461351896/titanic-getting-started-with-r-part-4-feature
1 df[‘Title‘] = df[‘Name‘].map(lambda x: re.compile(",(.*?)\.").findall(x)[0]) 2 df[‘Title‘][df.Title==‘Jonkheer‘] = ‘Master‘ 3 df[‘Title‘][df.Title.isin([‘Ms‘,‘Mlle‘])] = ‘Miss‘ 4 df[‘Title‘][df.Title == ‘Mme‘] = ‘Mrs‘ 5 df[‘Title‘][df.Title.isin([‘Capt‘, ‘Don‘, ‘Major‘, ‘Col‘, ‘Sir‘])] = ‘Sir‘ 6 df[‘Title‘][df.Title.isin([‘Dona‘, ‘Lady‘, ‘the Countess‘])] = ‘Lady‘ 7 df[‘Title_id‘] = pd.factorize(df.Title)[0]+1
对于Ticket属性也需要处理,可以看到Ticket字段有的全是数字有的是字母和数字的集合,进一步对数据分析发现约25%的数据有前缀,前缀共有45种,如果把 . 和 / 去掉的话还剩29种,数字部分也有一定的规律:以1开头的一般是一等舱2开头的是二等舱3开头的是三等舱,4-9开头的大都是三等舱。以上这些数据告诉我们处理Ticket是有意义的,能够发现其内部蕴涵的信息。
1 def processTicket(): 2 global df 3 df[‘TicketPrefix‘] = df[‘Ticket‘].map(lambda x: getTicketPrefix(x.upper())) 4 df[‘TicketPrefix‘] = df[‘TicketPrefix‘].map(lambda x: re.sub 5 (‘[\.?\/?]‘,‘‘,x)) 6 df[‘TicketPrefix‘] = df[‘TicketPrefix‘].map(lambda x:re.sub 7 (‘STON‘,‘SOTON‘,x)) 8 df[‘TicketPrefix‘] = pd.factorize(df[‘TicketPrefix‘])[0] 9 df[‘TicketNumber‘] = df[‘Ticket‘].map(lambda x: getTicketNumber(x) ) 10 df[‘TicketNumberLength‘] = df[‘TicketNumber‘].map(lambda x: len(x)).11 astype(int) 12 df[‘TicketNumberStart‘] = df[‘TicketNumber‘].map(lambda x: x[0:1]).13 astype(int) 14 df[‘TicketNumber‘] = df[‘TicketNumber‘].astype(int) 15 def getTicketPrefix(ticket): 16 match = re.compile("([a-zA-Z\.\/]+)").search(ticket) 17 if match: 18 return match.group() 19 else: 20 return ‘U‘ 21 def getTicketNumber(ticket): 22 match = re.compile("([0-9]+$)").search(ticket) 23 if match: 24 return match.group() 25 else: 26 return ‘0‘
二 简单组合属性提取特征
一些属性可以从它本身的数据里提取一些信息,有些属性则需要和其他属性组合来产生信息。比如对淘宝上的一个商品来说,购买数/点击率可以反应商品的转化率,也是商品的一个非常重要的特征。
对于Titanic来说,我们用Age*Pclass组合产生一个属性,虽然没有一个名词来解释它,但是从结果数据上来看,我们增大了年纪大的人的权重也提高了高等舱的权重,从最后幸存的结果上看,这个组合还是有意义的。除了这两个属性之外,我们还可以对其他数值属性进行数学运算,以得到更大的候选特征集。
1 numerics = df.loc[:, [‘Age_scaled‘, ‘Fare_scaled‘, ‘Pclass_scaled‘, ‘Parch_scaled‘, ‘SibSp_scaled‘, 2 ‘Names_scaled‘, ‘CabinNumber_scaled‘, ‘Age_bin_id_scaled‘, ‘Fare_bin_id_scaled‘]] 3 print "\nFeatures used for automated feature generation:\n", numerics.head(10) 4 5 new_fields_count = 0 6 for i in range(0, numerics.columns.size-1): 7 for j in range(0, numerics.columns.size-1): 8 if i <= j: 9 name = str(numerics.columns.values[i]) + "*" + str(numerics.columns.values[j]) 10 df = pd.concat([df, pd.Series(numerics.iloc[:,i] * numerics.iloc[:,j], name=name)], axis=1) 11 new_fields_count += 1 12 if i < j: 13 name = str(numerics.columns.values[i]) + "+" + str(numerics.columns.values[j]) 14 df = pd.concat([df, pd.Series(numerics.iloc[:,i] + numerics.iloc[:,j], name=name)], axis=1) 15 new_fields_count += 1 16 if not i == j: 17 name = str(numerics.columns.values[i]) + "/" + str(numerics.columns.values[j]) 18 df = pd.concat([df, pd.Series(numerics.iloc[:,i] / numerics.iloc[:,j], name=name)], axis=1) 19 name = str(numerics.columns.values[i]) + "-" + str(numerics.columns.values[j]) 20 df = pd.concat([df, pd.Series(numerics.iloc[:,i] - numerics.iloc[:,j], name=name)], axis=1) 21 new_fields_count += 2 22 23 print "\n", new_fields_count, "new features generated"
这个过程自动产生大量的特征,这里用了9个特征产生了176个特征,可能这些特征有些过于多了,但是它只是一个候选集,我们可以通过一些处理筛选掉一些特征。当然有些模型也很适合大量特征的训练集,比如随机森林(有论文验证,随机森林是分类算法中表现最好的模型)。
产生的这些特征可能高度相关于原始特征,线性模型处理这类特征时会产生multicollinearity问题,可以用计算这些特征的皮尔逊相关系数,筛选相关性特征。如果用随机森林模型训练的话,可以不需要这个步骤。
原文:http://www.cnblogs.com/north-north/p/4358084.html