从长到长的data.frame合并两列(键/值)的列

时间:2017-10-30 23:15:01

标签: r tidyr reshape2

我有这个data.frame

set.seed(28100)
label_1 <- sample(c('first_col','second_col'), 10, replace = T)
dat <- data.frame(label_1,
                  value_1 = sample(1:100, 10, replace = T),
                  label_2 = sapply(label_1, FUN = function(x) ifelse(x == 'first_col', 'second_col', 'first_col')),
                  value_2 = sample(1:100, 10, replace = T))

head(dat)
         label_1 value_1    label_2 value_2
1  first_col      88 second_col      84
2  first_col      40 second_col      30
3  first_col      98 second_col      32
4 second_col      80  first_col      64
5  first_col      34 second_col      43
6 second_col      52  first_col      10

具有两对键/值列的不一致排序。我想将相同的数据重新整形为长格式data.frame,例如:

desired_dat <- data.frame(first_col = rep(NA, 10), 
                          second_col = rep(NA, 10))

建议您使用reshape2tidyr来解决此问题?究竟是怎么回事?

5 个答案:

答案 0 :(得分:2)

如何使用dplyr(不需要tidyr等)?

library(dplyr)
dat %>% transmute(first_col = if_else(label_1 == "first_col", value_1, value_2),
                  second_col = if_else(label_2 == "second_col", value_2, value_1))

#>    first_col second_col
#> 1         88         84
#> 2         40         30
#> 3         98         32
#> 4         64         80
#> 5         34         43
#> 6         10         52
#> 7         23         85
#> 8         65         86
#> 9          4         35
#> 10        83          8

答案 1 :(得分:1)

我会使用data.table执行此操作,但同样的主体也可以应用于tidyverse

library(data.table)

## Setting as a data.table, and adding an 'id' value to keep track of rows
setDT(dat)
dat[, id := .I]


## then 'rbinding' the _1 and _2 columns together, with common column names
dat2 <- rbindlist(
    list(
        dat[, .(id, label = label_1, value = value_1)], 
        dat[, .(id, label = label_2, value = value_2)]
        )
)

## the reshaping from long to wide to give you your desired result
dcast(dat2, formula = id ~ label)
#     id first_col second_col
# 1:   1        88         84
# 2:   2        40         30
# 3:   3        98         32
# 4:   4        64         80
# 5:   5        34         43
# 6:   6        10         52
# 7:   7        23         85
# 8:   8        65         86
# 9:   9         4         35
# 10: 10        83          8

答案 2 :(得分:1)

这基本上是@ SymbolixAU的解决方案,刚刚翻译为dplyr

# Create an ID for each row: probably not necessary but useful to check
dat <- dat %>%
    mutate(id = row_number())

dat_long <- bind_rows(
    dat %>% select(id, label = label_1, value = value_1),
    dat %>% select(id, label = label_2, value = value_2)
)

output <- dat_long %>%
    spread(label, value)

答案 3 :(得分:1)

从版本v1.9.6开始(2015年9月19日CRAN),$可以同时data.table多个列。所以这是一个melt()表达式链:

data.table
library(data.table)
as.data.table(dat)[, rn := .I][
  , melt(.SD, measure.vars = patterns("label", "value"))][
    , dcast(.SD, rn ~ value1)][, -"rn"]

答案 4 :(得分:0)

这是一种可能的解决方案;但不是最优雅的。

unknownlevels