R: Создать новый столбец с разницей между значениями из того же столбца, где одно из них соответствует условию - PullRequest
0 голосов
/ 11 октября 2019

У меня есть фрейм данных со столбцами: Slot, Period, SortNumber и Value. Фактически, этот фрейм данных был создан для чтения данных из некоторых баз данных доступа, и я делаю некоторую работу над ним, сравнивая строки и т. Д. Итак, я также использую пакеты RODBC и stringr. Эта часть кода прекрасно работает в R и Power BI, поэтому я не воспроизводил здесь. Это пример моего последнего фрейма данных:

dfAccess <- data.frame(Slot = c("X1", "X2", "X3", "X1", "X3","X1", "X2", "X3", "X2", "X3"), 
                       Period = c(1,1,1,2,2,1,1,1,2,2), 
                       SortNumber = c(1, 1, 1, 1,1,2,2,2,2,2), 
                       Value = c(9,5,7,9,5,6,4,8,2,1))

Этот фрейм данных не имеет слота X2 для периода 2 в SortNumber 1 и слота X1 для периода 2 в SortNumber 2 (он может пропустить любую строку). Визуально это означает:

Slot     Period    SortNumber    Value    
=======================================
X1         1          1           9    
X2         1          1           5    
X3         1          1           7    
X1         2          1           9   
X3         2          1           5    
X1         1          2           6    
X2         1          2           4    
X3         1          2           8    
X2         2          2           2    
X3         2          2           1    

Я хочу создать новый столбец (DiffValue), который вычисляет разницу между значением и значением, где SortNumer = 1 (сгруппированы по слоту и периоду)

Проблема в том, что Slot и Period не обязательно имеют одинаковые значения для каждого SortNumber. В этом случае я хотел бы использовать 0 в качестве значения по умолчанию и рассчитать разницу для каждой строки.

Я использую dplyr и, когда данные согласованы, работает нормально. В противном случае я получаю ошибку: "Column DiffValue must be length 1 (the group size), not 0"

  dfAccess <-dfAccess %>%
  group_by(Slot, Period) %>%
  mutate(DiffValue = Value - Value[SortNumber == 1] )

Используя эти данные, я хотел бы видеть следующее:

Slot     Period    SortNumber    Value    DiffValue
=========================================================
X1         1          1           9            0
X2         1          1           5            0
X3         1          1           7            0
X1         2          1           9            0
X3         2          1           5            0
X1         1          2           6           -3
X2         1          2           4           -1
X3         1          2           8            1
X2         2          2           2           -2 ("0" - 2)
X3         2          2           1           -4

Это способ сделать это?

РЕДАКТИРОВАТЬ: Я изменил части исходного сообщения, потому что Синь Нгуен обнаружил проблему в данных, но у меня все еще есть проблемы для расчета разницы.

Спасибо!

Ответы [ 2 ]

1 голос
/ 12 октября 2019

Все еще не до конца уверен в характере вашего набора данных и в том, чего вы хотите достичь. Но это устранит ошибки и для пары Slot+Period, у которой нет SortNumber==1, будет автоматически использоваться 0(Zero) в качестве значения по умолчанию.

# Sample data set with one pair of Slot+Period that doesn't have any SortNumber==1
dfAccess <- data.frame(Slot = c("X1", "X2", "X3", "X1", "X2", "X3","X1", "X2", "X3","X1", "X2", "X3"), 
           Period = c(1,1,1,2,2,2,1,1,1,2,2,2), 
           SortNumber = c(1, 1, 2, 1,1,1,2,2,2,2,2,2), 
           Value = c(9,5,7,9,1,5,6,4,8,10,2,1))

# Your command will generate an error
dfAccess <-dfAccess %>%
      group_by(Slot, Period) %>%
      mutate(DiffValue = Value - Value[SortNumber == 1] )
# ​Error: Column `DiffValue` must be length 2 (the group size) or one, not 0

