Dan*_*anP 5 c# vb.net statistics cluster-analysis
假设我有一个事件的班次列表(格式为开始日期/时间,结束日期/时间) - 我是否可以使用某种算法来创建日程安排的概括?大多数轮班经常会出现某种常见的复发模式(即周一从上午9:00到下午1:00,周二从上午10:00到下午3:00等).但是,这条规则可以(并且将会是)例外(例如,其中一个班次在假期降低,并在第二天重新安排).将我的"摘要"中的内容排除在外是可以的,因为我希望提供一个更一般的答案,说明此事件通常何时发生.
我想我正在寻找某种统计方法来确定日期和时间,并根据列表中发现的最常见事件创建描述.对于像这样的东西,有某种通用算法吗?有没有人创造类似的东西?
理想情况下,我正在寻找C#或VB.NET的解决方案,但不介意从任何其他语言移植.
提前致谢!
Dr.*_*ius 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
Run Code Online (Sandbox Code Playgroud)
现在我们加入数据,获得一个大数据集:
data = Join[monshft1, monshft2, wedshft1, wedshft2, frishft1, frishft2, monexcp];
Run Code Online (Sandbox Code Playgroud)
让我们对数据进行聚类分析:
clusters = FindClusters[data, 7, Method->{"Agglomerate","Linkage"->"Complete"}]
Run Code Online (Sandbox Code Playgroud)
"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"}]
Run Code Online (Sandbox Code Playgroud)
结果是:
alt text http://i28.tinypic.com/2hmdlab.png
在那里你可以清楚地看到我们的七个星团.
这解决了部分问题:识别数据.现在你也希望能够标记它.
所以,我们将获得每个集群并采取手段(四舍五入):
Table[Round[Mean[clusters[[i]]]], {i, 7}]
Run Code Online (Sandbox Code Playgroud)
结果是:
Day Start End
{"1", "10", "15"},
{"1", "12", "17"},
{"3", "10", "15"},
{"3", "14", "17"},
{"5", "10", "15"},
{"5", "11", "15"},
{"1", "7", "9"}
Run Code Online (Sandbox Code Playgroud)
随之而来的是你的七个班级.
现在,也许你想要对这些变化进行分类,无论白天.如果同一个人每天在同一时间完成相同的任务,那么将它称为"星期一从10变为15"是没有用的,因为它也发生在Weds和Fridays(如我们的例子中).
让我们分析一下无视第一列的数据:
clusters=
FindClusters[Take[data, All, -2],Method->{"Agglomerate","Linkage"->"Complete"}];
Run Code Online (Sandbox Code Playgroud)
在这种情况下,我们不会选择要检索的群集数量,而是将决策留给包裹.
结果是
图片http://i27.tinypic.com/mise9.png
您可以看到已识别出五个群集.
让我们像以前一样"标记"它们:
Grid[Table[Round[Mean[clusters[[i]]]], {i, 5}]]
Run Code Online (Sandbox Code Playgroud)
结果是:
START END
{"10", "15"},
{"12", "17"},
{"14", "17"},
{"11", "15"},
{ "7", "9"}
Run Code Online (Sandbox Code Playgroud)
这正是我们"怀疑"的原因:每天都有重复的事件可以同时组合在一起.
如果你有(或计划有)从一天开始并在下面结束的轮班,那么建模更好
{Start-Day Start-Hour Length} // Correct!
Run Code Online (Sandbox Code Playgroud)
比
{Start-Day Start-Hour End-Day End-Hour} // Incorrect!
Run Code Online (Sandbox Code Playgroud)
这是因为与任何统计方法一样,变量之间的相关性必须明确,否则方法会失败.原则可能会像"保持候选人数据规范化"之类的.这两个概念几乎相同(属性应该是独立的).
---编辑结束---
到目前为止,我猜你很清楚,如果分析你可以用这种方法做什么.
HTH!