Создание переменной, которая отмечает первое наблюдаемое значение в одном столбце, найденное в другом столбце

#r #dplyr #tidyverse

#r #dplyr #tidyverse

Вопрос:

В данных ключевыми переменными являются: ‘слушатель’ и ‘динамик’. Первый прослушиватель, наблюдаемый для каждого «потока», является исходным автором потока.

Я пытаюсь создать отдельную переменную «участие автора», которая помечает в двоичном формате (0, 1) строки, в которых автор потока был говорящим.

Тестовые данные:

 structure(list(topic = c(1, 1, 1, 1, 2, 2, 2, 2, 2, 2), thread = c(10, 
10, 10, 10, 3, 3, 3, 3, 3, 3), listener = c(111, 111, 222, 111, 
222, 444, 333, 222, 444, 222), speaker = c(222, 333, 111, 444, 
444, 333, 222, 333, 222, 444)), class = "data.frame", row.names = c(NA, 
-10L), codepage = 65001L)
 

Конечный результат будет выглядеть так:

 ╔═══════╦════════╦══════════╦═════════╦════════════════════╦═══════════════════════════════════════════════════════════════╗
║ topic ║ thread ║ listener ║ speaker ║ writer_involvement ║ explanation                                                   ║
╠═══════╬════════╬══════════╬═════════╬════════════════════╬═══════════════════════════════════════════════════════════════╣
║   1101112220         ║ The first observed listener (111) is the writer of the thread ║
╠═══════╬════════╬══════════╬═════════╬════════════════════╬═══════════════════════════════════════════════════════════════╣
║   1101113330         ║                                                               ║
╠═══════╬════════╬══════════╬═════════╬════════════════════╬═══════════════════════════════════════════════════════════════╣
║   1102221111         ║ The writer of this thread, 111, spoke here                    ║
╠═══════╬════════╬══════════╬═════════╬════════════════════╬═══════════════════════════════════════════════════════════════╣
║   1101114440         ║                                                               ║
╠═══════╬════════╬══════════╬═════════╬════════════════════╬═══════════════════════════════════════════════════════════════╣
║   232224440         ║ The first observed listener (222) is the writer               ║
╠═══════╬════════╬══════════╬═════════╬════════════════════╬═══════════════════════════════════════════════════════════════╣
║   234443330         ║                                                               ║
╠═══════╬════════╬══════════╬═════════╬════════════════════╬═══════════════════════════════════════════════════════════════╣
║   233332221         ║ The writer of this thread, 222, spoke here                    ║
╠═══════╬════════╬══════════╬═════════╬════════════════════╬═══════════════════════════════════════════════════════════════╣
║   232223330         ║                                                               ║
╠═══════╬════════╬══════════╬═════════╬════════════════════╬═══════════════════════════════════════════════════════════════╣
║   234442221         ║ The writer of this thread, 222, spoke here                    ║
╠═══════╬════════╬══════════╬═════════╬════════════════════╬═══════════════════════════════════════════════════════════════╣
║   232224440         ║                                                               ║
╚═══════╩════════╩══════════╩═════════╩════════════════════╩═══════════════════════════════════════════════════════════════╝
 

Ответ №1:

Мы можем использовать match с nomatch= 0 после группировки по «теме»

 library(dplyr)
df %>%
   group_by(topic) %>% 
   mutate(write_involvement =  match(speaker, first(listener), nomatch = 0)) %>%
   ungroup
 

-вывод

 # A tibble: 10 x 5
#   topic thread listener speaker write_involvement
#   <dbl>  <dbl>    <dbl>   <dbl>             <int>
# 1     1     10      111     222                 0
# 2     1     10      111     333                 0
# 3     1     10      222     111                 1
# 4     1     10      111     444                 0
# 5     2      3      222     444                 0
# 6     2      3      444     333                 0
# 7     2      3      333     222                 1
# 8     2      3      222     333                 0
# 9     2      3      444     222                 1
#10     2      3      222     444                 0
 

Или создайте логический вывод и принудительно преобразуйте в двоичный

 df %>%
   group_by(topic) %>% 
   mutate(write_involvement =   (speaker == first(listener)))
 

Ответ №2:

Базовый параметр R, использующий ave

 within(
  df,
  writer_involvement <-  (ave(listener, topic, thread, FUN = function(x) head(x, 1)) == speaker)
)
 

дает

    topic thread listener speaker writer_involvement
1      1     10      111     222                  0
2      1     10      111     333                  0
3      1     10      222     111                  1
4      1     10      111     444                  0
5      2      3      222     444                  0
6      2      3      444     333                  0
7      2      3      333     222                  1
8      2      3      222     333                  0
9      2      3      444     222                  1
10     2      3      222     444                  0
 

Опция data.table

 setDT(df)[, writer_involvement :=  (speaker == head(listener, 1)), .(topic, thread)]
 

дает

 > df
    topic thread listener speaker writer_involvement
 1:     1     10      111     222                  0
 2:     1     10      111     333                  0
 3:     1     10      222     111                  1
 4:     1     10      111     444                  0
 5:     2      3      222     444                  0
 6:     2      3      444     333                  0
 7:     2      3      333     222                  1
 8:     2      3      222     333                  0
 9:     2      3      444     222                  1
10:     2      3      222     444                  0