2016-10-29 2 views
2

я следующий вход:Выберите имя столбца первого столбца, который соответствует определенный логический тест

id <- c("a", "b", "c", "d") 
target <- seq(from = 100, to = 400, length.out = 4) 
a <- c(300, 304, 100, 405) 
b <- c(300, 104, 100, 405) 
c <- c(85, 304, 500, 405) 
df <- as.data.frame(cbind(id, target, a, b, c)) 

Я хотел бы добавить новый столбец «столбец», который указывает на строку, которая из столбцов «а» , «b», «c» будет первым столбцом со значением, меньшим целевого решения. Запрошенный результат выглядит следующим образом:

Обязательный выход:

df$column <- c("c", "b", "a", "NA") 
df 

Я подумал про concenated если чек на строку и применить это ко всем строкам с помощью функции применяются. Однако столбцы abc довольно длинные (круглый 20, поэтому потребуется цикл), а число строк - около 4.000. Есть ли у кого-нибудь идея о том, как его решить?

+0

Спасибо за ответ. Я изменил свою систему на Mozilla/5.0 (X11, Linux x86_64) AppleWebKit/538.1 (KHTML, как и Gecko) RStudio Safari/538.1 Qt/5.4.0 с тех пор skript дает мне следующее сообщение об ошибке: Ошибка в Ops.data.frame (df ​​[, 3: 7], df [, 2]): '<' определяется только для кадров данных одинакового размера, и если я изменю код на df [, 3: 7], df [[, 2]]) Ошибка в [[.data.frame (df,, 2): отсутствует аргумент «..1», без значения по умолчанию. Любая идея, как я мог решить проблему? – Nils

ответ

3

Вот еще Векторизованное решения с использованием which. Это в основном принимает все случаи, когда target больше, а первые экземпляры используются с помощью функции duplicated.

indx <- which(df[, 3:5] < df[, 2], arr.ind = TRUE) 
indx2 <- indx[!duplicated(indx[, "row"]),] 
df[indx2[, "row"], "column"] <- names(df)[3:5][indx2[, "col"]] 
df 
# id target a b c column 
# 1 a 100 300 300 85  c 
# 2 b 200 304 104 304  b 
# 3 c 300 100 100 500  a 
# 4 d 400 405 405 405 <NA> 
+0

Спасибо за ответ. Я изменил свою систему в Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/538.1 (KHTML, как Gecko) RStudio Safari/538.1 Qt/5.4.0 с того времени Skript дает мне следующее сообщение об ошибке: Ошибка в ops.data.frame (df [, 3: 7], df [, 2]): '<' определяется только для кадров данных одинакового размера , и если я изменю код на df [, 3: 7] , df [[, 2]]) Ошибка в '[[.data.frame' (df,, 2): отсутствует аргумент« ..1 », без значения по умолчанию Любая идея, как я мог решить проблему вопрос? – Nils

5

Вы можете сделать это следующим образом:

1) Создать логическую матрицу, указывающую или нет значение в «A», «B» или «с» столбец меньше, чем целевой столбец:

m <- df[,3:5] < df[,2] 

2) Создать целочисленный вектор, который является первыми именами этих трех столбец, который имеет значение, меньший, чем целевой столбец с max.col и убедитесь, что значение NA возвращается для строк, где не было никакого значения меньше с [c(TRUE,NA)[1 + (rowSums(m) == 0)]]:

mc <- max.col(m, ties.method = 'first')[c(TRUE,NA)[1 + (rowSums(m) == 0)]] 

3) Присвоить имена в новый столбец:

df$column <- names(df[,3:5])[mc] 

, который дает:

> df 
    id target a b c column 
1 a 100 300 300 85  c 
2 b 200 304 104 304  b 
3 c 300 100 100 500  a 
4 d 400 405 405 405 <NA> 

Я отделил шаги, чтобы сделать его более ясным что делает код. Но вы можете, конечно, интегрировать его более следующим образом:

m <- df[,3:5] < df[,2] 
df$column <- names(df[,3:5])[max.col(m, ties.method = 'first')[c(TRUE,NA)[1 + (rowSums(m) == 0)]]] 
+0

Я никогда не думал, что это может быть векторизован! У меня есть +1. Это хорошее место/время, чтобы предложить некоторые отзывы? – Ivan

+0

Спасибо за ответ. Я изменил свою систему на Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/538.1 (KHTML, как Gecko) RStudio Safari/538.1 Qt/5.4.0 с тех пор skript дает мне следующее сообщение об ошибке: Ошибка в Ops.data.frame (df [, 3: 7], df [, 2]): '<', определенный только для кадров данных одинакового размера, и если я изменю код на df [, 3: 7], df [[, 2]]) Ошибка в [[.data.frame (df,, 2): аргумент «..1» отсутствует, без по умолчанию. Любая идея, как я мог решить проблему? – Nils

+0

@ Нильс не может точно сказать только сообщение об ошибке; пожалуйста, укажите [воспроизводимый пример] (http://stackoverflow.com/questions/5963269/how-to-make-a-great-r-reproducible-example/5963610) в вопросе – Jaap

0

Вы можете применить функцию вдоль строк, например. и использовать результат для заполнения вашей колонки т.д.,

searchFunction <- function(row) { 
    result <- "NA" 
    for (name in names(row)) { 
    if (name == "target" || name == "id") { 
     next 
    } 
    if (result == "NA" && as.numeric(row[name]) < as.numeric(row["target"])) { 
     result = name 
    } 
    } 
    return(result); 
} 

apply(df, 1, searchFunction) 
# [1] "c" "b" "a" "NA" 
+0

Нет необходимости в foro-loop imo. Большинство функций в R векторизованы. – h3rm4n

+0

@ h3rm4n спасибо за отзыв, мне было бы очень любопытно увидеть векторизованную версию этого – Ivan

+1

Для петель не так уж плохо в общем, но вы в основном выполняете двойной цикл здесь ('apply' также является циклом for), в то время как второй - за строку, что может стать неприятным для большого набора данных. –

Смежные вопросы