减去一列而不是其他列固定的行

时间:2019-03-22 12:00:15

标签: r dataframe dplyr

我有一个实验,我需要从对照(基准)中减去两种不同处理的值,但是这些减法必须对应于其他列(称为块和采样年份)。

虚拟数据框:

df <- data.frame("Treatment" = c("Control","Treat1", "Treat2"), 
     "Block" = rep(1:3, each=3), "Year" = rep(2011:2013, each=3),
     "Value" = c(6,12,4,3,9,5,6,3,1));df

  Treatment Block Year Value
1   Control     1 2011     6
2    Treat1     1 2011    12
3    Treat2     1 2011     4
4   Control     2 2012     3
5    Treat1     2 2012     9
6    Treat2     2 2012     5
7   Control     3 2013     6
8    Treat1     3 2013     3
9    Treat2     3 2013     1

所需的输出:

       Treatment Block Year Value
1 Control-Treat1     1 2011    -6
2 Control-Treat2     1 2011     2
3 Control-Treat1     2 2012    -6
4 Control-Treat2     2 2012    -2
5 Control-Treat1     3 2013     3
6 Control-Treat2     3 2013     5

任何建议,最好使用dplyr

我发现了类似的问题,但没有一个解决这个特定的问题。

5 个答案:

答案 0 :(得分:1)

我们可以使用dplyrgroup_by Block并从每个Value中减去Treatment == "Control"的{​​{1}},然后删除“控件”行。

Value

不确定,是否仅出于演示计算目的显示预期输出(library(dplyr) df %>% group_by(Block) %>% mutate(Value = Value[which.max(Treatment == "Control")] - Value) %>% filter(Treatment != "Control") # Treatment Block Year Value # <fct> <int> <int> <dbl> #1 Treat1 1 2011 -6 #2 Treat2 1 2011 2 #3 Treat1 2 2012 -6 #4 Treat2 2 2012 -2 #5 Treat1 3 2013 3 #6 Treat2 3 2013 5 Treatment)中Control-Treat1列中的值,或者OP确实希望将其用作输出。如果需要将其作为输出,我们可以使用

Control-Treat2

答案 1 :(得分:1)

某种不同的tidyverse可能是:

df %>%
 spread(Treatment, Value) %>%
 gather(var, val, -c(Block, Year, Control)) %>%
 mutate(Value = Control - val,
        Treatment = paste("Control", var, sep = " - ")) %>%
 select(Treatment, Block, Year, Value) %>%
 arrange(Block)

         Treatment Block Year Value
1 Control - Treat1     1 2011    -6
2 Control - Treat2     1 2011     2
3 Control - Treat1     2 2012    -6
4 Control - Treat2     2 2012    -2
5 Control - Treat1     3 2013     3
6 Control - Treat2     3 2013     5

答案 2 :(得分:1)

这可以通过如下的SQL自连接来完成:

library(sqldf)
sqldf("select a.Treatment || '-' || b.Treatment as Treatment, 
              a.Block, 
              a.Year, 
              a.Value - b.Value as Value
  from df a 
  join df b on a.block = b.block and 
               a.Treatment = 'Control' and 
               b.Treatment != 'Control'")

给予:

       Treatment Block Year Value
1 Control-Treat1     1 2011    -6
2 Control-Treat2     1 2011     2
3 Control-Treat1     2 2012    -6
4 Control-Treat2     2 2012    -2
5 Control-Treat1     3 2013     3
6 Control-Treat2     3 2013     5

答案 3 :(得分:0)

另一种dplyr-tidyr方法:您可以使用select删除不需要的列:

library(tidyr)
    library(dplyr)
    dummy_df %>% 
      spread(Treatment,Value) %>% 
      gather(key,value,Treat1:Treat2) %>%
      group_by(Block,Year,key) %>% 
      mutate(Val=Control-value)
   # A tibble: 6 x 6
# Groups:   Block, Year, key [6]
  Block  Year Control key    value   Val
  <int> <int>   <dbl> <chr>  <dbl> <dbl>
1     1  2011       6 Treat1    12    -6
2     2  2012       3 Treat1     9    -6
3     3  2013       6 Treat1     3     3
4     1  2011       6 Treat2     4     2
5     2  2012       3 Treat2     5    -2
6     3  2013       6 Treat2     1     5

精确的输出:

dummy_df %>% 
  spread(Treatment,Value) %>% 
  gather(key,value,Treat1:Treat2) %>% 
  mutate(Treatment=paste0("Control-",key)) %>% 
  group_by(Block,Year,Treatment) %>% 
  mutate(Val=Control-value) %>% 
  select(Treatment,everything(),-value,-key)%>% 
  arrange(Year)

结果:

# A tibble: 6 x 5
# Groups:   Block, Year, Treatment [6]
  Treatment      Block  Year Control   Val
  <chr>          <int> <int>   <dbl> <dbl>
1 Control-Treat1     1  2011       6    -6
2 Control-Treat2     1  2011       6     2
3 Control-Treat1     2  2012       3    -6
4 Control-Treat2     2  2012       3    -2
5 Control-Treat1     3  2013       6     3
6 Control-Treat2     3  2013       6     5

答案 4 :(得分:0)

另一个tidyverse解决方案。我们可以使用filter将“控制”和“处理”分离到不同的数据帧,使用left_join通过BlockYear组合它们,然后处理数据帧

library(tidyverse)

df2 <- df %>%
  filter(!Treatment %in% "Control") %>%
  left_join(df %>% filter(Treatment %in% "Control"), 
            ., 
            by = c("Block", "Year")) %>%
  mutate(Value = Value.x - Value.y) %>%
  unite(Treatment, Treatment.x, Treatment.y, sep = "-") %>%
  select(names(df))
#        Treatment Block Year Value
# 1 Control-Treat1     1 2011    -6
# 2 Control-Treat2     1 2011     2
# 3 Control-Treat1     2 2012    -6
# 4 Control-Treat2     2 2012    -2
# 5 Control-Treat1     3 2013     3
# 6 Control-Treat2     3 2013     5