将数据帧与data.table匹配

时间:2015-10-23 17:51:09

标签: r database match data.table

我需要使用另一个矩阵作为标识符(ID.MA)用长数据帧(DF)填充矩阵(MA)。

我的三个矩阵的想法: MA.ID创建一个标识符,在大DF中查找所需的变量:

     a      b      c
a    ID.aa  ID.ab  ID.ac
b    ID.ba  ID.bb  ID.bc
c    ID.ca  ID.cb  ID.cc

原始的大数据框有无用的信息,但也有一些对我填充目标MA矩阵有用的行:

ID     1990 1991 1992
ID.aa  10   11   12
ID.ab  13   14   15
ID.ac  16   17   18
ID.ba  19   20   21
ID.bb  22   23   24
ID.bc  25   26   27
ID.ca  28   29   30
ID.cb  31   32   33
ID.cc  34   35   36
ID.xx  40   40   55
ID.xy  50   51   45
....
MA应该填充交叉信息。在我的例子中,它应该看起来像DF的一个选定的列(假设,1990):

     a    b    c
a    10   13   16
b    19   22   25
c    28   31   34

我尝试过使用匹配但老实说它没有用完:

MA$a = DF[match(MA.ID$a, DF$ID),2]

我被建议使用data.table包,但我看不出这对我有什么帮助。

任何人都有办法解决这个问题吗?

2 个答案:

答案 0 :(得分:2)

假设您的输入是 dataframes ,那么您可以执行以下操作:

library(data.table)
setDT(ma)[, lapply(.SD, function(x) x = unlist(df[match(x,df$ID), "1990"]))
          , .SDcols = colnames(ma)]

返回:

    a  b  c
1: 10 13 16
2: 19 22 25
3: 28 31 34

解释

  • 使用setDT(ma)数据框转换为数据表(这是一个增强的数据框)。
  • 使用.SDcols=colnames(ma)指定必须应用转换的列。
  • lapply(.SD, function(x) x = unlist(df[match(x,df$ID),"1990"]))对使用.SDcols指定的每个列执行匹配操作。

使用data.table的替代方法是首先将ma转换为长 data.table

ma2 <- melt(setDT(ma), measure.vars = c("a","b","c"))
setkey(ma2, value)    # set key by which 'ma' has to be indexed
setDT(df, key="ID")   # transform to a datatable & set key by which 'df' has to be indexed

# joining the values of the 1990 column of df into
# the right place in the value column of 'ma'
ma2[df, value :=  `1990`]

给出:

> ma2
   variable value
1:        a    10
2:        b    13
3:        c    16
4:        a    19
5:        b    22
6:        c    25
7:        a    28
8:        b    31
9:        c    34

此方法的唯一缺点是“值”列中的数值存储为字符值。您可以通过如下扩展来更正此问题:

ma2[df, value :=  `1990`][, value := as.numeric(value)]

如果您想将其更改回宽屏格式,可以使用rowid中的dcast功能:

ma3 <- dcast(ma2, rowid(variable) ~ variable, value.var = "value")[, variable := NULL]

给出:

> ma3
    a  b  c
1: 10 13 16
2: 19 22 25
3: 28 31 34

使用过的数据:

ma <- structure(list(a = structure(1:3, .Label = c("ID.aa", "ID.ba", "ID.ca"), class = "factor"), 
                     b = structure(1:3, .Label = c("ID.ab", "ID.bb", "ID.cb"), class = "factor"), 
                     c = structure(1:3, .Label = c("ID.ac", "ID.bc", "ID.cc"), class = "factor")), 
                .Names = c("a", "b", "c"), class = "data.frame", row.names = c(NA, -3L))

df <- structure(list(ID = structure(1:9, .Label = c("ID.aa", "ID.ab", "ID.ac", "ID.ba", "ID.bb", "ID.bc", "ID.ca", "ID.cb", "ID.cc"), class = "factor"), 
                     `1990` = c(10L, 13L, 16L, 19L, 22L, 25L, 28L, 31L, 34L), 
                     `1991` = c(11L, 14L, 17L, 20L, 23L, 26L, 29L, 32L, 35L), 
                     `1992` = c(12L, 15L, 18L, 21L, 24L, 27L, 30L, 33L, 36L)), 
                .Names = c("ID", "1990", "1991", "1992"), class = "data.frame", row.names = c(NA, -9L))

答案 1 :(得分:2)

在基础R中,它可以被视为outer的作业:

> outer(1:nrow(MA.ID), 1:ncol(MA.ID), Vectorize(function(x,y) {DF[which(DF$ID==MA.ID[x,y]),'1990']}))
     [,1] [,2] [,3]
[1,]   10   13   16
[2,]   19   22   25
[3,]   28   31   34

说明:

  • outer创建一个矩阵作为第一个参数X(此处为a b c)和第二个参数Y的外部产品(此处为a b c })
  • 对于XY的每个组合,它会应用一个函数来查找DFID所在行MA.ID[X,Y]中的值},并在列1990
  • 这里的重要技巧是使用Vectorize包装函数,因为outer需要向量化函数
  • 结果最终以矩阵形式返回

或者,另一种方法(仍在基础R中)是:

  1. 将您的数据框MA.ID转换为向量
  2. sapply一个快速查找与DF$ID
  3. 对应的函数
  4. 并转换回矩阵。
  5. 这有效:

    > structure(
         sapply(unlist(MA.ID), 
                function(id){DF[which(DF$ID==id),'1990']}),
         dim=dim(MA.ID), names=NULL)
    
         [,1] [,2] [,3]
    [1,]   10   13   16
    [2,]   19   22   25
    [3,]   28   31   34
    

    (这里对structure(..., dim=dim(MA.ID), names=NULL)的调用将向量转换回矩阵)