计算二进制变量之间的重叠

问题描述

我正在尝试计算有多少人从事不同的运动组合。我知道如何计算和绘制相关性,但是我想获得每个合并组中有多少人的实际人数。

这是我的数据的简化演示。 1表示给定的人从事这项运动,而0表示不参加该运动。

    sports_example <- tibble(
      name = c(
        "Scarlett","Heather","Sarah","Anna","emma","Charlotte","Cheryl"
      ),hockey = c(1L,1L,0L,1L),basketball = c(0L,0L),track = c(1L,football = c(0L,0L)
    )

使用下面的代码,我可以计算不同运动之间的相关性。我可以说,曲棍球在篮球方面的参与人数多于足球。但是我想计算有多少运动员打曲棍球和篮球(本例中为3)。有简单的算法来计算重叠吗?我的真实数据集包含数十列,因此我的一次性代码无法删除(例如nrow(filter(sports_example,hockey + basketball == 2)))。

sports_example %>% 
  select(-name) %>% 
  cor() %>% 
  corrgram::corrgram(upper.panel = NULL)

Correlation plot of Andrew's demo data

解决方法

我建议您使用下一种方法来确定所有玩家的情况:

library(reshape2)
library(tibble)
library(dplyr)

#Data
sports_example <- tibble(
  name = c(
    "Scarlett","Heather","Sarah","Anna","Emma","Charlotte","Cheryl"
  ),hockey = c(1L,1L,0L,1L),basketball = c(0L,0L),track = c(1L,football = c(0L,0L)
)

#Reshape
Melted <- melt(sports_example,id.vars = 'name')

重塑后,您可以使用dplyr函数进行分组和聚合:

#Now filter and compute
Melted %>% group_by(name) %>% filter(variable %in% c('hockey','basketball')) %>% 
  summarise(N=sum(value))

它将导致:

# A tibble: 7 x 2
  name          N
  <chr>     <int>
1 Anna          1
2 Charlotte     2
3 Cheryl        1
4 Emma          1
5 Heather       2
6 Sarah         2
7 Scarlett      1

然后,您可以添加新的过滤器以达到所需的条件:

#Now filter and compute 2
Melted %>% group_by(name) %>% filter(variable %in% c('hockey','basketball')) %>% 
  summarise(N=sum(value)) %>% filter(N==2)

输出:

# A tibble: 3 x 2
  name          N
  <chr>     <int>
1 Charlotte     2
2 Heather       2
3 Sarah         2

然后,您还可以识别玩家和想要的号码。

,

如果您追求成对结果,则可以堆叠数据并使用crossprod()

spex <- subset(cbind(sports_example[1],stack(sports_example[-1])),values == 1)
res <- crossprod(table(spex$name,spex$ind))
res[upper.tri(res,diag = TRUE)] <- 0

subset(as.data.frame.table(res),Freq > 0)

         Var1       Var2 Freq
2  basketball     hockey    3
3       track     hockey    4
4    football     hockey    1
7       track basketball    3
8    football basketball    1
12   football      track    1
,

count()怎么样?

count(sports_example,hockey,basketball)
##   hockey basketball     n
##    <int>      <int> <int>
## 1      0          1     1
## 2      1          0     3
## 3      1          1     3

(count(sports_example,basketball) 
   %>% filter(hockey==1,basketball==1)
   %>% pull(n)
)

base-R版本类似于

with(sports_example,as.data.frame(table(hockey,basketball)))
,

以长格式获取数据,仅保留value = 1行,为每个namecount创建配对组合。

library(dplyr)

sports_example %>%
  tidyr::pivot_longer(cols = -name,names_to = 'col') %>%
  filter(value == 1) %>%
  group_by(name) %>%
  summarise(val = if(n() > 1) combn(col,2,function(x) 
                     sort(toString(x))) else col) %>%
  ungroup %>%
  count(val)

#  val                      n
#  <chr>                <int>
#1 basketball,football     1
#2 basketball,track        3
#3 hockey                   1
#4 hockey,basketball       3
#5 hockey,football         1
#6 hockey,track            4
#7 track,football          1

此答案适用于dplyr> 1.0.0,它允许返回summarise中的多行。

,

您可以矢量化:

(sports_example$hockey & sports_example$basketball) %>% sum