龙空技术网

机器学习(ML)算法编码:固定长度高基数非数字列

林小婵的店 171

前言:

目前你们对“算法编码方式”可能比较关心,小伙伴们都想要分析一些“算法编码方式”的相关内容。那么小编也在网摘上收集了一些关于“算法编码方式””的相关资讯,希望同学们能喜欢,你们一起来学习一下吧!

ML算法仅适用于数值。因此需要对问题及其数据进行完整的数字建模。例如,要在道路网络上运行聚类算法,将网络/图形表示为邻接矩阵是对其进行建模的一种方法。

图1:一个简单的道路网络,如左图所示。相应的邻接矩阵显示在右侧

一旦转换为数字,像k-means这样的聚类算法可以很容易地调用,以识别任何基础结构

from sklearn.cluster import KMeans

import numpy as np

X = np.array([

[0, 1, 0],

[0, 0, 1],

[1, 1, 0]

])

kmeans = KMeans(n_clusters=2, random_state=0).fit(X)

类似地,一个混合了数字和非数字/分类数据的表格数据也需要转换或编码成一个只有数字的表格。字符串值的列在管状数据中非常常见,在本文中,我们将讨论如何对它们进行编码的一些想法,尤其是那些具有高基数和已知长度的IP地址,移动号码等

图2:本文中作为运行示例使用的示例表格数据

处理分类列的传统方法是对它们进行one-hot编码。图2中的编码浏览器列将会变成

图3:one-hot编码的浏览器列会产生与其基数相等的额外列

该浏览器列被扩展到4列,其等于其基数。这里列的基数意味着列中唯一值的数量,在这种情况下为4,Chrome,Firefox,Safari和Edge。

以同样的方式对IP地址列进行单热编码可能会导致数百万行的实际情况,因为从理论上讲,IP地址的基数超过429亿。编码这种高基数列的三种方法是:

Bucketing or HashingCharacter EncodingEmbeddingsBucketing或Hashing

这是一种常用的减少基数的技术。我们的想法是设计一个函数f,它接收一个IP地址并返回一个数字。问题是,f应该只返回一组固定的数字/Buckets。Buckets的数量通常是f的一个参数,而且所有可能的IP地址都应该以某种方式映射到一个固定的Buckets的数量。由于Buckets的数量可以选择为相当小的,因此可以像在浏览器列中那样进行one-hot编码。

图3:将IPv4地址散列到固定数量的Buckets

上述方法通过限制Buckets的数量来减少基数。但是,如果f没有考虑基础数据分布,那么映射到每个存储Bucket的IP地址数量可能会有很大差异。由于编码引入数据偏斜会影响ML算法的性能。因此,f的目标不仅是将每个IP地址映射到一个存储Bucket,还包括如何尽可能保持原始数据分布。

f的另一个重要要求是一致性。无论何时和多少次被调用,相同的IP地址应映射到同一个存储Bucket。很容易看出为什么它是必需的,因为ML算法将仅使用编码对数据进行建模。

字符编码(Character Encodings)

如上所述设计最佳散列函数有时可能是有挑战性的。但是,在IP地址的情况下,其数字中存在固有的结构。除了其结构的核心网络和子网原因之外,还声称可以从IP地址估计地理位置。使用这些提示f可以通过编码每个字符来设计。

图4:通过填充零的每个部分将IPv4地址扩展为固定的12个字符

如图4所示,尽管IP地址列的基数很大,但在IPv4的情况下,每个字符/数字的基数仅为10。使用这个事实,每个数字可以是一个one-hot编码,只得到10 * 12 = 120列,而不是数百万。这可以类似于IPv6的扩展,并且可以用几行Python代码来实现,

def transform_ip(ip):

"""

If IPv4, equalizes each group and left zero pads to match IPv6 length

If IPv6, converts all to lower case

"""

IPV6_LENGTH = 39