# This command will only take 1st value of SortNumber==1 in any pair Slot+Number
dfAccess %>%
    group_by(Slot, Period) %>%
    mutate(DiffValue = Value - first(Value[SortNumber==1], default=0)) %>%
    ungroup()
0 голосов
/ 12 октября 2019

Не уверен, правильно ли я понимаю, но в качестве упражнения я преобразовал ваш фрейм данных в более широкий формат, чтобы его было легче просматривать:

df <- dfAccess %>%
  filter(SortNumber == 1) %>% 
  full_join(
    dfAccess %>% 
      filter(SortNumber == 2),
    by= c("Slot", "Period")
  ) %>% 
  mutate_at(vars(Value.x, Value.y), replace_na, 0) %>%    # impute missing values with zero
  rowwise() %>% 
  mutate(
    DiffValue = Value.y - Value.x
  )

df содержит:

# A tibble: 6 x 7
  Slot  Period SortNumber.x Value.x SortNumber.y Value.y DiffValue
  <fct>  <dbl>        <dbl>   <dbl>        <dbl>   <dbl>     <dbl>
1 X1         1            1       9            2       6        -3
2 X2         1            1       5            2       4        -1
3 X3         1            1       7            2       8         1
4 X1         2            1       9           NA       0        -9
5 X3         2            1       5            2       1        -4
6 X2         2           NA       0            2       2         2

Обратите внимание на строки 4 и 6, где отсутствует одна или другая SortNumber.

Это может быть указано в формате, аналогичном тому, который вы запрашивали (мой код уродлив, ноработает):

df2 <- df %>% 
  select(1:4) %>% 
  rename(
    SortNumber = 3,
    Value = 4
  ) %>% 
  mutate(
    DiffValue = 0
  ) %>% 
  bind_rows(
    df %>% 
      select(-3, -4) %>% 
      rename(
        SortNumber = 3,
        Value = 4
      )
  )

И df2 содержит:

# A tibble: 12 x 5
   Slot  Period SortNumber Value DiffValue
   <fct>  <dbl>      <dbl> <dbl>     <dbl>
 1 X1         1          1     9         0
 2 X2         1          1     5         0
 3 X3         1          1     7         0
 4 X1         2          1     9         0
 5 X3         2          1     5         0
 6 X2         2         NA     0         0
 7 X1         1          2     6        -3
 8 X2         1          2     4        -1
 9 X3         1          2     8         1
10 X1         2         NA     0        -9
11 X3         2          2     1        -4
12 X2         2          2     2         2

Если вы не хотите вменять "SortNumber == 2", то альтернативой будет:

df3 <- dfAccess %>%
  filter(SortNumber == 1) %>% 
  full_join(
    dfAccess %>% 
      filter(SortNumber == 2),
    by= c("Slot", "Period")
  ) %>% 
  mutate_at(vars(Value.x), replace_na, 0) %>% 
  rowwise() %>% 
  mutate(
    DiffValue = Value.y - Value.x
  ) %>% 
  select(1:4) %>% 
  rename(
    SortNumber = 3,
    Value = 4
  ) %>% 
  mutate(
    DiffValue = 0
  ) %>% 
  bind_rows(
    df %>% 
      select(-3, -4) %>% 
      rename(
        SortNumber = 3,
        Value = 4
      )
  ) 

И df3 будет:

# A tibble: 12 x 5
   Slot  Period SortNumber Value DiffValue
   <fct>  <dbl>      <dbl> <dbl>     <dbl>
 1 X1         1          1     9         0
 2 X2         1          1     5         0
 3 X3         1          1     7         0
 4 X1         2          1     9         0
 5 X3         2          1     5         0
 6 X2         2         NA     0         0
 7 X1         1          2     6        -3
 8 X2         1          2     4        -1
 9 X3         1          2     8         1
10 X1         2         NA    NA        NA
11 X3         2          2     1        -4
12 X2         2          2     2         2

HTH или, по крайней мере, даст вам и идею о том, как решить эту проблему

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...