在单个特征中保留订单信息

preserving order information in a single feature

以下是我尝试添加特征工程师的数据集的一列:

+---+-----------------------------+
|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,按日期消化每一行。我想通过将订单信息添加到现有模型来尝试改进我的预测。

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

+---+-----------------------------+
|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         |
+---+--------------------------------------------------+

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

一种选择是通过创建有意义的映射 1 --> 1(即一对一)直接 translate/transform 字符串。 在这种情况下,保序是可行的,也是有意义的。

这是一个简单的演示:

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,它的主要工作是记住并选择性地忘记步骤和步骤顺序!