前言

表格机器学习的4类特征

最近在思考表格机器学习,或者说对表格数据、结构化数据的有监督机器学习的工作流。

我认为在大部分场景下,大概有4类特征:

  1. categorical
  2. numerical
  3. date
  4. text

text 特征组

最近在调研text特征组。如果一个表格中有一列全是文本,其实这个文本是可以包含很多信息的,可以用TFIDF提取重要度,然后用主题模型建模或者用矩阵分解的方法进行降维。TFIDF的输出是一个稀疏矩阵,一般不能直接丢给学习器,最好做个降维,其实降维后信息的损失并不大,甚至对于模型还有提升的效果。

数据处理

载入数据

import pandas as pd
df=pd.read_csv("train_classification.csv")
name=df.Name

读入数据,只取出名字列

def clean_text(text):
    text=text.replace("\n"," ").replace("\r"," ")
    punc_list='''!"'#$&()*+,-./:;<=>?@[\]^_{|}~`0123456789'''
    t=str.maketrans(dict.fromkeys(punc_list," "))
    text=text.translate(t)
    return text

数据清洗

name=name.apply(clean_text)

对数据进行清洗,方便做tokenlization
Titanic数据集:仅用名字列就取得0.8的正确率_机器学习

分词

name_list=name.str.split()

分词(tokenlize)
Titanic数据集:仅用名字列就取得0.8的正确率_建模_02

删除低频词

from functools import reduce

from operator import add

flattern_name_list=reduce(add, name_list)

from collections import Counter

counter=Counter(flattern_name_list)

counter={k:v for k,v in counter.items() if v >1}

def remove_low_requency(items):
    return [item for item in items if item in counter]

filter_name_list=name_list.apply(remove_low_requency)

删除低频词

Titanic数据集:仅用名字列就取得0.8的正确率_矩阵分解_03

建模

建模我分两类,一类用sklearn建模,一类用gensim建模

benchmark模型采用没调参的RandomForest

from sklearn.model_selection import cross_val_score

from sklearn.ensemble import RandomForestClassifier

rf=RandomForestClassifier(random_state=100)

y=df["Survived"].values

sklearn

TF-IDF

list拼起来

str_series=filter_name_list.str.join(" ")

Titanic数据集:仅用名字列就取得0.8的正确率_建模_04

from sklearn.feature_extraction.text import TfidfVectorizer

tfidf=TfidfVectorizer().fit_transform(str_series)

Titanic数据集:仅用名字列就取得0.8的正确率_稀疏矩阵_05

Titanic数据集:仅用名字列就取得0.8的正确率_建模_06

用TF-IDF的确可以取得不错的效果。缺点是维度高,这里我已经删除了只出现一次的词了,但是还有400维。如果在更复杂的任务一般会上10万维。

而且TFIDF的输出是稀疏矩阵,很多学习器和预处理器不支持这样的数据,虽然可以做密集化,但是可能OOM。

NMF

非负矩阵分解

from sklearn.decomposition import NMF

x=NMF(n_components=4,random_state=42).fit_transform(tfidf);x

Titanic数据集:仅用名字列就取得0.8的正确率_矩阵分解_07
可以看到信息损失不大,但维度显著降低了

TruncatedSVD

https://scikit-learn.org/stable/modules/decomposition.html#lsa

https://blog.csdn.net/mmc2015/article/details/46867773

TSVD其实就是LSA,与LSI相似。

Titanic数据集:仅用名字列就取得0.8的正确率_机器学习_08
TSVD在本文中表现是最好的,直接取得了0.8的正确率

gensim

from gensim.sklearn_api import LdaTransformer, LsiTransformer, HdpTransformer, RpTransformer

与sklearn的API不同,gensim多了很多自己的东西,比如corpus和dictionary等,所以这里将gensim的模型单独拿到一个目录下说。

dic=Dictionary(filter_name_list)

首先要将filter_name_list这个元素都是list的series处理成字典

bow_list=[dic.doc2bow(item) for item in filter_name_list]

处理成文档词袋(感觉这种形式的数据结构和CSR的稀疏矩阵的内存占用可能差不多…)

Titanic数据集:仅用名字列就取得0.8的正确率_数据_09

LDA

latent dirichlet allocation

model = LdaTransformer(num_topics=4, id2word=dic, iterations=20, random_state=1)

Titanic数据集:仅用名字列就取得0.8的正确率_数据_10
不知道为什么,LDA是本文表现最差的模型

LSI

latent semantic indexing
Titanic数据集:仅用名字列就取得0.8的正确率_机器学习_11
这里需要注意的是,LSI的API中并没有random_state,并且模型的表现是有随机性的。

RP

RandomProjection
Titanic数据集:仅用名字列就取得0.8的正确率_建模_12
这里需要注意的是,RP的API中并没有random_state,并且模型的表现是有随机性的。

HDP

hierarchical dirichlet process

这个模型我没有跑通。这个模型可以指定random_state,但是却不能指定topic数目(实际的topic数目是根据数据判断出来的)