循环浏览数据范围列表,以返回带有固定质心的K均值群集的矩阵



这是我的第二篇文章,假设它早于第一个,我将在此处链接:

在r

中创建一个用两个用于循环的矩阵/dataFrame

我不会重复我在那里犯的新手错误,所以您可以在这里使用数据副本:

 > dput(head(dfn,1))
structure(c(-0.936707666207839, 0.684585833497428, -1.15671769161442, 
-0.325882814790034, 0.334512025995239, 0.335054315282587, 0.0671142954097706, 
-0.544867778136127, -0.958378799317135, 1.26734044843021, -0.483611966400142, 
-0.0781514731365092, -0.671994127070641, 0.332218249471269, 0.942550991112822, 
0.15534532610427, 0.192944412985922, 0.206169118270958, 0.424191119850985, 
-0.193936625653784, -0.574273356856365, -0.176553706556564, 0.696013509222779, 
0.118827262744793, 0.0649996884597108, 0.470171960447926, -0.570575475596488, 
0.336490371668436, 0.475005575251838, 0.010357165551236, 0.284525279467858, 
0.523668394513643, -0.0290958105736766, 0.62018540798656, 1.37452329937098, 
0.456726128895017), .Dim = c(1L, 36L), .Dimnames = list(NULL, 
    c("2015-01-30", "2015-02-27", "2015-03-31", "2015-04-30", 
    "2015-05-29", "2015-06-30", "2015-07-31", "2015-08-31", "2015-09-30", 
    "2015-10-30", "2015-11-30", "2015-12-31", "2016-01-29", "2016-02-29", 
    "2016-03-31", "2016-04-29", "2016-05-31", "2016-06-30", "2016-07-29", 
    "2016-08-31", "2016-09-30", "2016-10-31", "2016-11-30", "2016-12-30", 
    "2017-01-31", "2017-02-28", "2017-03-31", "2017-04-28", "2017-05-31", 
    "2017-06-30", "2017-07-31", "2017-08-31", "2017-09-29", "2017-10-31", 
    "2017-11-30", "2017-12-29")))

