【问题标题】:preserving order information in a single feature在单个特征中保留订单信息
【发布时间】:2020-07-28 10:47:36
【问题描述】:

以下是我正在尝试进行特征工程师的数据集的一列:

+---+-----------------------------+
|Id |events_list                  |
+---+-----------------------------+
|1  |event1,event3,event2,event1  |
+---+-----------------------------+
|2  |event3,event2                |
+---+-----------------------------+

有 3 种可能的事件类型,它们到达的顺序保存为字符串。 我已经像这样转换了事件列:

+---+--------------------+
|Id |event1|event2|event3|
+---+--------------------+
|1  |2     |1     |1     |
+---+--------------------+
|2  |0     |1     |1     |
+---+--------------------+

保留计数信息但丢失订单信息。

问:有没有办法将订单编码为特征?

更新:对于我计算当天的每一行事件的分数,模型应该预测新的日常事件的未来分数。无论如何,我的事件顺序和计数会影响每日得分。

更新:我的数据集包含其他日常信息,例如会话计数等,目前我的模型是按日期消化每一行的 LSTM。我想通过将订单信息添加到现有模型来尝试改进我的预测。

【问题讨论】:

标签: machine-learning dataset feature-engineering


【解决方案1】:

一种选择是通过创建有意义的映射 1 --> 1(即一对一)直接翻译/转换字符串。 在这种情况下,保持顺序是可行的并且是有意义的。

这是一个简单的演示:

data = ['event1,event3,event2,event1', 'event2,event2', 'event1,event2,event3']

def mapper(data):
    result = []
    for d in data:
        events = d.replace(' ', '').split(',')
        v = 0
        for i, e in enumerate(events):
            # for each string: get the sum of char values,
            # normalized by their orders
            # here 100 is optional, just to make the number small
            v += sum(ord(c) for c in e) / (i + 100) 
        result.append(v)
    return result

new_data = mapper(data)
print(new_data)

输出:

[23.480727373137086, 11.8609900990099, 17.70393127548049]

虽然冲突概率非常低,但对于庞大的数据集,并不能 100% 保证完全没有冲突。

检查此分析:

# check for clashes on huge dataset
import random as r
import matplotlib.pyplot as plt

r.seed(2020)

def ratio_of_clashes(max_events):
    MAX_DATA = 1000000
    events_pool = [','.join(['event' + str(r.randint(1, max_events))
                         for _ in range(r.randint(1, max_events))])
                   for _ in range(MAX_DATA)]
    # print(events_pool[0:10])  # print few to see
    mapped_events = mapper(events_pool)
    return abs(len(set(mapped_events)) - len(set(events_pool))) / MAX_DATA * 100


n_samples = range(5, 100)
ratios = []
for i in n_samples:
    ratios.append(ratio_of_clashes(i))

plt.plot(n_samples, ratios)
plt.title('The Trend of Crashes with Change of Number of Events')
plt.show()

因此,您拥有的事件或数据越少,冲突率就越小,直到达到某个阈值,然后它就会变平——但它毕竟一点也不差(个人而言,我可以忍受)。


更新和最终想法:

我刚刚注意到您已经在使用 LSTM,因此顺序非常重要。在这种情况下,我强烈建议您将事件编码为整数,然后创建一个完全适合 LSTM 的时间序列,按照以下步骤操作:

  1. 预处理每个字符串并将它们拆分为事件(就像我在示例中所做的那样)。
  2. LabelEncoder 放在它们上面并将它们转换为整数。
  3. 通过拟合 MinMaxScaler 将结果缩放为 [0 - 1]。

你会得到这样的结果:

'event1':1

'event2' : 2

'event3' : 3

。 . .

'eventN' : N

对于 'event1,event3,event2,event3',它将变为:[1, 3, 2, 3]。 缩放 --> [0, 1, 0.5, 1]。

然后,LSTM 能够自然地计算出顺序。并且忘记维度点,因为它是 LSTM,它的主要工作是记住和选择性地忘记步骤和步骤的顺序!。

【讨论】:

  • 感谢您的回复,那么这是否意味着'event1,event2' == 'event2,event1' 因为它们的总和相同?
  • @ShlomiSchwartz 不客气,Shlomi。关于您的问题:不,它们肯定会有所不同(11.850、11.851)。但是,我们假设事件在一个角色上有所不同(这不太现实,尽管结果是独一无二的),但实际上,我认为您的事件有不同的名称,对吧?
  • 非常聪明的主意!如果我理解正确,“魔术”就是将总和除以事件的索引,对吗?
  • @ShlomiSchwartz 没错,总和只是为了得到事件的相对唯一表示,稍后按事件的顺序归一化那个序列。结果,每个序列将根据事件、它们的数量和它们的顺序转换为一个唯一的数值。最后一件事,请不要忘记在最后将数据归一化/标准化,然后再将它们扔给 LSTM(作为一般方法)。
  • @ShlomiSchwartz amount 信息已包含在内。例如,10 个事件的序列被映射为比 3 个事件序列更大的值。但是,如果两个序列的长度非常接近(例如 9 和 10),我会看到您的观点,在这种情况下,如果您想通过每个序列的 events 数量进行标准化(这确实是一个非常有效的观点),然后您需要在末尾将 sequence 除以 / len(events),如下所示:result.append(v / len(events))。在这种情况下,序列通过每个序列的信息量进行归一化。
【解决方案2】:

一种可能性可能是一系列向量,表示在nth 事件之前发生的事件。 n 是可以发生的最大事件数,向量长度是可能的事件数。这会将事件的顺序隐式编码到固定大小的特征空间中。

+---+-----------------------------+
|Id |events_list                  |
+---+-----------------------------+
|1  |event1,event3,event2,event1  |
+---+-----------------------------+
|2  |event3,event2                |
+---+-----------------------------+



+---+--------------------------------------------------+
|Id | events_1  events_2  events_3  events_4  events_5 |
+---+--------------------------------------------------+
|1  | [1,0,0]   [1,0,1]   [1,1,1]   [2,1,1]   [2,1,1]  |
+---+--------------------------------------------------+
|2  | [0,0,1]   [0,1,1]   [0,1,1]   [0,1,1]   [0,1,1]  |
+---+--------------------------------------------------+

具有相同信息的更少特征维度,将记录在事件步骤发生的事件,n

+---+--------------------------------------------------+
|Id | event_1  event_2  event_3  event_4  event_5      |
+---+--------------------------------------------------+
|1  |   1         3        2        1        0         |
+---+--------------------------------------------------+
|2  |   3         2        0        0        0         |
+---+--------------------------------------------------+

这具有较少的维度,这是好的,但可能存在未显式编码最终状态的缺点。对问题本身或您打算使用哪种模型一无所知,很难知道这是否重要。

【讨论】:

  • 感谢您的回复,不幸的是,如果一行有 1000 个事件,而其他行只有 2 个事件,那么列数将全部为 1000。
  • 是的,确实如此,但可能存在对每一行的固定大小特征空间的要求,具体取决于您的模型?除非您使用的是循环神经网络或其他东西?但如果是这样的话,我怀疑你会问这样的问题。向我们提供有关问题和约束以及您要使用的模型的更多具体信息,也许可以针对您的情况举一个更具体的示例。
猜你喜欢
  • 2018-07-11
  • 2023-03-18
  • 1970-01-01
  • 1970-01-01
  • 2021-11-28
  • 1970-01-01
  • 2018-09-13
  • 2012-01-24
  • 2019-08-23
相关资源
最近更新 更多