在结构化数据中经常遇到列表或交易等非结构化列,比较典型的案例如下,此时一个列表列会包含字符串 或 一个列表:
ID列 Tag列
用户A tag1, tag2, tag3
用户B tag3, tag5, tag6, tag10
用户C tag3, tag5, tag6, tag10
如何对此类列进行编码和提取特征呢?本文将给出一些基础和进阶的解决方法。
方法1:进行基础统计
在进行编码时,最基础的想法是可以统计个数,个数的多少可以直观反应这列包含的信息的多少。
df['Tag列'].apply(len)
当然可以直接进行统计列表长度,也可以先计算每个tag的频次,然后进行相应的统计。
-
优点:实现简单,并没有增加维度;
-
缺点:信息丢失较多
方法2:提取TFIDF
在进行编码的过程中,可以使用onehot对单个某个tag进行编码,又或者使用直接使用TFIDF进行编码。
-
CounterVecoter:计算TF
-
TFIDFVector:计算TF + IDF
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.feature_extraction.text import TfidfVectorizer
-
优点:可以对tag进行有效索引;
-
缺点:增加特征维度;
方法3:TFIDF + LDA/SVD
进行次数编码容易造成维度爆炸,一种代替的方法是先进行TFIDF编码,然后进行降维:LDA、SVD或者t-SNE降维。
from sklearn.decomposition import PCA
from sklearn.decomposition import LatentDirichletAllocation
from sklearn.decomposition import TruncatedSVD
-
优点:维度更低,特征更加有区分性。
-
缺点:降维需要额外的训练时间;
方法4:句子嵌入
词向量是一种非常有效的单词编码方法,可以对单词进行映射。我们可以参考无监督句子编码的方法,对tag进行嵌入,然后对多个tag进行聚合。
如果一个tag编码为100维度,则我们需要将任意多个tag都编码为100维度。这里的聚合方法包括:
-
Mean-pooling
-
Max-pooling
-
TFIDF-pooling
-
SIF Embedding
上述实现过程需要额外训练词向量,如果使用深度学习框架实现会更加快速。
-
优点:维度更加可控,语义更加完整。
-
缺点:不适用tag乱序的情况
方法5:频繁项聚类
对于tag列可以作为集合进行处理,可以参考频繁项挖掘的方法进行聚类操作。频繁项集聚类提供了一个减少维度,聚类之后的聚类类别可以单独当做类别变量。
相应簇由包含频繁项集,当然也可以使用文本聚类的方法,比如层次聚类。
-
优点:可解释性强,维度低;
-
缺点:需要额外编码,聚类更新困难
方法6:PageRank
在多个tag进行编码的过程,可以单独计算每个tag的IDF,也就是权重。当然我们也可以将多个tag组合在一起视为一个图。
比如tag1, tag2, tag3
可以构建为一个三个节点的有向图,构建完成之后然后计算每个节点的权重。
通过PageRank可以计算得到每个tag的权重,也可以得到所有tag得到的图的核心节点。
-
优点:tag权重有意义,可解释。
-
缺点:适用于tag间存有向的情况。
方法7:minihash或者LSH
如果将tag列表当做集合看待,我们可以使用minihash进行对集合进行编码,然后使用LSH进行编码。LSH包含多次哈希,最终可以将包含相同tag的列表哈希得到相同的桶中。
-
优点:适用于大规模和分布式数据集
-
缺点:需要手动设计哈希函数