如何创建组成员的 table 或数据框(按组的项目,来自长格式数据)?

How can I create a table or data frame of members of a group (items by group, from long format data)?

我正在处理一些聚类分析结果。我正在尝试为我正在进行的每个集群分析创建集群成员表。

例如:

test_data <- data.frame(
        Cluster = sample(1:5,100,replace=T),
        Item = sample(LETTERS[1:20],5, replace=F))

head(test_data)
  Cluster Item
1       2    R
2       5    F
3       1    T
4       5    Q
5       3    B
6       3    J

我想制作这样的东西:

    Cluster_1   Cluster_2   Cluster_3   Cluster_4   Cluster_5
         T           R           C           P           L 
         K           O           J           M           Q
         I           H           B           N           F
         D                                   G           E
         S                                               A

我第一次尝试 spread ,但没有使用这些数据

spread(test_data, item,group)

错误:行的标识符重复

spread(test_data, group,item)

错误:行的标识符重复

然后我尝试了:

test_frame <- split.data.frame(test_data,test_data$group)

但这会产生一个数据框列表,每个组都有一个数据框。我一直无法成功地将其操纵成我想要的。

我尝试了unnestunlist,但是因为每个组都有不同数量的成员元素,所以这些函数会出错。

引入 NA 就好了。

是否有一种我忽略的直接方法来完成此操作?

修改了我的答案。全部在 base R 中。相当简洁:

test_data <- data.frame(
  Cluster = sample(1:5,100,replace=T),
  Item = sample(LETTERS[1:20],5, replace=T), stringsAsFactors=FALSE)

clusters <- unique(test_data$Cluster)

test_data <- lapply(clusters, function(i) {
  test_data[test_data$Cluster == i,]$Item } ) 

n_max <- Reduce(f=max, x=lapply(test_data, FUN=length))

test_data <- lapply(test_data, function(i) {length(i) <- n_max; i})

test_data <- Reduce(x=test_data, f=cbind)

test_data <- as.data.frame(test_data)

names(test_data) <- paste0('Cluster_', clusters)

test_data

这是一个使用 tidyverse 的解决方案。 test_final 是最终输出。

# Load package
library(tidyverse)

# Set seed for reproducibility
set.seed(123)

# Create example data frame
test_data <- data.frame(
  Cluster = sample(1:5,100,replace=T),
  Item = sample(LETTERS[1:20],5, replace=T))

# Split the data frame into a list of data frames
test_list <- test_data %>%
  mutate(Item = as.character(Item)) %>%
  arrange(Cluster) %>%
  split(f = .$Cluster)

# Find out the maximum row number of each data frame
max_row <- max(map_int(test_list, nrow))

# Design a function to process each data frame in test_list
process_fun <- function(dt, max_row){

  # Append NA to the Item column
  dt_vec <- dt$Item
  dt_vec2 <- c(dt_vec, rep(NA, max_row - nrow(dt)))
  # Get the cluster number
  clusterNum <- unique(dt$Cluster)
  # Create a new data frame
  dt2 <- data_frame(Item = dt_vec2)
  # Change column name
  colnames(dt2) <- paste("Cluster", clusterNum, sep = "_")
  return(dt2)
} 

# Process the data
test_final <- test_list %>% 
  map(process_fun, max_row = max_row) %>%
  bind_cols()
test_data <- data.frame(
       Cluster = sample(1:5,100,replace=T),
          Item = sample(LETTERS[1:20],5, replace=T),stringsAsFactors = FALSE)

m <- with(test_data,tapply(Item,paste("Cluster",Cluster,sep="_"),I))
e <- data.frame(sapply(m,`length<-`,max(lengths(m))))
   print(e,na.print="")