首页 文章

如何将函数应用于R中的每组面板数据(带data.table?)?

提问于
浏览
1

我有R的基本知识,我尝试自动化数据框上的一些计算 . 我创建了一个函数和一些代码,并想要一些帮助,使所有内容与R哲学保持一致 .

我有一个面板数据集df,您可以这样构建:

# sample data frame
id <- c("i","i","i","j","j","j","k","k")
time <- c(1,2,3,1,2,3,1,2)
b1 <- c(1,0,1,0,0,1,1,0)
b2 <- c(0,0,1,0,0,0,1,1)
b3 <- c(0,1,0,1,0,0,0,0)
b4 <- c(0,0,0,0,1,0,1,1)
df <- data.frame(id,time,b1,b2,b3,b4)

我使用data.table转换它:

# data.table
### set-up
dt <- data.table(df)
setkey(dt,id,time)

### lead
nm1 <- grep("^b", colnames(dt), value=TRUE)
nm2 <- paste("lead", nm1, sep=".")
dt[, (nm2) := shift(.SD, type='lead'), by = id, .SDcols=nm1]

现在,我想为每个组id计算一个矩阵,将所有过渡从一行添加到下一行 . 每个矩阵都存储在一个列表中 . 我创建了一个我应用于每个组的函数:

# empty list
m.out <- list()

# group i
m <- matrix(0,cat,cat + 1)
dt1 <- dt["i",c(nm1,nm2),with=FALSE]
m.out[[1]] <- calcMatrix(dt1)

# group j
m <- matrix(0,cat,cat + 1)
dt1 <- dt["j",c(nm1,nm2),with=FALSE]
m.out[[2]] <- calcMatrix(dt1)

# group k
m <- matrix(0,cat,cat + 1)
dt1 <- dt["k",c(nm1,nm2),with=FALSE]
m.out[[3]] <- calcMatrix(dt1)

How can I apply the function and create the list of matrix to all the groups of the data.table (especially if I try the code on a big dataset)?

I thought of this solution BUT IT DOES NOT WORK. The function itself does not create a matrix for each .SD and the list is not appended correctly:

m.out <- list()
m.out <- dt[,calcMatrix(.SD),by = id, .SDcols = c(nm1,nm2)]

函数calcMatrix定义如下:

calcMatrix <- function(x) {

  # number of "b" categories
  cat <- length(nm1)
  # vector of column indices
  col.index <- grep("^b",colnames(x))
  # number of rows in the data.table x
  row.num <- nrow(x)

  # fill in matrix
  m <- matrix(0,cat,cat + 1)
  for(i in col.index) {
    for(j in 1:(row.num - 1)) {
      m[i,] = m[i,] + as.integer(x[j,i,with=FALSE]) * c(0,as.matrix(x[j, .SD, .SDcols = nm2]))
    }
   m[i,1] = m[i,1] + as.integer(x[row.num,i,with=FALSE])
  }
  return(m)
}

This function may not be optimized for R due to the two loops. IS THERE A WAY TO GET RID OF THE LOOPS?

编辑:我可以解释一下我在 calcMatrix 做了什么 .

  • 对于每个组ID,我想获得一个矩阵,其中bi变量的数量为行,bi变量的数量为1 . 我将计算每个组ID的转换次数 .

  • 然后我拿下每个bi并检查下一次到达哪个bj(基本上是从bi到bj的过渡) .

  • 然后我在单元格m [i,j 1]的矩阵中做1(第一列用于最后一行) .

  • 当我们在最后一行(最后一次)时,没有转换,所以如果当时bi = 1,我在第一列中做1(自身转换) .

这样,我计算从bi到bj和所有最后状态的所有转换 . 这就是我使用 shift 函数计算线索的原因 . 我可以直接将前导行添加到矩阵中 . 我想知道这是否可以在没有循环但是通过矢量化的情况下以不同的方式编写,因为它是R中的哲学 .

1 回答

  • 2

    实际上有两个问题 . 只有一个可以回答 . 关于优化功能的第二个需要额外的信息 .

    如何应用函数并为data.table的所有组创建矩阵列表?

    您可以尝试 lapply() 来创建结果列表:

    lapply(dt[, unique(id)], function(.id) {calcMatrix(dt[id == .id, c(nm1,nm2), with=FALSE])})
    

    返回:

    [[1]]
         [,1] [,2] [,3] [,4] [,5]
    [1,]    1    0    0    1    0
    [2,]    1    0    0    0    0
    [3,]    0    1    1    0    0
    [4,]    0    0    0    0    0
    
    [[2]]
         [,1] [,2] [,3] [,4] [,5]
    [1,]    1    0    0    0    0
    [2,]    0    0    0    0    0
    [3,]    0    0    0    0    1
    [4,]    0    1    0    0    0
    
    [[3]]
         [,1] [,2] [,3] [,4] [,5]
    [1,]    0    0    1    0    1
    [2,]    1    0    1    0    1
    [3,]    0    0    0    0    0
    [4,]    1    0    1    0    1
    

相关问题