Условно замените NA символьными строками во фрейме данных в R - PullRequest
0 голосов
/ 31 мая 2018

У меня есть фрейм данных, который выглядит примерно так:

df <- as.data.frame(matrix(c("True Organic", "True Organic", NA, NA, NA, 0,
         "True Organic", "True Organic", NA, NA, NA, 0,
         "Organic Search (SEO)", "Induced Organic", NA, NA, NA, 0,
         "Display", NA, NA, NA, NA, 0,
         "Social Ads (Act)", "Induced Organic", "Induced Organic", NA, NA, 1,
         "Referral", "Social Ads (Act)", NA, NA, NA, 0,
         "Special Emails", "Induced Organic", NA, NA, NA, 1,
         "Daily Email", "Daily Email", "Daily Email", NA, NA, 0), nrow = 8,
         ncol = 6, byrow = TRUE, dimnames = list(NULL, c("Node_1", "Node_2",
                                                         "Node_3", "Node_4",
                                                         "Node_5", "conversion"))), ,
         stringsAsFactors = FALSE)


df

                Node_1           Node_2          Node_3 Node_4 Node_5 conversion
1         True Organic     True Organic            <NA>   <NA>   <NA>          0
2         True Organic     True Organic            <NA>   <NA>   <NA>          0
3 Organic Search (SEO)  Induced Organic            <NA>   <NA>   <NA>          0
4              Display             <NA>            <NA>   <NA>   <NA>          0
5     Social Ads (Act)  Induced Organic Induced Organic   <NA>   <NA>          1
6             Referral Social Ads (Act)            <NA>   <NA>   <NA>          0
7       Special Emails  Induced Organic            <NA>   <NA>   <NA>          1
8          Daily Email      Daily Email     Daily Email   <NA>   <NA>          0

Для каждой строки я хочу заменить все NA на строку "Null", если столбец преобразования для этой строки равен0 или с «Преобразованием», если столбец преобразования равен 1.

Мой окончательный вывод должен выглядеть следующим образом.

df_desired <- as.data.frame(matrix(c("True Organic", "True Organic", "Null", "Null", "Null", 0,
                                 "True Organic", "True Organic", "Null", "Null", "Null", 0,
                                 "Organic Search (SEO)", "Induced Organic", "Null", "Null", "Null", 0,
                                 "Display", "Null", "Null", "Null", "Null", 0,
                                 "Social Ads (Act)", "Induced Organic", "Induced Organic", "Conversion", "Conversion", 1,
                                 "Referral", "Social Ads (Act)","Null", "Null", "Null", 0,
                                 "Special Emails", "Induced Organic", "Converison", "Conversion", "Conversion", 1,
                                 "Daily Email", "Daily Email", "Daily Email", "Null", "Null", 0), nrow = 8,
                               ncol = 6, byrow = TRUE, dimnames = list(NULL, c("Node_1", "Node_2",
                                                                               "Node_3", "Node_4",
                                                                               "Node_5", "conversion"))), ,
                        stringsAsFactors = FALSE)


df_desired 


               Node_1           Node_2          Node_3     Node_4     Node_5 conversion
1         True Organic     True Organic            Null       Null       Null          0
2         True Organic     True Organic            Null       Null       Null          0
3 Organic Search (SEO)  Induced Organic            Null       Null       Null          0
4              Display             Null            Null       Null       Null          0
5     Social Ads (Act)  Induced Organic Induced Organic Conversion Conversion          1
6             Referral Social Ads (Act)            Null       Null       Null          0
7       Special Emails  Induced Organic      Converison Conversion Conversion          1
8          Daily Email      Daily Email     Daily Email       Null       Null          0  

Я могу сделать это с помощью вложенного цикла for.

  for (i in 1:nrow(df)){
  for (j in 1:ncol(df)){
    df[i,j] <- ifelse(((is.na(df[i,j])) & df[i,]$conversion == "1"), "Conversion", df[i,j]) 
    for (j in 1:ncol(df)){
      df[i,j] <- ifelse(((is.na(df[i,j])) & df[i,]$conversion == "0"), "Null", df[i,j])
    }   
  }
}

К сожалению, это плохо масштабируется.Должен быть лучший способ сделать это.Любые предложения будут ценны.Заранее спасибо!

Ответы [ 3 ]

0 голосов
/ 01 июня 2018

Другая альтернатива с использованием dplyr:

library(dplyr)
df <- df %>% 
  mutate_all(funs(case_when(
    is.na(.) & conversion == 0 ~ "Null", 
    is.na(.) & conversion == 1 ~ "conversion", 
    TRUE ~ .
)))
0 голосов
/ 01 июня 2018

Сделайте это с одним индексированным назначением, полагаясь на индекс row каждого значения NA для подстановки столбца df$conversion:

df[is.na(df)] <- c("Null","Conversion")[as.numeric(df$conversion)+1][row(df)[is.na(df)]]

#                Node_1           Node_2          Node_3     Node_4     Node_5 conversion
#1         True Organic     True Organic            Null       Null       Null          0
#2         True Organic     True Organic            Null       Null       Null          0
#3 Organic Search (SEO)  Induced Organic            Null       Null       Null          0
#4              Display             Null            Null       Null       Null          0
#5     Social Ads (Act)  Induced Organic Induced Organic Conversion Conversion          1
#6             Referral Social Ads (Act)            Null       Null       Null          0
#7       Special Emails  Induced Organic      Conversion Conversion Conversion          1
#8          Daily Email      Daily Email     Daily Email       Null       Null          0

Это должно быть быстрым для выполнения.Вот 1,5 миллиона строк и 115 столбцов, обработанных за 4,2 секунды.

df <- df[sample(1:8,1.5e6,replace=TRUE),c(sample(1:5,115,replace=TRUE),6)]
dim(df)
#[1] 1500000     116
system.time({
  df[is.na(df)] <- c("Null","Conversion")[as.numeric(df$conversion)+1][row(df)[is.na(df)]]
})
#   user  system elapsed 
#   2.59    1.61    4.20 
0 голосов
/ 01 июня 2018

Давайте напишем небольшую функцию, которая делает это с одним вектором (ввод обоих векторов):

foo = function(x, conversion) {
    x = ifelse(!is.na(x), x, ifelse(conversion == 1, "Conversion", "Null"))
}

Затем простой цикл, чтобы сделать это для всех столбцов, кроме conversion:

for (col in setdiff(names(df), "conversion")) {
    df[[col]] = foo(df[[col]], df$conversion)
}

df
#                 Node_1           Node_2          Node_3     Node_4     Node_5 conversion
# 1         True Organic     True Organic            Null       Null       Null          0
# 2         True Organic     True Organic            Null       Null       Null          0
# 3 Organic Search (SEO)  Induced Organic            Null       Null       Null          0
# 4              Display             Null            Null       Null       Null          0
# 5     Social Ads (Act)  Induced Organic Induced Organic Conversion Conversion          1
# 6             Referral Social Ads (Act)            Null       Null       Null          0
# 7       Special Emails  Induced Organic      Conversion Conversion Conversion          1
# 8          Daily Email      Daily Email     Daily Email       Null       Null          0

Вот слегка оптимизированная версия.Это может сэкономить вам еще несколько секунд на 1M + рядах.

foo_x = function(x, conversion) {
    x_na = is.na(x)
    conversion_1 = conversion == 1
    x[x_na & conversion_1] = "Conversion"
    x[x_na & !conversion_1] = "Null"
    return(x)
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...