Вычтите строки, варьирующиеся в одном столбце, но оставьте фиксированные - PullRequest
1 голос
/ 22 марта 2019

У меня есть эксперимент, в котором мне нужно вычесть значения двух разных обработок из контроля (базовый уровень), но эти вычитания должны соответствовать другим столбцам, названным блоком и выбранным годом.

Пустой фрейм данных:

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 ]

1 голос
/ 22 марта 2019

Это можно сделать с помощью самостоятельного соединения 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
1 голос
/ 22 марта 2019

А как-то иначе 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
1 голос
/ 22 марта 2019

Мы можем использовать dplyr, group_by Block и вычитать Value, где Treatment == "Control" из каждого Value и удалять строки "Control".

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, Control-Treat2) показаны только для демонстрационных целей расчета, или OP действительно хочет это как вывод.В случае, если это необходимо в качестве вывода, мы можем использовать

df %>%
  group_by(Block) %>%
  mutate(Value = Value[which.max(Treatment == "Control")]  - Value, 
         Treatment = paste0("Control-", Treatment)) %>%
  filter(Treatment != "Control-Control")

#   Treatment      Block  Year Value
#  <chr>          <int> <int> <dbl>
#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
0 голосов
/ 22 марта 2019

Другое решение tidyverse. Мы можем использовать filter, чтобы разделить «Контроль» и «Обработка» на разные фреймы данных, использовать left_join, чтобы объединить их по Block и Year, а затем обработать фрейм данных.

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
0 голосов
/ 22 марта 2019

Другой подход 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...