这篇文章主要关注一个不太为人所知的深度学习应用领域:结构化数据。本文由旧金山大学(USF)研究生KeremTurgutlu撰写。按照本文描述的步骤使用深度学习方法处理结构化数据具有以下好处:算法/方法。这就是为什么一些机器学习方法在解决某些任务之前需要大量特征工程的主要原因,例如图像分类、NLP和许多其他“非常规”数据处理——不能直接输入逻辑回归模型或随机森林的数据模型。相比之下,深度学习可以在这些类型的任务上取得良好的性能,而无需任何繁琐且耗时的特征工程。大多数时候,这些功能需要领域知识、创造力和大量的反复试验。当然,领域专业知识和复杂的特征工程仍然非常有价值,但本文将涵盖的技术足以让您在没有任何领域知识的情况下进入Kaggle竞赛的前3名,请参阅:http://blog.kaggle。com/2016/01/22/rossmann-store-sales-winners-interview-3rd-place-cheng-gui/图1:一只可爱的狗和一只愤怒的猫由于特征生成(如CNN卷层)复杂性质和能力,因此深度学习已广泛应用于图像、文本和音频数据的各种问题。这些问题对于人工智能的发展无疑是非常重要的,而这一领域的顶尖研究人员每年都在猫、狗、船的分类等任务上齐头并进,而且每年的成绩都比前一年好。但是我们很少在实际的行业应用中看到这一点。这是为什么?公司数据库涉及结构化数据,这些领域塑造了我们的日常生活。首先,让我们定义结构化数据。在结构化数据中,您可以将行视为收集的数据点或观察值,将列视为表示每个观察值的单个属性的字段。例如,来自在线零售商店的数据包含表示客户交易事件的列和包含有关购买的商品、数量、价格、时间戳等信息的列。下面我们有一些卖家数据,行代表每个单独的销售事件,列提供有关这些销售事件的信息。图2:结构化数据的pandasdataframe示例接下来我们讨论如何将神经网络用于结构化数据任务。事实上,在理论层面上,创建一个具有任何所需架构的全连接网络,然后使用“列”作为输入是很简单的。在损失函数经过一些点积和反向传播之后,我们将拥有一个训练有素的网络,可以进行预测。尽管看似简单,但在处理结构化数据时,人们往往更喜欢基于树的方法而不是神经网络。为什么?这可以从算法的角度来理解——算法究竟是如何对待和处理我们的数据的。人们处理结构化数据的方式与处理非结构化数据的方式不同。非结构化数据是“非常规的”,但我们通常处理的是单个实体的单位量,例如像素、体素、音频、雷达后向散射、传感器测量等。对于结构化数据,我们往往需要处理多种不同的数据类型;这些数据类型分为两类:数值数据和分类数据。分类数据需要在训练前进行预处理,因为包括神经网络在内的大多数算法都无法直接处理它们。编码变量有很多选项,例如标签/值编码和单热编码。但是这些技术在类层次结构的记忆和现实表示方面存在问题。内存问题可能更重要,让我们用一个例子来说明。假设我们专栏中的信息是星期几。如果我们使用单热或任意标签对该变量进行编码,那么我们必须分别假设级别之间的距离/差异相等且任意。图3:one-hotencoding和labelencoding但是这两种方法都假设每两天的差异是相等的,但是我们清楚地知道事实并非如此,我们的算法也应该知道这一点!“神经网络的连续性限制了它们对分类变量的应用。因此,用整数来表示分类变量,然后直接应用神经网络不会产生好的结果。”[1]基于树的算法不需要假设分类变量是连续的,因为它们可以根据需要分支以找到状态,但神经网络不是。实体嵌入可以帮助解决这个问题。实体嵌入可用于映射离散值进入一个多维空间,其中具有相似函数输出的值彼此更接近。例如,如果您要将省份嵌入国家空间以解决销售问题,那么在这个投影空间中,相似省份的销售额将更接近。由于我们不想在分类变量的层面上做任何假设,我们将为欧几里得空间中的每个类别学习更好的表示。这种表示只是单热编码和可学习权重的点积。嵌入在NLP中广泛使用,其中每个单词都可以表示为一个向量。Glove和word2vec是两种著名的嵌入方法。我们可以从图4[2]中看到嵌入的力量。只要符合您的目标,您就可以随时下载和使用这些载体;它实际上是表示它们包含的信息的好方法。图4:来自TensorFlow教程的word2vec虽然嵌入可以用于不同的上下文(无论是监督的还是非监督的),但我们的主要目标是了解如何为分类变量执行此映射。实体嵌入尽管人们对“实体嵌入”有不同的说法,但它们与我们看到的词嵌入用例并没有太大区别。毕竟,我们只关心分组数据的高维向量表示;这些数据可能是单词、星期几、国家等。这种从词嵌入到元数据嵌入(在我们的例子中是类别)的转换允许YoshuaBengio等人。使用简单的自动方法赢得2015年的Kaggle比赛——这通常无法赢得比赛。参见:https://www.kaggle.com/c/pkdd-15-predict-taxi-service-trajectory-i“为了处理由客户ID、出租车ID、日期和时间信息组成的离散元数据,我们共同学习了Embeddings对于使用模型的每条消息。这种方法的灵感来自于自然语言建模方法[2],其中每个词都映射到一个固定大小的向量空间(这个向量称为词嵌入)。[3]图5:可视化使用t-SNE2D投影的出租车元数据嵌入我们将逐步探索如何在神经网络中学习这些特征。定义一个完全连接的神经网络,然后分别处理数值变量和分类变量。对于每个分类变量:1.初始化一个随机嵌入矩阵mxD:m:分类变量的不同层数(星期一、星期二...)D:表示维度需要,它是一个超参数,可以取值从1到m-1(取1为labelencoding,取m为one-hotencoding)图6:嵌入矩阵2.然后,对于神经网络中的每个前向传递,我们都针对给定标签(比如“星期一”查询“道”)查询一次嵌入矩阵,这会产生一个1xD向量。图7:查找后的嵌入向量3.将这个1×D向量附加到我们的输入向量(数字向量)。您可以将此过程视为矩阵扩充,其中我们使用嵌入向量来扩充每个类,该向量是通过对每个特定行执行查找而获得的。图8:添加嵌入向量后4.在执行反向传播时,我们还以梯度方式更新这些嵌入向量以最小化我们的损失函数。输入通常不会更新,但嵌入矩阵有一种特殊情况,我们允许梯度流回这些映射特征,优化它们。我们可以将其视为使类别嵌入更好地代表每次迭代的过程。注意:根据经验,应保留基数不是很高的类别。因为如果某个变量的特定水平占观测值的90%,那么它就是一个没有很好预测价值的变量,我们最好避免使用它。好消息是,通过在我们的嵌入向量中执行查找并允许requires_grad=True并学习它们,我们可以在我们最喜欢的框架(最好是动态框架)中很好地实现上述架构。但Fast.ai已经实现了所有这些步骤,甚至更多。除了使结构化深度学习更容易之外,该库还提供了许多当前最先进的功能,例如微分学习率、SGDR、循环学习率、学习率查找等。这些都是我们可以利用的功能。您可以在以下博客中了解有关这些主题的更多信息:https://medium.com/@bushaev/improving-the-way-we-work-with-learning-rate-5e99554f163bhttps://medium.com/@surmenok/estimating-optimal-learning-rate-for-a-deep-neural-network-ce32f2556ce0https://medium.com/@markkhoffmann/exploring-stochastic-gradient-descent-with-restarts-sgdr-fa206c38a74e在Fast中实现。ai这部分,我们将介绍如何实现上述步骤,构建一个能够更高效处理结构化数据的神经网络。为此,我们将看看流行的Kaggle竞赛:https://www.kaggle.com/c/mercari-price-suggestion-challenge/。这是实体嵌入的一个完美示例,因为数据主要是分类数据并且基数相当高(不是太高),除此之外没有太多其他数据。data:约140万行item_condition_id:商品的状况(base:5)category_name:品类名称(base:1287)brand_name:品牌名称(base:4809)shipping:运费是否包含在价格中(base:2)重要注意:因为我已经找到了最好的模型参数,所以我不会在这个例子中包含验证集,但是你应该使用验证集来调整超参数。第一步:添加缺失值作为一个层次,因为缺失本身就是一个重要的信息。train.category_name=train.category_name.fillna('missing').astype('category')train.brand_name=train.brand_name.fillna('missing').astype('category')train.item_condition_id=train.item_condition_id。astype('category')test.category_name=test.category_name.fillna('missing').astype('category')test.brand_name=test.brand_name.fillna('missing').astype('category')测试。item_condition_id=test.item_condition_id.astype('category')第2步:预处理数据并按比例缩放和调整数值列,因为神经网络喜欢归一化数据。如果你不扩展你的数据,网络可能会过度关注一个特征,因为它只是点积和梯度。如果我们根据训练统计数据对训练数据和测试数据进行缩放会更好,但这应该影响不大。这就像将每个像素的值除以255,同理。因为我们希望相同的层具有相同的编码,所以我合并了训练和测试数据。combined_x,combined_y,nas,_=proc_df(combined,'price',do_scale=True)第3步:创建模型数据对象。路径是Fast.ai存储模型和激活的地方。path='../data/'md=ColumnarModelData.from_data_frame(path,test_idx,combined_x,combined_y,cat_flds=cats,bs=128第四步:确定D(嵌入维度),cat_sz是每个类别列的元素列表groups(col_name,cardinality+1).#WesaidthatD(dimensionofembedding)isanhyperparameter#ButhereisJeremyHoward'sruleofthumbemb_szs=[(c,min(50,(c+1)//2))for_,cincat_sz]#[(6,3),(1312,50),(5291,50),(3,2)]第五步:创建learner,这是Fast.ai库的核心对象。params:embeddingsizes,numberofnumericalcols,embeddingdropout,output,layersizes,layerdropoutsm=md.get_learner(emb_szs,len(combined_x.columns)-len(cats),第6步:这部分在我之前提到的另一篇文章中有更详细的解释。充分利用Fast.ai。在损失开始增加之前的某个时间,我们将选择我们的学习率...#findbestlrm.lr_find()#findbestlrm.sched.plot()图9:学习率与损失图拟合我们可以看到3个epoch之后,您将得到:lr=0.0001m.fit(lr,3,metrics=[lrmse])更合适的m.fit(lr,3,metrics=[lrmse],cycle_len=1)以及更多更多....m.fit(lr,2,metrics=[lrmse],cycle_len=1)因此,只需几分钟,无需进一步操作,这些简单但有效的步骤将使您达到大约10%的位置。如果你真的有更高的目标,我建议你使用item_description列并将其用作多个分类变量。那么就把工作交给entityembedding,当然也不要忘记堆叠和组合。参考文献[1]ChengGuo,FelixBerkhahn(2016,April,22)EntityEmbeddingsofCategoricalVariables。取自https://arxiv.org/abs/1604.06737。[2]TensorFlow教程:https://www.tensorflow.org/tutorials/word2vec[3]YoshuaBengio等。人工神经网络应用于出租车目的地预测。取自https://arxiv.org/pdf/1508.00021.pdf。
