假设我有一个事件的班次列表(格式为开始日期/时间,结束日期/时间) - 是否有某种算法可用于创建日程安排的概括?大多数轮班经常会出现某种常见的复发模式(即周一从上午9:00到下午1:00,周二从上午10:00到下午3:00等)。但是,这条规则可以(并且将会是)例外(例如,其中一个班次在假期降低,并在第二天重新安排)。从我的“摘要”中排除这些内容会很好,因为我希望提供一个更通用的答案,说明此事件通常何时发生。
我想我正在寻找某种统计方法来确定出现的日期和时间,并根据列表中最常见的出现次数创建描述。对于像这样的东西,有某种通用算法吗?有没有人创造过类似的东西?
理想情况下,我在寻找C#或VB.NET的解决方案,但不介意从任何其他语言移植。
提前致谢!
答案 0 :(得分:11)
您可以使用Cluster Analysis。
群集是一种将一组数据分离为类似组件(子集)的方法。 “相似性”概念涉及点之间“距离”的某种定义。存在许多通常的距离公式,其中包括通常的欧几里德距离。
在向您指出交易的怪癖之前,让我们为您的问题展示一个实际案例,这样您就可以参与算法和软件包,或者提前将它们丢弃。
为了方便起见,我在Mathematica中对问题进行了建模,因为Cluster Analysis包含在软件中并且非常简单易于设置。
首先,生成数据。格式为{DAY,START TIME,END TIME} 开始和结束时间添加了一个随机变量(+半小时,零,半小时),以显示算法处理“噪音”的能力。
有三天,每天三班,一个额外(最后一个)“异常”班次,从上午7点开始,到上午9点结束(可怜的家伙!)。
每个“正常”班次有150个事件,而在特殊班次中只有两个。
正如您所看到的,一些变化并不是很远。
我将代码包含在Mathematica中,以防您有权访问该软件。我试图避免使用函数语法,使代码更容易阅读“外国人”。
以下是数据生成代码:
Rn[] := 0.5 * RandomInteger[{-1, 1}];
monshft1 = Table[{ 1 , 10 + Rn[] , 15 + Rn[] }, {150}]; // 1
monshft2 = Table[{ 1 , 12 + Rn[] , 17 + Rn[] }, {150}]; // 2
wedshft1 = Table[{ 3 , 10 + Rn[] , 15 + Rn[] }, {150}]; // 3
wedshft2 = Table[{ 3 , 14 + Rn[] , 17 + Rn[] }, {150}]; // 4
frishft1 = Table[{ 5 , 10 + Rn[] , 15 + Rn[] }, {150}]; // 5
frishft2 = Table[{ 5 , 11 + Rn[] , 15 + Rn[] }, {150}]; // 6
monexcp = Table[{ 1 , 7 + Rn[] , 9 + Rn[] }, {2}]; // 7
现在我们加入数据,获得一个大数据集:
data = Join[monshft1, monshft2, wedshft1, wedshft2, frishft1, frishft2, monexcp];
让我们对数据进行聚类分析:
clusters = FindClusters[data, 7, Method->{"Agglomerate","Linkage"->"Complete"}]
“聚集”和“联系” - > “完成”是Mathematica中实现的聚类方法的两个微调选项。他们只是指出我们正在努力寻找非常紧凑的集群。
我指定尝试检测7个群集。如果正确的移位数未知,您可以尝试几个合理的值并查看结果,或让算法选择更合适的值。
我们可以得到一个包含结果的图表,每个群集都有不同的颜色(不介意代码)
ListPointPlot3D[ clusters,
PlotStyle->{{PointSize[Large], Pink}, {PointSize[Large], Green},
{PointSize[Large], Yellow}, {PointSize[Large], Red},
{PointSize[Large], Black}, {PointSize[Large], Blue},
{PointSize[Large], Purple}, {PointSize[Large], Brown}},
AxesLabel -> {"DAY", "START TIME", "END TIME"}]
结果是:
alt text http://i28.tinypic.com/2hmdlab.png
你可以清楚地看到我们的七个星团分开。
这解决了部分问题:识别数据。现在你也希望能够标记它。
因此,我们将获得每个集群并采取方法(四舍五入):
Table[Round[Mean[clusters[[i]]]], {i, 7}]
结果是:
Day Start End
{"1", "10", "15"},
{"1", "12", "17"},
{"3", "10", "15"},
{"3", "14", "17"},
{"5", "10", "15"},
{"5", "11", "15"},
{"1", "7", "9"}
然后你再次获得七个班级。
现在,也许你想要对这些变化进行分类,无论白天。如果同一个人每天在同一时间完成相同的任务,那么将它称为“星期一从10变为15”是没有用的,因为它也发生在Weds和Fridays(如我们的例子中)。
让我们分析一下无视第一栏的数据:
clusters=
FindClusters[Take[data, All, -2],Method->{"Agglomerate","Linkage"->"Complete"}];
在这种情况下,我们不会选择要检索的群集数量,而是将决定留给包裹。
结果是
image http://i27.tinypic.com/mise9.png
您可以看到已识别出五个群集。
让我们像以前一样“标记”它们:
Grid[Table[Round[Mean[clusters[[i]]]], {i, 5}]]
结果是:
START END
{"10", "15"},
{"12", "17"},
{"14", "17"},
{"11", "15"},
{ "7", "9"}
这正是我们“怀疑”的原因:每天都有重复的事件可以组合在一起。
如果你有(或计划有)从一天开始并在下面结束的班次,最好建模
{Start-Day Start-Hour Length} // Correct!
比
{Start-Day Start-Hour End-Day End-Hour} // Incorrect!
这是因为与任何统计方法一样,变量之间的相关性必须明确,否则方法会失败。原则可能会像“保持候选人数据规范化”之类的。这两个概念几乎相同(属性应该是独立的)。
---编辑结束---
到现在为止,我猜你很清楚,如果分析,你可以用这种方式做什么。
答案 1 :(得分:1)
我不认为任何现成的算法存在,所以不幸的是你需要自己想出一些东西。因为这个问题没有得到很好的定义(从数学的角度来看),所以需要测试一些具有合理代表性的“真实”数据,并进行相当多的调整。
我会从将工作日划分为工作日开始(因为如果我理解正确,你是在每周观看之后) - 所以对于每个工作日我们都会在当天进行轮班。然后,对于每一天,我会将同时发生的变化分组(或“大致”同时发生 - 在这里你需要提出一些启发式,即开始和结束时间都不会偏离组中的平均值。超过15分钟或30分钟)。现在我们需要另一种启发式方法来决定这个群体是否相关,即如果一个星期一下午1点到3点的班次只发生一次它可能不相关,但如果它发生在至少70%的周一数据所涵盖的那么它是相关。现在,您每周每天的相关小组将形成您所追求的时间表。
答案 2 :(得分:0)
我们能看到一个示例数据集吗?如果它真的是“干净”的数据,那么你可以简单地找到开始和结束时间的模式。
答案 3 :(得分:0)
一个选项是将所有开始时间标记为+1,结束时间标记为-1,然后创建三列时间表(开始和结束),标签(+1或-1)和数量当时的工作人员(从零开始,使用标签添加或减去工作人员)并按时间顺序对整个事项进行排序。
此时间序列现在是您的员工级别的摘要描述符,标签也是一系列。现在,您可以应用时间序列统计信息来查找每日,每周或每月模式。