Вот шаги, использующие базовые функции R:
df <- data.frame(from_id=c(624227,624227,624227,624227,624227,624227,667255,667255,667255,7134655,713465),
to_id = c(352731,693915,184455,771100,503940,91558,626814,857601,862512,156874,419242),
message_sent=c(1,6,2,1,1,1,2,7,3,1,1))
# merge dataset together with itself swapping from_id and to_id columns
df.full <- merge(df,df, by.x=c("from_id","to_id"), by.y=c("to_id","from_id"),suffixes = c(".x",".y"), all=TRUE)
# fill missing values with 0
# those records will correspond to all the pairs where
# someone did not send any messages back
df.full[is.na(df.full)] <- 0
# calculate total number of messages for each pair:
df.full$total <- df.full$message_sent.x + df.full$message_sent.y
head(df.full)
# from_id to_id message_sent.x message_sent.y total
# 1 91558 624227 0 1 1
# 2 156874 7134655 0 1 1
# 3 184455 624227 0 2 2
# 4 352731 624227 0 1 1
# 5 419242 713465 0 1 1
# 6 503940 624227 0 1 1
Для очень больших наборов данных базовые функции R могут быть медленными, в этом случае вы можете изучить использование библиотеки dplyr (для большинства шагов здесь она имеет похожие функции):
library(dplyr)
df.full.2 <- merge(df,df # merge dataframe and switched one
,by.x=c("from_id","to_id"),by.y=c("to_id","from_id")
,all.x=TRUE,all.y=TRUE) %>%
mutate(message_sent.x=coalesce(message_sent.x,0), # replace NAs with 0
message_sent.y=coalesce(message_sent.y,0)) %>%
mutate(total=rowSums(.[3:4])) # calculate total number of messages
head(df2.full.2)
# from_id to_id message_sent.x message_sent.y total
#1 91558 624227 0 1 1
#2 156874 7134655 0 1 1
#3 184455 624227 0 2 2
#4 352731 624227 0 1 1
#5 419242 713465 0 1 1
#6 503940 624227 0 1 1
Если важно, чтобы записи в парах следовали друг за другом, вы также можете добавить следующий код:
df2.full.3 <- df2.full.2 %>%
mutate(pair.id=sprintf("%06d%6d",pmin(from_id,to_id ),
pmax(from_id,to_id ))) %>%
arrange(pair.id) %>% select(-pair.id)
head(df2.full.3)
# from_id to_id message_sent.x message_sent.y total
#1 91558 624227 0 1 1
#2 624227 91558 1 0 1
#3 156874 7134655 0 1 1
#4 7134655 156874 1 0 1
#5 184455 624227 0 2 2
#6 624227 184455 2 0 2
Существует также пакет data.table, который также оченьэффективен для очень больших наборов данных:
library(data.table)
# convert dataframe to datatable
setDT(df)
df.full <- merge(df,df, by.x=c("from_id","to_id"), by.y=c("to_id","from_id"),
suffixes = c(".x",".y"), all=TRUE)
# substitute NAs with zeros
for (j in 3:4)set(df.full,which(is.na(df.full[[j]] )),j,0)
# calculate the total number of messages
df.full[, total:=message_sent.x+message_sent.y]
head(df.full)
# from_id to_id message_sent.x message_sent.y total
# 1: 91558 624227 0 1 1
# 2: 156874 7134655 0 1 1
# 3: 184455 624227 0 2 2
# 4: 352731 624227 0 1 1
# 5: 419242 713465 0 1 1
# 6: 503940 624227 0 1 1
В зависимости от размера вашего набора данных один из этих методов может быть более эффективным, чем два других.