【问题标题】:How to dynamically create variables and combine it to the dataframe in r?如何动态创建变量并将其组合到 r 中的数据框?
【发布时间】:2021-06-26 10:42:16
【问题描述】:

我正在为多个number of clusters 运行kmeans,然后尝试将cluster results 组合original dataframe

来自https://stats.stackexchange.com/questions/10838/produce-a-list-of-variable-name-in-a-for-loop-then-assign-values-to-the 的帖子我正在使用他们下面提到的代码来动态创建变量并根据我的需要进行修改。

上述帖子中的原始代码:

x <- as.list(rnorm(10000))
names(x) <- paste("a", 1:length(x), sep = "")
list2env(x , envir = .GlobalEnv)

现在将其应用于 iris 数据:

library(tidyverse)
library(ggthemes)
library(factoextra)

这在创建 3 个集群列表时效果很好:

# running for 1 to 3 clusters
lapply(1:3,

function(cluster_num){
  cluster_res_list <- as.list(kmeans(iris %>% select(-Species), cluster_num, nstart = 25)) 
  names(cluster_res_list) <- paste("iris_clus", 1:length(cluster_res_list), sep="_")
  list2env(cluster_res_list, envir = .GlobalEnv)
 
 # iris_df <- cbind(iris, cluster_res_list)
} )

问题:当我尝试将它们与原始数据集结合时出现错误:Error in as.data.frame.default(x[[i]], optional = TRUE, stringsAsFactors = stringsAsFactors) : cannot coerce class ‘"kmeans"’ to a data.frame

lapply(1:3,

function(cluster_num){
  cluster_res_list <- as.list(kmeans(iris %>% select(-Species), cluster_num, nstart = 25)) 
  names(cluster_res_list) <- paste("iris_clus", 1:length(cluster_res_list), sep="_")
  list2env(cluster_res_list, envir = .GlobalEnv)
 
  # to combine each cluster result to original df
  iris_df <- cbind(iris, cluster_res_list)
} )

【问题讨论】:

  • broom 包提供了一些将模型输出转换为整齐数据帧的功能。示例:kmeans(iris %&gt;% select(-Species), 3, nstart = 25) %&gt;% broom::tidy()。我不确定您需要哪种数据框,但我希望这会有所帮助。
  • @Damian 我只想将 kmeans 集群的结果结合到原始数据帧中。我也试过iris_df &lt;- cbind(iris, paste0("iris_clus_", cluster_num)),但这也没有用。一定会检查扫帚。

标签: r dataframe apply lapply k-means


【解决方案1】:

kmeans 的输出可以使用fitted 函数查看为矩阵。矩阵的行名称标识集群。如果您想在原始日期框架中添加一列来标识集群分配,那么类似的方法会起作用。

以 3 个集群为例:

cluster_num <- 3

iris %>% 
    select(-Species) %>% 
    kmeans(centers = cluster_num, nstart = 25) %>% 
    fitted() %>% 
    row.names() %>%
    tibble(iris_clus = .) %>%
    cbind(iris) %>% 
    tail()

    iris_clus Sepal.Length Sepal.Width Petal.Length Petal.Width   Species
145         2          6.7         3.3          5.7         2.5 virginica
146         2          6.7         3.0          5.2         2.3 virginica
147         1          6.3         2.5          5.0         1.9 virginica
148         2          6.5         3.0          5.2         2.0 virginica
149         2          6.2         3.4          5.4         2.3 virginica
150         1          5.9         3.0          5.1         1.8 virginica

将其插入您示例中的lapply

lapply(1:3, function(cluster_num) {
    iris %>% 
        select(-Species) %>% 
        kmeans(centers = cluster_num, nstart = 25) %>% 
        fitted() %>% 
        row.names() %>%
        tibble(iris_clus = .) %>%
        cbind(iris) 
})

这是将所有数据组合成一个数据集的一种方法。每个模型一列

clusters <- Reduce(cbind, lapply(1:3, function(cluster_num) {

   result <- iris %>% 
        select(-Species) %>% 
        kmeans(centers = cluster_num, nstart = 25) %>% 
        fitted() %>% 
        row.names() %>% 
        tibble(iris_clus = .)

   names(result) <- paste("iris_clus", cluster_num, sep = "_")
   return(result)

}))

cbind(iris, clusters)

【讨论】:

  • 是的,这让我得到了数据框中的集群结果,但不是所有 3 次运行的集群结果。所以为此我尝试了tibble(paste("iris_clus", cluster_num, sep = "_") = .) %&gt;% cbind(iris),但这不起作用。
  • 也试过这段代码,但这也给出了错误:iris_df &lt;- iris lapply(1:3, function(cluster_num) { iris %&gt;% select(-Species) %&gt;% kmeans(centers = cluster_num, nstart = 25) %&gt;% fitted() %&gt;% row.names() %&gt;% # tibble(iris_clus = .) %&gt;% tibble(paste0("iris_clus_", cluster_num) = .) %&gt;% cbind(iris_df) })
  • 期望的输出是什么样的?最终输出的 iris 数据集中会不会总共增加 3 个新列?
  • 是的,iris_clus_1iris_clus_2iris_clus_3 列应该添加到虹膜数据中。这就是为什么我使用apply 函数运行它,以便将所有 kmeans 集群 试验的 result 合并到原始数据中。
  • lapply 函数分别存储每个结果并将它们作为列表返回。输出列表可以在运行后合并。也就是说,使用 for 循环而不是每次使用新列更新相同的数据框可能更符合您的想法。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-12-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多