如何创建组成员的表或数据框(逐项,从长格式数据)?

时间:2017-07-28 21:27:17

标签: r dplyr tidyr

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

例如:

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会很好。

是否有一种直截了当的方式来实现这一点,我忽略了?

3 个答案:

答案 0 :(得分:3)

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="")

答案 1 :(得分:1)

重新解决了我的问题。全部基于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

答案 2 :(得分:0)

以下是使用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()