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

时间:2012-11-01 11:05:00

标签: r dataframe

我有一个'长格式'数据框,其中包含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 个答案:

答案 0 :(得分:6)

这是一种类似于@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

答案 1 :(得分: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")

我们只对有idfeatureCode的{​​{1}}感兴趣:

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对another question的回答适用于此处。它需要安装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   .

答案 2 :(得分: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'
       ")

肯定有一些更简单的解决方案,特别是如果你有更多的组合需要考虑。也许搜索列联表可以帮助你。

答案 3 :(得分: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