Вычтите / найдите разницу между 2 кадрами данных с разным количеством столбцов - PullRequest
0 голосов
/ 07 февраля 2019

Я относительно новичок в R и не смог найти нигде, который отвечает на этот запрос.

У меня есть 2 кадра данных с одинаковым количеством строк, но с разным количеством столбцов.Я хочу вычесть значения в соответствующих столбцах, чтобы определить разницу между двумя кадрами данных.

Например, эти 2 кадра данных напоминают те, с которыми я работаю:

df1<-data.frame(Measure=rep("test",3),Filename=c("filename1","filename2","filename3"),Op1=c(79,72,95),Op2=c(NA,NA,5),Op3=c(75,64,66),Op4=c(86,71,58))

   Filename  Op1  Op2  Op3  Op4
1  filename1  79   NA   75   86
2  filename2  72   NA   64   71
3  filename3  95   5    66   58

df2<-data.frame(Measure=rep("test",3),Filename=c("filename1","filename2","filename3"),Op1=c(9,NA,5),Op4=c(80,70,50))

   Filename  Op1  Op4
1  filename1   9   80
2  filename2   NA  70
3  filename3   5   50

В настоящее время у меня есть функция, которая объединяет 2 кадра данных и суммирует данные, которые выглядят следующим образом:

CalcFunSum<-function(MeasureName,BoxNumbers){
  temp<-data.frame()
  for (i in BoxNumbers){
    data<-melt(BoxNumbers[i])
    temp<-temp %>% bind_rows(data)
  }
  temp<-cbind(Measure = MeasureName,dcast(temp,Filename~variable,sum,fill = 0))
  temp
}

Итак, CalcFunSum(test,c(df1,df2)) сложит вместе 2 фрейма данных и выдаст

  Measure  Filename  Op1  Op2  Op3  Op4
1  test   filename1  88   NA   75   166
2  test   filename2  72   NA   64   141
3  test   filename3  100  5    66   108

Что-то похожее на выполнение вычисления df1-df2 для получения:

  Measure  Filename  Op1  Op2  Op3  Op4
1  test   filename1  70   NA   75   6
2  test   filename2  72   NA   64   1
3  test   filename3  90   5    66   8

Я пытался заменить sum в функции на diff, но это не сработало

Есть идеи, как это сделать?

edit - Iпонял, что функция включала ссылку на список, в котором я держу эти фреймы данных, и изменил его.

Продолжение: работа со значениями NA

Итак, ответы до сих пор работают,но при тестировании с моими фактическими данными я заметил, что в случаях, когда df2 имеет NA, но df1 имеет значение, результирующий вывод содержит NA, а не значение в df1.Я собираюсь изменить одно из значений в df2 на NA, чтобы отразить это.

В текущих ответах @akrun и @IceCreamToucan результат будет

  Measure  Filename  Op1  Op2  Op3  Op4
1  test   filename1  70   NA   75   6
2  test   filename2  NA   NA   64   1
3  test   filename3  90   5    66   8

Я предполагаю этогде-то в коде есть NA.rm = T, или мне нужно иметь дело со значениями NA на более ранних этапах процесса, но было бы полезно узнать, есть ли в ответах твики, которые могли бы с этим разобраться.

Ответы [ 2 ]

0 голосов
/ 07 февраля 2019

Если вы сравниваете одну строку в df1 с той же строкой в ​​df2, т.е. сопоставляете индексы и не проверяете равенство некоторого столбца соединения, вы можете просто вычесть df2[common_columns] из df1[common_columns] и назначитьрезультат возвращается к df1 (или к копии).

common <- intersect(names(df1), names(df2))[-(1:2)]
new <- df1 # or copy(df1) if df1 is a data.table
new[common] <- df1[common] - df2[common]


new
#   Measure  Filename Op1 Op2 Op3 Op4
# 1    test filename1  70  NA  75   6
# 2    test filename2  70  NA  64   1
# 3    test filename3  90   5  66   8

Редактировать: Если некоторые значения в df2 равны NA, вы можете replace их с 0 до вычитания

common <- intersect(names(df1), names(df2))[-(1:2)]
new <- df1
new[common] <- new[common] - replace(df2[common], is.na(df2[common]), 0)


new
#   Measure  Filename Op1 Op2 Op3 Op4
# 1    test filename1  70  NA  75   6
# 2    test filename2  72  NA  64   1
# 3    test filename3  90   5  66   8
0 голосов
/ 07 февраля 2019

Вот один вариант с объединением с использованием data,table.Получите имена столбцов, общие для обоих наборов данных (intersect), и удалите имена, которые не нужны для сравнения (setdiff)

library(data.table)
nm1 <- setdiff(intersect(names(df1), names(df2)), c("Measure", "Filename"))

Затем выполните объединение on 'Измерение', 'Имя файла ', получите значения столбцов (' nm1 ') из' df1 'и соответствующих столбцов в' df2 '.Здесь это будет i., так как 'df2' находится в i-й позиции (таблица данных следует тому же формату [i, j, by]. Используя mget, он возвращает столбцы в list, мыполучить разницу (-) обоих наборов столбцов с Map и обновить, присвоив (:=) значения, которые будут отражаться в исходном наборе данных ('df1')

setDT(df1)[df2, (nm1) := Map(`-`, mget(nm1),
           mget(paste0("i.", nm1))), on = .(Measure, Filename)]
df1
#   Measure  Filename Op1 Op2 Op3 Op4
#1:    test filename1  70  NA  75   6
#2:    test filename2  70  NA  64   1
#3:    test filename3  90   5  66   8

Обновить

Любое значение по сравнению с NA возвращает NA. Аналогично,

72-NA
#[1] NA

Чтобы избежать этой проблемы, мы можем replace NA с 0 и затем сделать разницу

setDT(df1)[df2, (nm1) := Map(function(x, y) replace(x, is.na(x), 0) - 
     replace(y, is.na(y), 0), 
    mget(nm1),mget(paste0("i.", nm1))), on = .(Measure, Filename)]

df1
#   Measure  Filename Op1 Op2 Op3 Op4
#1:    test filename1  70  NA  75   6
#2:    test filename2  72  NA  64   1
#3:    test filename3  90   5  66   8
...