Вычтите столбцы в кадре данных R, но сохраните значения var1 или var2, когда другой равен NA - PullRequest
0 голосов
/ 02 сентября 2018

Я хотел вычесть один столбец из другого в R, и это оказалось сложнее, чем я думал.

Предположим, это мои данные (столбцы a и b), а столбец c - это то, что я хочу, а именно a - b, но сохраняю a при b==NA и наоборот:

   a    b    c
1  2    1    1
2  2   NA    2
3 NA    3    3
4 NA   NA   NA

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

matrixStats::rowDiffs(data, na.rm=T) # only works for matrix-format, and returns NA's

dat$c <- dat$a - dat$b + ifelse(is.na(dat$b),dat$a,0) + ifelse(is.na(dat$a),dat$b,0) # seems like a desparately basic solution, but not even this does the trick as it also returns NA's

apply(dat[,(1:2)], MARGIN = 1,FUN = diff, na.rm=T) # returns NA's

dat$b<-dat$b*(-1)
dat$c<-rowSums(dat,na.rm=T) # this kind of works but it's a really ugly workaround

Кроме того, если вы можете придумать решение dplyr, поделитесь своими знаниями. Я даже не знал, что попробовать.

Удалит этот вопрос, если вы считаете, что он дублирует существующий, хотя ни один из существующих потоков не был особенно полезен.

Ответы [ 3 ]

0 голосов
/ 02 сентября 2018

Вы можете попробовать использовать функцию coalesce из пакета dplyr:

dat <- data.frame(a=c(2, 2, NA, NA), b=c(1, NA, 3, NA))
dat$c <- coalesce(dat$a - coalesce(dat$b, 0), dat$b)
dat$c

   a  b  c
1  2  1  1
2  2 NA  2
3 NA  3  3
4 NA NA NA

Идея в том, чтобы взять a минус b или a в одиночку, если b будет NA. Если все это выражение все еще NA, то это означает, что a также NA, и в этом случае мы берем b.

0 голосов
/ 02 сентября 2018

Вот один вариант с base R, где мы replace элементы NA с 0, Reduce это единичное vector, взяв разность строк и изменив строки, содержащие все элементы NA до NA

df1$c <- abs(Reduce(`-`, replace(df1, is.na(df1), 0))) *
               NA^ (!rowSums(!is.na(df1)) )
df1$c
#[1]  1  2  3 NA

Или используя аналогичный метод с data.table

library(data.table)
setDT(df1)[!is.na(a) | !is.na(b), c := abs(Reduce(`-`, 
               replace(.SD, is.na(.SD), 0)))]

данные

df1 <- structure(list(a = c(2L, 2L, NA, NA), b = c(1L, NA, 3L, NA)), 
 row.names = c("1", "2", "3", "4"), class = "data.frame")
0 голосов
/ 02 сентября 2018

Попробуйте это (решение Base R):

Если df$b равно NA, тогда просто примите значение df$a, в противном случае, если df$a равно NA, просто примите значение df$b, иначе сделайте df$a-df$b

df$c=ifelse(is.na(df$b),df$a,ifelse(is.na(df$a),df$b,df$a-df$b))

Выход:

df
   a  b  c
1  2  1  1
2  2 NA  2
3 NA  3  3
4 NA NA NA
...