这是一个417行的时间序列数据库,带有36个时间帧(过去3年的每个月(。

这是我用来创建数据范围列表的代码:

ProgrSubset <- function(x,i) { x[,i:sum(i,11)] }
dfList <- lapply(1:25, function(x) ProgrSubset(dfn, x) )
然后,

dflist是25个数据范围的列表,由12个月的滚动窗口从原始窗口取代。

现在,我想在列表的每个数据框架上运行k-means算法,并将每次迭代的群集编号存储在一个名为it_mat的矩阵中。

但这是悲伤,我希望质心成为上一跑的人(如果第一次固定在第一次运行中,那将是很棒的(。

我没有问题"手":

it_mat <- cbind(ref_data$sec_id)
k = 18
cl <- kmeans(dfList[[1]], centers = k, nstart = 10)
it_mat <- cbind(it_mat, cl$cluster)
head(it_mat) #first iteration
colnames(cl$centers) <- colnames(dfn[,2:13])
k <- cl$centers
cl <- kmeans(dfList[[2]], centers = k, nstart = 10)
it_mat <- cbind(it_mat, cl$cluster)
head(it_mat) #second iteration

应该直接通过数据库列表循环循环,但这是一个没有显示的内容:我设计的for循环仅返回一个只有第一个迭代的矩阵:

it_mat <- cbind(ref_data$sec_id)
for(i in 1:25){
    if(i == 1){
        k = 18
        cl <- kmeans(dfList[[i]], centers = k, nstart = 10)
        it_mat <- cbind(it_mat, cl$cluster)
    }else{
        colnames(cl$centers) <- colnames(dfn[,i:i+11])
        k = cl$centers
        cl <- kmeans(dfList[[i]], centers = k, nstart = 10)
        it_mat <- cbind(it_mat, cl$cluster)
    }
}

也许在错误之后停止: Error: empty cluster: try a better set of initial centers

,但我不在乎群集是否为空。

我还尝试循环第一个之后的后续迭代,以使其在没有ifelse的情况下变得更简单:

for(i in 2:25){
    colnames(cl$centers) <- colnames(dfn[,2:13])
    k <- cl$centers
    cl <- kmeans(dfList[[i]], centers = k, nstart = 10)
    it_mat <- cbind(it_mat, cl$cluster)
}

仍然相同的结果:仅具有第一次迭代的矩阵。

我还尝试使用it_mat[ ,i] <- cl$cluster而不是it_mat <- cbind(it_mat, cl$cluster),但它是相同的。

我会感谢您的任何帮助,评论或建议:我可能会犯一些非常愚蠢的错误,例如我上一个问题,或者我选择了一条非常困难的道路,使我的工作变得复杂。

我的主要目标是了解簇构图如何在某些时间序列中变化。

谢谢大家的时间。

这是一种方法,尽管我无法与您的小数据集和k一起使用。也许它可以通过您的实际数据更好。如果您不想知道为什么/如何工作,请跳至 tl; dr

使用Reduce

我正在使用的技巧是Reduce,其第一个参数是带有两个参数的函数。它的一个微不足道的演示是:

Reduce(function(a,b) 2*a+b, 1:4)

这相当于2*1+2,然后是2*(2*1+2)+3等。也许以其当前形式不鼓励。让我们打印一些打印,然后"累积"数据:

Reduce(function(a,b) {
  cat(paste(c(a,b), collapse=","), "n")
  return(2*a+b)
}, 1:4, accumulate=TRUE)
# 1,2 
# 4,3 
# 11,4 
# [1]  1  4 11 26

o,该函数的第一个调用将取决于向量1和第二个元素2的第一个元素,并调用该函数。然后,它将返回的值(2*1+24(和向量3的第三个元素,并具有魔术。等等。

使用Reduce时通常做出的一个"假设"是两个值必须是对象的"类型"。这不需要,所以我会欺骗一些事情。

要注意的另一件事是,它是从列表的前两个元素开始的,这也不是严格的要求。如果我们设置了init,我们可以控制第一个呼叫上的a

Reduce(function(a,b) {
  cat(paste(c(a,b), collapse=","), "n")
  return(2*a+b)
}, 1:4, init=99, accumulate=TRUE)
# 99,1 
# 199,2 
# 400,3 
# 803,4 
# [1]   99  199  400  803 1610

请注意,仅在一个函数调用中使用列表中的每个元素?

添加kmeans

因此,我的技术是考虑我们想要的函数n呼叫的内容:我们希望从n-1n数据中使用先前的群集对象。意识到"以前的群集对象" 在上一个示例中看起来很像199、400和803。我们将编写一个假设上一个群集对象的函数是第一个参数,并且数据是第二个参数。

my_cascade_kmeans <- function(prevclust, dat) {
  kmeans(dat, centers = prevclust$centers, nstart = 10)
}
Reduce(my_cascade_kmeans, dfList, accumulate = TRUE)

(顺便说一句:我正在收集整个群集输出,而不仅仅是中心,因为我们最终想获得群集对象的列表。(

您会很快发现(并回想起来(的问题是,这是第一次称为前两个元素。因此,我们要声明初始值。处理这一点的两种方法:

  1. Reduce(my_cascade_kmeans, dfList, init=list(centers=5), accumulate=TRUE)

    这是利用kmeans的群集对象和静态list(centers=5)都可以用$centers索引的便利性,并且它们返回我认为我们需要的东西。

  2. Reduce(my_cascade_kmeans, dfList, init=NULL, accumulate=TRUE)

    为此,我们需要修改我们的功能以期望NULL中的CC_28并相应地处理。有时候可能会更好。

我更喜欢选项1,因为它在原始Reduce调用中放置了"默认的k值",而不一定埋在功能代码中。但是您可能更喜欢那里,而不是您。

对于此答案,我将初始簇从18减少到4 ...任何较高的东西,并且Error: empty cluster: try a better set of initial centers失败了,我猜这是由于截断的样本数据集。

TL; DR

my_cascade_kmeans <- function(prevclust, dat) {
  kmeans(dat, centers = prevclust$centers, nstart = 10)
}
clusters <- Reduce(my_cascade_kmeans, dfList, init = list(centers=4), accumulate = TRUE)
length(clusters)
# [1] 26

您可能会对这个问题进行balk态,但这是我们告诉它要做的:"通过将 list(centers=4)预先准备到开始,然后累积结果,然后累积结果" ,所以我们不要感到惊讶它比我们最初的。

clusters[[1]]
# $centers
# [1] 4

确认它。用

清洁
clusters <- clusters[-1]

现在clusters中的每个是使用以前的

kmeans(...)返回
clusters[[1]]
# K-means clustering with 4 clusters of sizes 2, 4, 3, 3
# Cluster means:
#         [,1]
# 1  0.9759631
# 2  0.1646323
# 3 -0.4514542
# 4 -1.0172681
# Clustering vector:
# 2015-01-30 2015-02-27 2015-03-31 2015-04-30 2015-05-29 2015-06-30 2015-07-31 2015-08-31 2015-09-30 2015-10-30 2015-11-30 
#          4          1          4          3          2          2          2          3          4          1          3 
# 2015-12-31 
#          2 
# Within cluster sum of squares by cluster:
# [1] 0.16980147 0.12635651 0.02552839 0.02940412
#  (between_SS / total_SS =  94.0 %)
# Available components:
# [1] "cluster"      "centers"      "totss"        "withinss"     "tot.withinss" "betweenss"    "size"         "iter"        
# [9] "ifault"      

在蛋糕上结冰,这也可以与2或2000个数据集一起使用。

最新更新