重新排列数据帧 - R.

时间:2013-02-20 12:04:13

标签: r dataframe melt

我有一个如下所示的数据框:

       a        b       c         d
ab    0        0        1         0
cd   -0.415    1.415    0         0
ef    0        0        0.0811    0.918

有没有一种简单的方法可以将此表转换为:

       a        b       c         d
ab    0        0        1         0
cd   -0.415    0        0         0
cd    0    1.415        0         0
ef    0        0        0.0811    0
ef    0        0        0         0.918

如果原始表中有两个或更多个数字,我想将其转换为相应的行数。我还没有弄清楚如何做到这一点,所以任何帮助将不胜感激

5 个答案:

答案 0 :(得分:4)

这是一种使用矩阵索引的方法。 (数据会变成一个矩阵,因此如果您的数据属于一种类型会更好,就像您的示例中的情况一样。)

reformat.dat <- function(dat) {
  tdat <- t(dat)
  nz <- tdat != 0
  i <- col(tdat)[nz]
  j <- row(tdat)[nz]
  out <- matrix(0, sum(nz), ncol(dat))
  out[cbind(seq_len(sum(nz)), j)] <- tdat[nz]
  rownames(out) <- rownames(dat)[i]
  colnames(out) <- colnames(dat)
  out
}

reformat.dat(dat)
#         a     b      c     d
# ab  0.000 0.000 1.0000 0.000
# cd -0.415 0.000 0.0000 0.000
# cd  0.000 1.415 0.0000 0.000
# ef  0.000 0.000 0.0811 0.000
# ef  0.000 0.000 0.0000 0.918

答案 1 :(得分:4)

从@AnandaMahto借用一些并根据您的要求融化。请考虑:您想要检查的任何独特组合都在左侧〜变量的值在右侧。在这种情况下,变量名称变为值。

library(reshape2)
mydf <- structure(list(a = c(0, -0.415, 0), b = c(0, 1.415, 0), 
                       c = c(1, 0, 0.0811), d = c(0, 0, 0.918)), 
                  .Names = c("a", "b", "c", "d"), 
                  class = "data.frame", row.names = c("ab", "cd", "ef"))
mydf$rows<- rownames(mydf)
m1<- melt(mydf, id="rows", measured= names(mydf))
m2<- dcast(m1, rows+value~..., fill=0)
m2<- m2[m2$value!=0, ]
m2$value <- NULL    

#rows      a     b      c     d
#2   ab  0.000 0.000 1.0000 0.000
#3   cd -0.415 0.000 0.0000 0.000
#5   cd  0.000 1.415 0.0000 0.000
#7   ef  0.000 0.000 0.0811 0.000
#8   ef  0.000 0.000 0.0000 0.918

答案 2 :(得分:2)

以下是使用diag

的直接解决方案
o <- apply(df, 1, function(x) {
    t <- diag(x)
    colnames(t) <- names(x)
    t <- t[rowSums(t == 0) != length(x), ,drop = FALSE]
    t
})
ids <- rep(names(o), sapply(o, nrow))
o <- do.call(rbind, o)
row.names(o) <- ids

#         a     b      c     d
# ab  0.000 0.000 1.0000 0.000
# cd -0.415 0.000 0.0000 0.000
# cd  0.000 1.415 0.0000 0.000
# ef  0.000 0.000 0.0811 0.000
# ef  0.000 0.000 0.0000 0.918

这是matrix。如果您需要as.data.frame(.),请使用data.frame

答案 3 :(得分:1)

这是一种方法,但您需要跟进修改行名称的一些修饰。

您的数据是以可复制的形式:

mydf <- structure(list(a = c(0, -0.415, 0), b = c(0, 1.415, 0), 
                       c = c(1, 0, 0.0811), d = c(0, 0, 0.918)), 
                  .Names = c("a", "b", "c", "d"), 
                  class = "data.frame", row.names = c("ab", "cd", "ef"))

NA s替换零:

mydf[mydf == 0] <- NA

stack您的data.frame将其设为“长”data.frame

mydf1 <- data.frame(Rows = rownames(mydf), stack(mydf))

为“行”生成唯一值

mydf1$Rows <- make.unique(as.character(mydf1$Rows))
# Let's see what we have so far....
mydf1
#    Rows  values ind
# 1    ab      NA   a
# 2    cd -0.4150   a
# 3    ef      NA   a
# 4  ab.1      NA   b
# 5  cd.1  1.4150   b
# 6  ef.1      NA   b
# 7  ab.2  1.0000   c
# 8  cd.2      NA   c
# 9  ef.2  0.0811   c
# 10 ab.3      NA   d
# 11 cd.3      NA   d
# 12 ef.3  0.9180   d

现在,只需使用xtabs来获取您正在寻找的输出。如果您需要as.data.frame.matrix,请将其包裹在data.frame中,并在需要时清理行名称。

as.data.frame.matrix(xtabs(values ~ Rows + ind, mydf1))
#           a     b      c     d
# ab.2  0.000 0.000 1.0000 0.000
# cd   -0.415 0.000 0.0000 0.000
# cd.1  0.000 1.415 0.0000 0.000
# ef.2  0.000 0.000 0.0811 0.000
# ef.3  0.000 0.000 0.0000 0.918

答案 4 :(得分:-1)

我认为你所要求的内容并不优雅,但也许你可以使用melt中的reshape2代替?它会为每行/每列提供一行:

> library(reshape2) 
> # add row names as column
> df <- cbind(df, names=rownames(df))
> df <- melt(df,id.var="names")
Using  as id variables
> df[df$value != 0,]
   names variable   value
2     cd        a -0.4150
5     cd        b  1.4150
7     ab        c  1.0000
9     ef        c  0.0811
12    ef        d  0.9180