如何从长格式数据框中计算成对计数表

4

我有一个“长格式”数据框,其中包含列id(主键)和featureCode(分类变量)。每个记录具有1到9个分类变量值。例如:

id  featureCode
5   PPLC
5   PCLI
6   PPLC
6   PCLI
7   PPL
7   PPLC
7   PCLI
8   PPLC
9   PPLC
10  PPLC

我希望能够计算每个特征码与其他特征码一起使用的次数(即标题中的“成对计数”)。在此阶段,特征码的使用顺序不重要。我设想结果将是另一个数据框,其中行和列是特征码,而单元格是计数。例如:
      PPLC  PCLI  PPL
PPLC  0     3     1
PCLI  3     0     1
PPL   1     1     0

很不幸,我不知道如何进行这个计算,而且在寻求建议时一无所获(主要原因可能是我不知道正确的术语)。

4个回答

8
这里有一个类似于@mrdwab的data.table方法。
如果featureCodecharacter类型,则效果最佳。
library(data.table)

DT <- data.table(dat)
# convert to character
DT[, featureCode := as.character(featureCode)]
# subset those with >1 per id
DT2 <- DT[, N := .N, by = id][N>1]
# create all combinations of 2
# return as a data.table with these as columns `V1` and `V2`
# then count the numbers in each group
DT2[, rbindlist(combn(featureCode,2, 
      FUN = function(x) as.data.table(as.list(x)), simplify = F)), 
    by = id][, .N, by = list(V1,V2)]


     V1   V2 N
1: PPLC PCLI 3
2:  PPL PPLC 1
3:  PPL PCLI 1

我也尝试了类似的方法,但是卡在你创建DT2的地方了。 - A5C1D2H2I1M1N2O1R2T1
我花了一些时间才意识到simplify = FALSE是一个选项,然后找出如何返回正确维度的data.table时间数据。 - mnel
1
如果我也想将数据中 PPLC 到 PPLC 的计数包含在内,怎么办? - Rajarshi Bhadra

2
如果您不需要精确的结构,只需要获取配对计数,可以尝试以下方法:
以下是您的数据:
dat <- read.table(header = TRUE, 
       text = "id  featureCode
                5         PPLC
                5         PCLI
                6         PPLC
                6         PCLI
                7          PPL
                7         PPLC
                7         PCLI
                8         PPLC
                9         PPLC
               10         PPLC")

我们只关心那些有多个featureCodeid
dat2 <- dat[ave(dat$id, dat$id, FUN=length) > 1, ]

将这些数据作为列表进行处理将非常有用,因为这样可以使用lapply来获取成对组合。

dat2 <- split(dat2$featureCode, dat2$id)

如果您愿意,可以将下一步拆分为其中间部分,但基本想法是创建每个列表项中向量的组合,然后制表未列出的输出。

table(unlist(lapply(dat2, function(x) 
  combn(sort(x), 2, FUN = function(y) 
    paste(y, collapse = "+")))))
# 
#  PCLI+PPL PCLI+PPLC  PPL+PPLC 
#         1         3         1

更新:另一个问题有更好的答案

进行少量修改后,@flodel的答案适用于另一个问题。它需要安装igraph包(install.packages("igraph"))。

dat2 <- dat[ave(dat$id, dat$id, FUN=length) > 1, ]
dat2 <- split(dat2$featureCode, dat2$id)
library(igraph)
g <- graph.edgelist(matrix(unlist(lapply(dat2, function(x) 
  combn(as.character(x), 2, simplify = FALSE))), ncol = 2, byrow=TRUE), 
                    directed=FALSE)
get.adjacency(g)
# 3 x 3 sparse Matrix of class "dgCMatrix"
#      PPLC PCLI PPL
# PPLC    .    3   1
# PCLI    3    .   1
# PPL     1    1   .

1

另一个解决方案,我认为在概念上很容易理解。您在这里有一个二分图,只需要将该图投影到“featureCode”顶点上即可。以下是使用igraph包执行此操作的方法:

dat <- read.table(header = TRUE, stringsAsFactors=FALSE,
                  text = "id  featureCode                                       
                          5         PPLC                                                  
                          5         PCLI                                                  
                          6         PPLC                                                  
                          6         PCLI                                                  
                          7          PPL                                                  
                          7         PPLC                                                  
                          7         PCLI                                                  
                          8         PPLC                                                  
                          9         PPLC                                                  
                         10         PPLC")

g <- graph.data.frame(dat, vertices=unique(data.frame(c(dat[,1], dat[,2]),
                          type=rep(c(TRUE, FALSE), each=nrow(dat)))))

get.adjacency(bipartite.projection(g)[[1]], attr="weight", sparse=FALSE)

#      PPLC PCLI PPL
# PPLC    0    3   1
# PCLI    3    0   1
# PPL     1    1   0

1

我会使用SQL,在R中可以通过sqldf包使用。

提取所有可能的组合,类似于:

sqldf("select distinct df1.featureCode, df2.featureCode
       from df df1, df df2       
       ")

然后您可以提取结果元素:
(也许只需使用for循环处理所有组合)

PCLI - PPLC

sqldf("select count(df1.id)
       from df df1, df df2
       where df1.id = df2.id
       and df1.featureCode = 'PCLI' and df2.featureCode = 'PPLC'
       ")

PPLC - PPL

sqldf("select count(df1.id)
       from df df1, df df2
       where df1.id = df2.id
       and df1.featureCode = 'PPLC' and df2.featureCode = 'PPL'
       ")

PCLI - PPL

sqldf("select count(df1.id)
       from df df1, df df2
       where df1.id = df2.id
       and df1.featureCode = 'PCLI' and df2.featureCode = 'PPL'
       ")

如果你需要考虑更多的组合,那么肯定有更简单的解决方案。也许搜索“列联表”可以帮助你。


很不幸,数据集中有大约90个特征代码,因此手动创建组合将耗费太多时间。感谢您的建议。 - Iain Dillingham

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接