根据SQL或R中的某些条件复制行

时间:2018-01-04 17:51:11

标签: sql r rbind do.call

我用R来生成玩具套装

data.frame(name = c("Tom", "Shane", "Daniel", "Akira", "Jack", "Zoe"), c1 = c(1,2,3,0,5,0), c2 = c(0, 3, 5, 0,4,0), c3 = c(0, 0,1,0,0,3), c4=c(0,0,0,1,0,0))

显示如下:

enter image description here

我只关心列c1, c2, c3, c4,如果某个特定行有多个值,大于0.我们需要复制行以确保只有一个值,这个值更大比0,然后删除原始行。

例如,第二行有两个值大于0(c1:2,c2:3),那么我们必须将该行复制为两个,看起来像这样

Shane 2 0 0 0

Shane 0 3 0 0

我正在尝试构建一个SQL查询来捕获它。但是,我不确定是否有任何SQL函数可以检测特定行中的多个非零值而不先查看结果。无论如何,如果存在任何神奇的SQL函数,最终结果应如下所示:

enter image description here

我也想过用R来完成它。我知道唯一可以复制行的R函数是do.call()函数,然后将它与rbind()函数结合起来。但是,它不适合我的情况。你能有人给我任何提示吗?非常感谢:)

5 个答案:

答案 0 :(得分:2)

您可以使用一些tidyverse函数执行此操作。首先,我们输入您的样本数据

library(tidyverse)
dd <- tribble(~name, ~c1, ~c2, ~c3, ~c4,
        "Tom", 1, 0, 0, 0,
        "Shane", 2, 3, 0, 0,
        "Daniel", 3, 5, 1, 0,
        "Akira", 0, 0, 0 ,1,
        "Jack", 5, 4, 0, 0,
        "Zoe", 0, 0, 3, 0)

然后我们收集,过滤和传播以获得您想要的行。通过添加行id,我们将不同的值保存在不同的行上。

dd %>% 
  gather("var", "val", -name) %>% 
  rowid_to_column() %>% 
  filter(val>0) %>% 
  spread(var, val, fill=0) %>% 
  select(-rowid)
# A tibble: 10 x 5
#      name    c1    c2    c3    c4
#  *  <chr> <dbl> <dbl> <dbl> <dbl>
#  1    Tom     1     0     0     0
#  2  Shane     2     0     0     0
#  3 Daniel     3     0     0     0
#  4   Jack     5     0     0     0
#  5  Shane     0     3     0     0
#  6 Daniel     0     5     0     0
#  7   Jack     0     4     0     0
#  8 Daniel     0     0     1     0
#  9    Zoe     0     0     3     0
# 10  Akira     0     0     0     1

答案 1 :(得分:2)

也许使用CROSS APPLY

的另一种选择

示例

Select A.Name
      ,B.*
 From  YourTable A
 Cross Apply ( values (C1,0,0,0)
                     ,(0,C2,0,0)
                     ,(0,0,C3,0)
                     ,(0,0,0,C4)
             ) B (C1,C2,C3,C4)
 Where B.C1+B.C2+B.C3+B.C4<>0

<强>返回

enter image description here

答案 2 :(得分:1)

使用union all的另一个选项。

select name,c1,0 as c2,0 as c3,0 as c4 from tbl where c1>0
union all
select name,0,c2,0,0 from tbl where c2>0
union all
select name,0,0,c3,0 from tbl where c3>0
union all
select name,0,0,0,c4 from tbl where c4>0

答案 3 :(得分:1)

react-native run-ios

答案 4 :(得分:1)

考虑带有by的基础R,为每个不同的名称构建一个零填充的数据帧,然后将所有数据帧绑定到最终的数据帧,类似于union SQL:

df_list <- by(df, df$name, FUN = function(d){

  tmp <- data.frame(name = d$name[1],
             c1 = c(max(d$c1), rep(0, 3)),
             c2 = c(0, max(d$c2), rep(0, 2)),
             c3 = c(rep(0, 2), max(d$c3), 0),
             c4 = c(rep(0, 3), max(d$c4)))

  tmp <- tmp[rowSums(tmp[-1])!=0,]
  row.names(tmp) <- NULL
  tmp

})

final_df <- do.call(rbind, unname(df_list))
final_df