R:根据多列中的值添加零行

时间:2014-10-17 01:23:49

标签: r if-statement zero data-manipulation

我正在尝试将行附加到R df。这是一个例子df foo:

A   B   C   D
1   1   1   200
1   1   2   50
1   1   3   15
1   2   1   150
1   2   4   50
1   3   1   300
2   1   2   40
2   1   4   90
2   3   2   80

对于每个A,有3个可能的B值,并且对于每个B,有4个可能的C值。但是,初始df仅包含D的非零值。我喜欢操纵df使得B和C都包括零。因此,对于任何B / C值为0,df将在D中显示0。我已经看到用一列来解决这个问题的问题,但是不能找到一个用多列来解决它的问题。最终的df看起来像这样:

A   B   C   D
1   1   1   200
1   1   2   50
1   1   3   15
1   1   4   0
1   2   1   150
1   2   2   0
1   2   3   0
1   2   4   50
1   3   1   300
1   3   2   0
1   3   3   0
1   3   4   0
2   1   1   0
2   1   2   40
2   1   3   0
2   1   4   90
2   2   1   0
2   2   2   0
2   2   3   0
2   2   4   0
2   3   1   0
2   3   2   80
2   3   3   0
2   3   4   0

我首先尝试创建一个虚拟数据框,然后与初始df合并,但有些东西不能正常工作。这是当前的代码,我知道这是错误的,因为这段代码只生成基于A的行。我想我想根据A和B制作虚拟帧,但我不知道怎么做 - 可能是if / else函数在这里工作?:

# create dummy df
dummy <- as.data.frame(
  cbind(
    sort(rep(unique(foo$A), 12)),
    rep(1:3,length(unique(foo$A)))))
colnames(dummy) <- c("A","B")
foo$A <- as.numeric(foo$A)
foo$B <- as.numeric(foo$C)

# merge with foo
mergedummy <- merge(dummy,foo,all.x=T)

非常感谢任何见解 - 谢谢!

3 个答案:

答案 0 :(得分:5)

一个班轮:

merge(dat, data.frame(table(dat[1:3]))[-4],all.y=TRUE)

#   A B C   D
#1  1 1 1 200
#2  1 1 2  50
#3  1 1 3  15
#4  1 1 4  NA
#...

或者可能不那么复杂:

out <- data.frame(xtabs(D ~ ., data=dat))
out[do.call(order,out[1:3]),]

#   A B C Freq
#1  1 1 1  200
#7  1 1 2   50
#13 1 1 3   15
#19 1 1 4    0
#...

dat的位置:

dat <- structure(list(A = c(1L, 1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L), B = c(1L, 
1L, 1L, 2L, 2L, 3L, 1L, 1L, 3L), C = c(1L, 2L, 3L, 1L, 4L, 1L, 
2L, 4L, 2L), D = c(200L, 50L, 15L, 150L, 50L, 300L, 40L, 90L, 
80L)), .Names = c("A", "B", "C", "D"), class = "data.frame", row.names = c(NA, 
-9L))

答案 1 :(得分:3)

我创建了一个主数据框,其中包含您在预期结果中描述的A,B和C的所有组合。然后,我合并主数据框和您的数据框。最后,我将NA替换为0。

master <- data.frame(A = rep(1:2, each = 12),
                     B = rep(1:3, each = 4),
                     C = rep(1:4, times = 6))

library(dplyr)

master %>%
    left_join(., mydf) %>%
    mutate(D = ifelse(D %in% NA, 0, D))

#   A B C   D
#1  1 1 1 200
#2  1 1 2  50
#3  1 1 3  15
#4  1 1 4   0
#5  1 2 1 150
#6  1 2 2   0
#7  1 2 3   0
#8  1 2 4  50
#9  1 3 1 300
#10 1 3 2   0
#11 1 3 3   0
#12 1 3 4   0
#13 2 1 1   0
#14 2 1 2  40
#15 2 1 3   0
#16 2 1 4  90
#17 2 2 1   0
#18 2 2 2   0
#19 2 2 3   0
#20 2 2 4   0
#21 2 3 1   0
#22 2 3 2  80
#23 2 3 3   0
#24 2 3 4   0

答案 2 :(得分:2)

这是一个解决方案:

foo <- merge(expand.grid(lapply(foo[,1:3], unique)), foo, all=TRUE, sort=TRUE)
foo[is.na(foo)] <- 0