Вычислить разницу между строкой в наборе данных и всеми строками в другом наборе данных в R

#r #difference

#r #разница

Вопрос:

У меня есть 2 набора данных, я хочу для каждой строки в datset1 вычислить разницу между всеми строками в другом наборе данных2. Я также заменяю любую отрицательную разницу на 0. Вот простой пример моих 2 наборов данных (потому что у меня есть наборы данных около 1000 * 1000).

 df1 <- data.frame(ID = c(1, 2), Obs = c(1.0, 2.0), var=c(2.0,5.0))
df2 <- data.frame(ID = c(2, 1), Obs = c(3.0, 2.0),var=c(7.0,3.0))

 df1
  ID Obs var
1  1   1   2
2  2   2   5

 df2
  ID Obs var
1  2   3   7
2  1   2   3


for(i in 1:nrow(df1)){
  b1=as.matrix(df1)
  b2=as.matrix(df2)
  diff= b1-b2
  diff[which(diff < 0 )] <- 0
 
  diff.data= data.frame(cbind(diff, total = rowSums(diff)))
 
}

 diff.data
  ID Obs var total
1  0   0   0     0
2  1   0   2     3
  

Это то, что я смог сделать, я сделал разницу между 2 наборами данных, заменил отрицательные значения на 0, а также был заинтересован в суммировании значений столбцов после. Для первой строки в df1 я хотел бы вычислить разницу между всеми строками в df2, а для второй строки в df1 вычислить разницу между всеми строками в df2 (и так далее). Обратите внимание, что я не должен вычислять разницу между идентификаторами (я не знаю, как это сделать, может быть, изменить diff= b1-b2 на diff= b1[,-1]-b2[,-1] ? ). Я хочу сохранить идентификатор из df1, чтобы отслеживать моих пациентов (случай моего набора данных). Я хотел бы иметь что-то подобное

 diff.data
ID Obs var total
1  0   0   0
1  0   0   0
2  0   0   0
2  0   2   2
  

Заранее благодарю вас за помощь.

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

 difference=function(df1,df2){
  if(class(df1) != "data.frame" || class(df2) != "data.frame") stop(" df1 or df2 is not  a dataframe!")
  df1=data.frame(df1)
  df2=data.frame(df2)
  ID1=seq(nrow(df1))
  ID2=seq(nrow(df2))
  new_df1 = df1[rep(ID1, each = nrow(df2)), ]
  new_df1[-1] = new_df1[-1] - df2[rep(seq(nrow(df2)), nrow(df1)), -1]
  new_df1[new_df1 < 0] = 0
  new_df1$total = rowSums(new_df1[-1])
  rownames(new_df1) = NULL
  output=new_df1
  return(output)
  
}
  

Я знаю тот факт, что я указал df1=data.frame(df1) должен быть фреймом данных, просто я не знаю, как также включить, что это может быть матрица.

Еще раз заранее благодарю вас за помощь.

Ответ №1:

Вы можете повторять каждую строку в df1 with for nrow(df2) times и каждую строку в df2 for nrow(df1) times, чтобы размер фреймов данных был одинаковым, и мы могли напрямую вычитать значения.

 #Repeat each row of df1 nrow(df2) times
new_df1 <- df1[rep(df1$ID, each = nrow(df2)), ]
#Repeat rows of df2 and subtract
new_df1[-1] <- new_df1[-1] - df2[rep(seq(nrow(df2)), nrow(df1)), -1]
#Replace negative values with 0
new_df1[new_df1 < 0] <- 0
#Add row-wise sum
new_df1$total <- rowSums(new_df1[-1])
#Remove rownames
rownames(new_df1) <- NULL
new_df1

#  ID Obs var total
#1  1   0   0     0
#2  1   0   0     0
#3  2   0   0     0
#4  2   0   2     2
  

Комментарии:

1. Спасибо @Ronak Shah за помощь! Я действительно одобряю это! Не могли бы вы, пожалуйста, взглянуть на мой код и сказать мне, что мне делать, если я хочу, чтобы мои наборы данных были либо матричными, либо фреймами данных? На самом деле я не знаю, должен ли я ответить на свой вопрос, чтобы опубликовать измененный код, или просто отредактировать свой вопрос? все еще новичок в Stack. Спасибо!

2. Вы можете отредактировать свой вопрос, включив в него имеющийся у вас код.

3. Спасибо @Ronak! Я отредактировал свой пост, я был бы признателен за вашу помощь.

4. Почему бы не использовать is.data.frame и is.matrix не узнать, являются ли передаваемые данные фреймом данных или матрицей. Что-то вроде этого if(!(is.data.frame(df1) amp;amp; is.data.frame(df2) || is.matrix(df1) amp;amp; is.matrix(df2))) stop('')

5. Спасибо @Ronak! Это работает. Сначала я подумал, почему бы просто не использовать if(class(df1) = "character" || class(df2) = "character" ) then stop , но я боялся, что пользователь введет что-нибудь еще и продолжит вычисления. Таким образом, я уверен. Еще раз спасибо за вашу помощь и терпение !