Создайте новый столбец на основе значений в других строках других столбцов

#r #loops #row #multiple-columns

Вопрос:

У меня есть фрейм данных (df) с тремя столбцами, как показано ниже:

 A   B   C
1   15  -1.60
15  17  -1.49
3   13  2.59
17  18  3.34
 

Я хочу создать новый столбец «D», в котором каждая строка является копией значения в столбце «C», в котором в своей строке столбец «A» имеет значение, равное значению столбца «B», и если нет равного значения, поставьте «NA»; что-то вроде ниже:

 A   B   C   D
1   15  -1.6    -1.49
15  17  -1.49   3.34
3   13  2.59    NA
17  1   3.34    -1.6
 

Я попытался написать цикл, чтобы сделать столбец «D» из столбца «C», но это не работает:

 for(i in 1:nrow(df)) {
      if (df$B==df$A){
        df$D==df$C
      }else{
        df$D==NA}
    }
 

Есть ли какой-нибудь способ вместо циклического создания этой колонки? Если нет, то как я могу использовать циклы?

Ответ №1:

Здесь не нужны петли. Много раз (читай: большую часть времени) вы получите лучшие/более быстрые результаты (в R), если оставите в покое циклы for и будете использовать векторизованные функции.

Вот data.table подход, использующий соединение по ссылке

 library( data.table )

df <- fread("A   B   C
1   15  -1.60
15  17  -1.49
3   13  2.59
17  1  3.34")

#or use the code:  setDT( df )

df[ df , D := i.C, on = .(B = A)][]
#     A  B     C     D
# 1:  1 15 -1.60 -1.49
# 2: 15 17 -1.49  3.34
# 3:  3 13  2.59    NA
# 4: 17  1  3.34 -1.60
 

Ответ №2:

В base R , мы можем использовать match

 df$D <- with(df, C[match(B, A)])
 

-выход

 df
#   A  B     C     D
#1  1 15 -1.60 -1.49
#2 15 17 -1.49  3.34
#3  3 13  2.59    NA
#4 17  1  3.34 -1.60
 

данные

 df <- structure(list(A = c(1L, 15L, 3L, 17L), B = c(15, 17, 13, 1), 
    C = c(-1.6, -1.49, 2.59, 3.34)),
    row.names = c(NA, -4L), class = "data.frame")
 

Ответ №3:

Используя dplyr пакет, вы можете сделать следующее:

 # data 
df <- 
    data.frame(A = c(1, 15, 3, 17), 
               B = c(15, 17, 13, 1), 
               C = c(-1.6, -1.49, 2.59, 3.34))

# code
library(dplyr)
df %>% 
    left_join(df %>% select(A, C) %>% rename(D = C), 
              by = c("B" = "A"))