【问题标题】:How do I stack only some columns in a data frame?如何仅堆叠数据框中的某些列?
【发布时间】:2013-01-16 07:40:18
【问题描述】:

我在数据框中有一些数据,格式如下:

A  B  C  V1  V2  V3
1  1  1  x   y   z
1  1  2  a   b   c
...

其中 A、B、C 是因子,A、B、C 的组合对于每一行都是唯一的。

我需要将一些列转换为因子,以实现如下形式:

A  B  C  V  val
1  1  1  V1 x
1  1  1  V2 y
1  1  1  V3 z
1  1  2  V1 a
1  1  2  V2 b
1  1  2  V2 c
...

这似乎与stackxtabs 的倒数有关,但我不知道如何指定只有某些列应该“堆叠”。

【问题讨论】:

  • 参见 reshape 和 reshape 包。

标签: r reshape


【解决方案1】:

使用reshape2

dat <- read.table(text = 'A  B  C  V1  V2  V3
1  1  1  x   y   z
1  1  2  a   b   c',header= T)
library(reshape2)
melt(dat,id.vars = c('A','B','C'))
 A B C variable value
1 1 1 1       V1     x
2 1 1 2       V1     a
3 1 1 1       V2     y
4 1 1 2       V2     b
5 1 1 1       V3     z
6 1 1 2       V3     c

【讨论】:

    【解决方案2】:

    在@AnandaMahto 来到这里并提供他的基础reshape 解决方案之前,这是我的尝试:

    dat <- read.table(text = 'A  B  C  V1  V2  V3
    1  1  1  x   y   z
    1  1  2  a   b   c',header= T)
    
    expandvars <- c("V1","V2","V3")
    
    datreshape <- reshape(dat,
                       idvar=c("A","B","C"),
                       varying=list(expandvars),
                       v.names=c("val"),
                       times=expandvars,
                       direction="long")
    
    > datreshape
             A B C time val
    1.1.1.V1 1 1 1   V1   x
    1.1.2.V1 1 1 2   V1   a
    1.1.1.V2 1 1 1   V2   y
    1.1.2.V2 1 1 2   V2   b
    1.1.1.V3 1 1 1   V3   z
    1.1.2.V3 1 1 2   V3   c
    

    【讨论】:

    • @agstudy,很高兴在我的公司里有其他一些变形者。为你们俩 +1。
    • @agstudy 和 Thela(抱歉,你现在被这个名字卡住了),我无法抗拒adding an answer 提出重塑问题。 (我应该寻求帮助....)
    • +1,谢谢!我没有意识到 SO 上有一个 R 忍者社区。​​span>
    【解决方案3】:

    stack

    stack 是一种可能性是对的,但您可能错过了stack 文档中的关键行:

    请注意,堆栈适用于向量(由 is.vector 确定):非向量列(例如因子)将被忽略(从 R 2.15.0 开始出现警告)。

    那么,我们该如何进行呢?

    这是您的数据:

    dat <- read.table(text = 'A  B  C  V1  V2  V3
        1  1  1  x   y   z
        1  1  2  a   b   c',header= T)
    

    在这里,我们将因子转换为as.character

    dat[sapply(dat, is.factor)] = lapply(dat[sapply(dat, is.factor)], as.character)
    

    以下是我们如何指定 stack 的列:

    stack(dat[4:6])
    #   values ind
    # 1      x  V1
    # 2      a  V1
    # 3      y  V2
    # 4      b  V2
    # 5      z  V3
    # 6      c  V3
    

    但是,我们仍然需要为第 1-3 列“扩展”您的行。请参阅here 了解如何执行此操作。

    有了这些信息,我们就可以使用cbind来得到想要的结果了。

    cbind(dat[rep(row.names(dat), 3), 1:3], stack(dat[4:6]))
    #     A B C values ind
    # 1   1 1 1      x  V1
    # 2   1 1 2      a  V1
    # 1.1 1 1 1      y  V2
    # 2.1 1 1 2      b  V2
    # 1.2 1 1 1      z  V3
    # 2.2 1 1 2      c  V3
    

    xtabs

    您也说得对,xtabs 似乎很有可能,但 xtabs 实际上希望与您提供的内容相反。也就是说,当你指定一个公式时,它期望左边的项目是数字,右边的项目是因子。因此,如果您的数据被交换,您可以当然使用xtabs

    这是一个演示(它之所以有效,是因为您使用的是一个简单的示例,我们可以轻松地将match“字母”转换为“数字”)。

    dat2 <- dat # Make a copy of "dat"
    # Swap out dat 4-6 with numbers
    dat2[4:6] <- lapply(dat2[4:6], function(x) match(x, letters))
    # Swap out dat 1-3 with letters
    dat2[1:3] <- lapply(dat2[1:3], function(x) letters[x])
    # Our new "dat"
    dat2
    #   A B C V1 V2 V3
    # 1 a a a 24 25 26
    # 2 a a b  1  2  3
    data.frame(xtabs(cbind(V1, V2, V3) ~ A + B + C, dat2))
    #   A B C Var4 Freq
    # 1 a a a   V1   24
    # 2 a a b   V1    1
    # 3 a a a   V2   25
    # 4 a a b   V2    2
    # 5 a a a   V3   26
    # 6 a a b   V3    3
    

    换句话说,您选择的工具可能是正确的,但您的数据也需要采用工具所期望的形式。

    但是,当reshape 和朋友们有更好的解决方案时,我不确定你为什么要完成我展示的所有工作;)


    很晚更新...

    您还可以查看我的“splitstackshape”包中的merged.stack

    library(splitstackshape)
    merged.stack(dat, var.stubs = "V", sep = "NoSep")
    #    A B C .time_1 V
    # 1: 1 1 1      V1 x
    # 2: 1 1 1      V2 y
    # 3: 1 1 1      V3 z
    # 4: 1 1 2      V1 a
    # 5: 1 1 2      V2 b
    # 6: 1 1 2      V3 c
    

    或来自“tidyr”的gather

    library(dplyr)
    library(tidyr)
    # gather(dat, var, val, V1:V3)
    dat %>% gather(var, val, V1:V3) 
    #   A B C var val
    # 1 1 1 1  V1   x
    # 2 1 1 2  V1   a
    # 3 1 1 1  V2   y
    # 4 1 1 2  V2   b
    # 5 1 1 1  V3   z
    # 6 1 1 2  V3   c
    

    【讨论】:

    • 感谢您的回复。我才刚刚开始了解 R 数据模型,这种回复提供了非常有用的见解。
    • @saffsd,没问题。 SO 是了解这些事情的好地方。请务必阅读this post,并尝试以可重复的格式分享您的问题。
    • 从旧帖子跟进,基本版本可以像cbind(dat[1:3],stack(lapply(dat[4:6],as.character))) 一样变得更简单 - 无需显式重复行。
    猜你喜欢
    • 2016-01-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-02-10
    • 2021-06-17
    • 1970-01-01
    • 2010-09-17
    相关资源
    最近更新 更多