将列(长)的级别重塑为新列(宽)

Reshape levels of a column (long) into new columns (wide)

我想在一个 DF 中获取列的级别,并将每个级别添加为新 DF 中的新列。这是一个显示源和理想目标 DF 的玩具数据集。

来源 DF

person  hour  ride 
Bill     1      A
Sue      2      B
Bob      1      C
Jill     3      B
Dan      3      A
Tina     3      A

映射的 DF

hour   A   B   C   Saturation 
1      1   0   1     .66
2      0   1   0     .33
3      1   1   0     .66

这里是测试数据集:

test_data <- cbind.data.frame(person = c('Bill', 'Sue', 'Bob', 'Jill', 'Dan', 'Tina'),
                              hour = factor(c(1, 2, 1, 3, 3, 3)),
                              ride = c('A', 'B', 'C', 'B', 'A', 'A'))

test_data$person <- as.character(test_data$person)

看看 Source 中的每次骑行如何变成 Mapped 中的新专栏。我可以通过

获取关卡并使用它们创建映射的 DF
new_data <- cbind.data.frame(hour = levels(test_data$hour))

但是当我尝试遍历级别以添加新列时,一切都失败了。我看到等级了。

unlist(lapply(levels(test_data$ride), function(x) paste(x)))

产量

[1] "A" "B" "C"

那么如何遍历 $ride 中的级别并在映射的 DF 中添加一列?

奖金:我将 运行 通过 test_dataifelse() 中的每一行 1 在对应于该骑行的列中显示它有骑手,否则 0,但必须有人知道如何更优雅地做到这一点?就目前而言,我需要为从 $ride 中的级别提取的每一列添加一个 ifelse,我知道这必须比要求的更冗长。

require(reshape2)

mydat <- recast(test_data,hour~ride)
mydat
  hour A B C
1    1 1 0 1
2    2 0 1 0
3    3 2 1 0
# 2nd part
for(i in 2:ncol(mydat)){
  for(ii in 1:nrow(mydat)){
    if(mydat[ii,i] > 0) {mydat[ii,i] <- 1}
  }
}
  hour A B C
1    1 1 0 1
2    2 0 1 0
3    3 1 1 0

我们可以使用 dcast 来自 data.table

library(data.table)
dcast(setDT(test_data), hour~ride, value.var="person", 
               function(x) as.integer(length(x) > 0))[, 
        Saturation := round(rowSums(.SD)/3,2), .SDcols = A:C][]
#    hour A B C Saturation
#1:    1 1 0 1       0.67
#2:    2 0 1 0       0.33
#3:    3 2 1 0       1.00