Упорядочить строки по парам в R на основе двух столбцов - PullRequest
0 голосов
/ 23 мая 2018

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

Я хочу изменить порядок строк, чтобы я мог видеть, сколько сообщений пользователи обменялись между собой.Если один пользователь отправил сообщение, но другой не ответил, мне нужно иметь значение 0 в столбце Messages_sent.

table

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

Пожалуйста, посоветуйте, как я могу изменить таблицу данных!

Ответы [ 2 ]

0 голосов
/ 23 мая 2018

Вот шаги, использующие базовые функции 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

В зависимости от размера вашего набора данных один из этих методов может быть более эффективным, чем два других.

0 голосов
/ 23 мая 2018

С помощью dplyr, чтобы получить таблицу, указанную в вашем описании, этот код должен работать.Но если вы хотите сложить счет в обоих направлениях, первая строка содержит все, что вы можете.

df <- merge(df,df
  ,by.x=c("from_id","to_id"),by.y=c("to_id","from_id")
  ,all.x=TRUE,all.y=TRUE)
df <- mutate(df,Messages_sent.x=coalesce(Messages_sent.x,0),
                Messages_sent.y=coalesce(Messages_sent.y,0))
df$row <- 1:nrow(df)
rbind(select(df,-Messages_sents.y) %>%
        rename(Messages_sent=Messages_sent.x),
      select(df,-Messages_sent.x) %>% 
        rename(Messages_sent=Messages_sent.y,from_id=to_id,to_id=from_id)
     ) %>% arrange(row) %>% select(-row)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...