IPV4_GROUP_LENGTH = 3 # each group in IPv4 is of this length

if len(ip) < IPV6_LENGTH:

# IPv4 address

groups = ip.split( "." )

equalize_group_length = "".join( map( lambda group: group.zfill(3), groups ))

left_pad_with_zeros = list( equalize_group_length ).zfill( IPV6_LENGTH )

return left_pad_with_zeros

else:

return list(ip.lower())

transform_ip 通过均衡IPv4中的每个组的IPv4和IPv6地址长度以及零填充来对IP地址执行一些预处理,以使所有4组长度为3。

from sklearn.preprocessing import CategoricalEncoder

def one_hot_ip(df):

"""

Converts the ipAddress column of pandas DataFrame df, to one-hot

Also returns the encoder used

"""

enc = CategoricalEncoder()

ip_df = df.ipAddress.apply( lambda ip: transform_ip(ip) ).apply( pd.Series ) # creates separate columns for each char in IP

X_ip = enc.fit_transform( ip_df ).toarray()

return X_ip, enc

使用scikit-learn的CategoricalEncoder类,每一个字符/数字编码到10类中的一个(在短短的IPv4的情况下)。截至今日,CategoricalEncoder尚未发布,可直接从其源代码安装,

pip install git+git://github.com/scikit-learn/scikit-learn.git

以这种方式编码满足理想f的所有3个属性——保持数据分布,一致,编码所有可能的IP地址。类似的技术可以应用于任何高基数的非数值固定长度列。但是,如果这些字符串x基数的长度仍然很大,嵌入(Embeddings)技术是一种选择。

嵌入(Embeddings)

按照上面的描述,对每个字符进行编码可以破坏维度的数量。此外,它也不一定总是表达列中条目之间的隐藏关系。如在餐馆和地点的数据库中,纽约的编码(通过某种距离度量)更接近波士顿,而不是旧金山,那就更好了,因为纽约比旧金山更接近波士顿。地理距离只是餐馆数据库的一个方面。可以是地点,生活方式,食物种类等模式。手工设计一个可以编码城市的功能,根据数据集捕捉这些潜在的特征是非常具有挑战性的。

进入深层神经网络

由于分类变量之间的关系(如New York & Boston)基于数据集的变化,它们的编码/嵌入与其他模型参数一起被训练。这样做,每个分类变量的表示/编码都是在问题的背景下学习的。

为了更好地理解,假设问题是预测给定IP地址和浏览器列的持续时间列,如图2所示。而且为了简单起见,只有IP地址是用嵌入来编码的,而浏览器只是像上面一样的one-hot编码。

如上图所示,一个嵌入矩阵的shape (Cardinality of IP Address column, # Latent Features)是随机初始化的,它是由一个优化算法,比如梯度下降,用成本函数进行的,就像其他模型参数一样。潜在特征是代表分类变量的各种特征的数值。在这里,神经网络被要求找出IP地址的12个特征(我们不一定理解)。除了one-hot编码的浏览器特性外,它们还被作为深层神经网络的输入。通过这种方式,可以学习更精确的IP地址的上下文表示(而不是手工编码),这比one-hot或基于字符的编码技术更紧凑。

结论

给出了三种不同的非数值编码方法。one-hot编码是最简单的,如果基数很小,则可以很好地工作。Bucketing 通过减少基数来解决这个问题,但是如果不小心,可能会引入不需要的数据倾斜。字符编码(Character encoding)利用每个字符的低基数和要编码的字符串的固定长度性质,解决了基数问题。对于某些扩展领域知识,需要确保这种编码是否适用。Embeddings 将完全编码的责任推给神经网络。免费获得更高的质量和紧凑的潜在特征。但是,这需要像分类问题一样对问题进行建模,并且可能需要大量的数据,因为神经网络需要更多的参数进行调优。因此,基于用例,选择正确的策略来编码分类数据并获得机器学习的巨大好处!

标签: #算法编码方式