【问题标题】:Count number of new and lost friends between two data frames in R计算R中两个数据帧之间的新朋友和丢失朋友的数量
【发布时间】:2020-02-27 21:07:50
【问题描述】:

我有两个相同受访者的数据框,一个来自时间 1,下一个来自时间 2。在每一波中,他们都提名了他们的朋友,我想知道:

1) 有多少朋友在时间 2 被提名但在时间 1 没有被提名(新朋友)

2) 有多少朋友在时间 1 被提名但在时间 2 没有被提名(失去的朋友)

样本数据:

Time 1 DF

ID  friend_1  friend_2  friend_3  
1          4        12         7       
2          8         6         7   
3          9        NA        NA     
4         15         7         2    
5          2        20         7   
6         19        13         9       
7         12        20         8    
8          3        17        10 
9          1        15        19     
10         2        16        11  


Time 2 DF

ID  friend_1  friend_2  friend_3  
1          4        12         3    
2          8         6        14       
3          9        NA        NA      
4         15         7         2      
5          1        17         9
6          9        19        NA
7         NA        NA        NA     
8          7         1        16  
9         NA        10        12   
10         7        11         9   

因此所需的 DF 将包括这些列(编辑填充列):

ID  num_newfriends  num_lostfriends  
1               1                 1      
2               1                 1   
3               0                 0      
4               0                 0        
5               3                 3          
6               0                 1  
7               0                 3   
8               3                 3
9               2                 3
10              2                 1  

EDIT2:

我试过做反连接

df3 <- anti_join(df1, df2)

但是这种方法没有考虑到可能出现在时间 2 不同列中的朋友 ID 号(例如受访者#6 朋友 9 和 19 在 T1 和 T2 中,但在每次不同的列中)

【问题讨论】:

  • 你能举一个输出的例子吗,例如对于 ID 1?
  • 到目前为止你尝试过什么?

标签: r dplyr tidyverse data-manipulation network-analysis


【解决方案1】:

简单的比较是一种选择

library(tidyverse)
na_sums_old <- rowSums(is.na(time1))
na_sums_new <- rowSums(is.na(time2))
kept_friends <- map_dbl(seq(nrow(time1)), ~ sum(time1[.x, -1] %in% time2[.x, -1]))
kept_friends <- kept_friends - na_sums_old * (na_sums_new >= 1)

new_friends  <- 3 - na_sums_new - kept_friends
lost_friends <- 3 - na_sums_old - kept_friends

tibble(ID = time1$ID, new_friends = new_friends, lost_friends = lost_friends)


# A tibble: 10 x 3
      ID new_friends lost_friends
   <int>       <dbl>        <dbl>
 1     1           1            1
 2     2           1            1
 3     3           0            0
 4     4           0            0
 5     5           3            3
 6     6           0            1
 7     7           0            3
 8     8           3            3
 9     9           2            3
10    10           2            2

【讨论】:

  • 这似乎有效,但在完整的数据集中,一些值最终是负数,知道为什么吗?完整的数据集最多有 7 个朋友,所以我将 3 - 替换为 7 -
【解决方案2】:

您可以通过首先旋转到“长”数据框来使anti_join 工作。

df1 <- df1 %>%
  pivot_longer(starts_with("friend_"), values_to = "friend") %>%
  drop_na()
df2 <- df2 %>%
  pivot_longer(starts_with("friend_"), values_to = "friend") %>%
  drop_na()

head(df1)
#> # A tibble: 6 x 3
#>      ID name     friend
#>   <int> <chr>     <int>
#> 1     1 friend_1      4
#> 2     1 friend_2     12
#> 3     1 friend_3      7
#> 4     2 friend_1      8
#> 5     2 friend_2      6
#> 6     2 friend_3      7

lost_friends <- anti_join(df1, df2, by = c("ID", "friend"))
new_fiends <- anti_join(df2, df1, by = c("ID", "friend"))

respondents <- distinct(df1, ID)

respondents %>%
  full_join(
    count(lost_friends, ID, name = "num_lost_friends")
  ) %>%
  full_join(
    count(new_fiends, ID, name = "num_new_friends")
  ) %>%
  mutate_at(vars(starts_with("num_")), replace_na, 0)
#> Joining, by = "ID"
#> Joining, by = "ID"
#> # A tibble: 10 x 3
#>       ID num_lost_friends num_new_friends
#>    <int>            <dbl>           <dbl>
#>  1     1                1               1
#>  2     2                1               1
#>  3     3                0               0
#>  4     4                0               0
#>  5     5                3               3
#>  6     6                1               0
#>  7     7                3               0
#>  8     8                3               3
#>  9     9                3               2
#> 10    10                2               2

reprex package (v0.3.0) 于 2019 年 11 月 1 日创建

【讨论】:

    【解决方案3】:

    另一种选择:

    library(tidyverse)
    
    left_join(
      gather(df1, key, x, -ID),
      gather(df2, key, y, -ID),
      by = c("ID", "key")
    ) %>%
      group_by(ID) %>%
      summarise(
        num_newfriends = sum(!y[!is.na(y)] %in% x[!is.na(x)]),
        num_lostfriends = sum(!x[!is.na(x)] %in% y[!is.na(y)])
      )
    

    输出:

    # A tibble: 10 x 3
          ID num_newfriends num_lostfriends
       <int>          <int>           <int>
     1     1              1               1
     2     2              1               1
     3     3              0               0
     4     4              0               0
     5     5              3               3
     6     6              0               1
     7     7              0               3
     8     8              3               3
     9     9              2               3
    10    10              2               2
    

    【讨论】:

    • 我运行了这个,但输出只有一行,并没有为每个受访者提供结果。
    • 哼,不知道这可能是什么。你有什么错误吗?
    • 不,没有错误!它只给了我 1 个新朋友和 3 个失落的朋友。
    • 不幸的是,它是受限制的数据,所以我无法分享。我会看看我能不能让它工作。谢谢!
    • 您确定按 ID 列(或实际表中的任何名称)分组吗?如果您在不分组的情况下汇总所有内容,我希望有一行。
    猜你喜欢
    • 1970-01-01
    • 2015-10-21
    • 1970-01-01
    • 1970-01-01
    • 2011-08-10
    • 2013-08-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多