我正在开展一个小项目,用户可以在其中创建事件(例如Eat
,Sleep
,Watch a movie
等),并记录与这些事件匹配的日志条目。
我的数据模型看起来像这样(应用程序本身在Python 3 / Django中,但我认为这不重要):
# a sample event
event = {
'id': 1,
'name': 'Eat',
}
# a sample entry
entry = {
'event_id': event['id'],
'user_id': 12,
# record date of the entry
'date': '2017-03-16T12:56:32.095465+00:00',
# user-given tags for the entry
'tags': ['home', 'delivery'],
# A user notation for the entry, it can be positive or negative
'score': 2,
'comment': 'That was a tasty meal',
}
用户可以为任意数量的事件记录任意数量的条目,他们可以在需要时创建新事件。数据存储在关系数据库中。
现在,我想通过在用户访问"添加条目"时建议相关事件,使用户更容易输入数据。形成。目前,他们可以在下拉列表中选择与其输入相对应的事件,但我想在此基础上向他们建议一些相关事件。
我认为,鉴于用户历史记录(所有记录的条目),应该可以通过识别条目中的模式来预测可能的输入,例如:
Eat
通常每天,中午和晚上7点发生Sleep
通常在晚上10点之后发生Watch a movie
通常发生在星期五晚上8:00之后理想情况下,我喜欢一个函数,给定用户ID和日期时间,并使用用户历史记录,将返回更有可能发生的事件列表:
def get_events(user_id, datetime, max=3):
# implementation
# returns a list of up to max events
return events
因此,如果我采用前面的示例(具有更多人类日期),我将得到以下结果:
>>> get_events(user_id, 'Friday at 9:00 PM')
['Watch a movie', 'Sleep', 'Eat']
>>> get_events(user_id, 'Friday at 9:00 PM', max=2)
['Watch a movie', 'Sleep']
>>> get_events(user_id, 'Monday at 9:00 PM')
['Sleep', 'Eat', 'Watch a movie']
>>> get_events(user_id, 'Monday at noon')
['eat']
当然,在现实生活中,我会传递真实的日期时间,并且我想获得一个事件ID,以便我可以从数据库中获取相应的数据。
(对不起,如果需要一些时间来解释整个事情)
我的实际问题是,实现此目的所需的实际算法/工具/库是什么?它甚至可以吗?
我目前的猜测是,我需要使用一些花哨的机器学习东西,使用像scikit-learn和classifiers这样的东西,用它来提供用户历史来训练它,然后让整个事情去做它的魔力
我对机器学习一点也不熟悉,我担心自己没有足够的数学/科学背景来开始学习。你能给我一些参考资料,帮助我理解如何解决这个问题,我需要深入研究的算法/词汇,还是一些伪代码?
答案 0 :(得分:2)
我认为k-nearest neighbours(kNN)方法将是一个很好的起点。在这种特定情况下的想法是寻找最接近给定时间发生的 k 事件,并计算最常发生的事件。
实施例
假设您有输入
Friday at 9:00 PM
。占据所有距离 数据库中的事件到此日期并按升序排列。 例如,如果我们以分钟为单位考虑所有元素的距离 数据库,一个示例排名可以如下。('Eat', 34) ('Sleep', 54) ('Eat', 76) ... ('Watch a movie', 93)
接下来,您将获取第一个 k = 3 并计算它们的频率 发生,
('Eat', 2) ('Sleep', 1)
以便函数返回
['Eat', 'Sleep']
(按此顺序)。
选择好的 k 非常重要。太小的值将允许意外异常值(在特定时刻执行一次)对结果产生很大影响。选择 k 太大将允许计数中包含不相关的事件。缓解这种情况的一种方法是使用距离加权kNN(见下文)。
正如评论中所提到的,使用两个时间戳之间的简单距离可能会丢失一些信息,例如星期几。我们可以通过使距离函数d(e1, e2)
稍微复杂来解决这个问题。在这种情况下,我们可以选择它作为时间和星期几之间的权衡,例如
d(e1, e2) = a * |timeOfDay(e1) - timeOfDay(e2)| * (1/1440) +
b * |dayOfWeek(e1) - dayOfWeek(e2)| * (1/7)
我们将两个差异标准化为一天(以分钟为单位)的时间与一周中的几天之间的最大差异。 a
和b
是可用于对这些差异之一赋予更多权重的参数。例如,如果我们选择a = 3
和b = 1
,我们说在同一天发生的重要性比同时发生的重要性高三倍。
您可以通过不仅仅选择 k 最近的元素,而是根据给定点的距离为所有事件指定权重(例如距离)来提高复杂性(并希望性能)。让e
作为输入示例,o
是数据库中的示例。然后我们将o
的权重计算为e
1
w_o = ---------
d(e, o)^2
我们发现点的减重速度比e
增加的距离快。在您的情况下,然后从最终排名中选择许多元素。这可以通过对相同事件的权重求和来计算事件类型的最终排名来完成。
关于kNN的好处是它很容易实现。您将大致需要以下组件。
d(e1, e2)
的实现。根据此函数和给定的输入示例对数据库中的所有元素进行排名的函数。
def rank(e, db, d):
""" Rank the examples in db with respect to e using
distance function d.
"""
return sorted([(o, d(e, o)) for o in db],
key=lambda x: x[1])