以特殊形式重塑数据框

时间:2018-11-21 14:30:41

标签: r

我有一个特定的数据框,可以说:

Site  Date   Start  End    Spec1 Spec2
ZR    10.05  10:40  11:40  X1
ZR    10.05  10:40  11:40  X2
ZR    10.05  10:40  11:40  X3
ZR    10.05  10:40  11:40        X1
ZR    10.05  10:40  11:40        X4
ZR    10.05  10:40  11:40        X5

最后它应该看起来像:

      ZR
Date  10.05
Start 10:40
End   11:40
Spec1 X1
Spec1 X2
Spec1 X3
Spec2 X1
Spec2 X4
Spec2 X5

有些人有一个很好的主意如何开始?我对每个Spec1和Spec2需要一个新行感到困惑。

测试数据:

structure(list(Site = c("ZR", "ZR", "ZR", "ZR", "ZR", "ZR"), 
    Date = c("10.05", "10.05", "10.05", "10.05", "10.05", "10.05"
    ), Start = c("10:40", "10:40", "10:40", "10:40", "10:40", 
    "10:40"), End = c("11:40", "11:40", "11:40", "11:40", "11:40", 
    "11:40"), Spec1 = c("X1", "X2", "X3", "", "", ""), Spec2 = c("", 
    "", "", "X1", "X2", "X3")), class = "data.frame", row.names = c(NA, 
-6L))

4 个答案:

答案 0 :(得分:1)

我假设您的实际数据中包含多个站点的数据。这是使用tidyverse的通用解决方案。请注意,不可能有重复的行名,因此我在输出中将它们变成了variable列-

df %>% 
  gather(variable, value, -Site) %>% 
  distinct() %>% 
  filter(value != "") %>% 
  rownames_to_column("id") %>% 
  spread(Site, value) %>%
  select(-id)

  variable    ZR
1     Date 10.05
2    Start 10:40
3      End 11:40
4    Spec1    X1
5    Spec1    X2
6    Spec1    X3
7    Spec2    X1
8    Spec2    X4
9    Spec2    X5

答案 1 :(得分:0)

一种(非一般性!)解决问题的方法是

library(tidyverse)
gather(foo,key = Var, value=ZR, -Site) %>% 
 filter(ZR!="") %>% 
 select(-Site) %>% 
 distinct()

   Var    ZR
1  Date 10.05
2 Start 10:40
3   End 11:40
4 Spec1    X1
5 Spec1    X2
6 Spec1    X3
7 Spec2    X1
8 Spec2    X4
9 Spec2    X5

但是,在我看来,您希望将Key变量用作行名(?)。这实际上不起作用,因为它包含重复项。而且,我看不出您为什么要这么做的原因?

答案 2 :(得分:0)

这是data.table

的一个选项
library(data.table)
unique(melt(setDT(df1), id.var = "Site", 
               value.name = 'ZR'))[ZR != ''][, Site := NULL][]
#   variable    ZR
#1:     Date 10.05
#2:    Start 10:40
#3:      End 11:40
#4:    Spec1    X1
#5:    Spec1    X2
#6:    Spec1    X3
#7:    Spec2    X1
#8:    Spec2    X2
#9:    Spec2    X3

答案 3 :(得分:0)

在基数R中,您可以利用unique()lapply()的列中有唯一值的事实,这为您提供了一个列表。使用do.call(rbind())方法,您可以将列表的行绑定在一起。与do.call(c())相似,方法是将需要转换的内容串联起来,以便可以rbind()与第一部分一起使用。像这样:

var <- c(names(df1)[1:3], rep(names(df1)[5:6], each=3))
ZR <- rbind(do.call(rbind, lapply(df1[, 2:4], unique)),
            as.matrix(
              do.call(c, lapply(5:6, function(x) df1[, x][df1[, x] != ""])))
            )
out1 <- data.frame(var, ZR, row.names=NULL)

给予

> out1
    var    ZR
1  Site 10.05
2  Date 10:40
3 Start 11:40
4 Spec1    X1
5 Spec1    X2
6 Spec1    X3
7 Spec2    X1
8 Spec2    X4
9 Spec2    X5

或者,如果不需要每个Spec*和行名而不是​​ID变量都需要多余的行,则可以

out2 <- data.frame(rbind(
  do.call(rbind, lapply(df1[, 2:4], unique)),
  do.call(rbind, lapply(5:6, function(x) paste0(df1[, x][df1[, x] != ""], collapse=", ")))
))
dimnames(out2) <- list(names(df1)[-1], df1[1,1])

给予

> out2
              ZR
Date       10.05
Start      10:40
End        11:40
Spec1 X1, X2, X3
Spec2 X1, X4, X5