【问题标题】:An efficient way to indicate multiple indicator variables per row?指示每行多个指标变量的有效方法?
【发布时间】:2015-05-13 15:07:16
【问题描述】:

给定一个“空”指标数据框:

Index    Ind_A    Ind_B
  1        0        0
  2        0        0
  3        0        0
  4        0        0

和一个值的数据框:

Index    Indicators
  1         Ind_A
  3         Ind_A
  3         Ind_B
  4         Ind_A

我想结束:

Index    Ind_A    Ind_B
  1        1        0
  2        0        0
  3        1        1
  4        1        0

有没有办法在没有 for 循环的情况下做到这一点?

【问题讨论】:

标签: r dataframe indicator


【解决方案1】:

我会直接做:

df = transform(df, Index=factor(Index, level=min(Index):max(Index)))
as.data.frame.matrix(table(df))
#  Ind_A Ind_B
#1     1     0
#2     0     0
#3     1     1
#4     1     0

数据:

df = structure(list(Index = c(1, 3, 3, 4), Indicators = c("Ind_A", 
"Ind_A", "Ind_B", "Ind_A")), .Names = c("Index", "Indicators"
), row.names = c(NA, -4L), class = "data.frame")

【讨论】:

    【解决方案2】:

    我会使用矩阵:

    ind_mat <- as.matrix(ind_df[,-1]); rownames(ind_mat) <- ind_df[,1]
    val_mat <- cbind(match(val_df$Index,ind_df[,1]),match(val_df$Indicators,names(ind_df[-1])))
    
    ind_mat[val_mat] <- 1L
    #   Ind_A Ind_B
    # 1     1     0
    # 2     0     0
    # 3     1     1
    # 4     1     0
    

    您可能不需要“索引”作为列,只需将它们设置为rownames。如果 (i) 您的值矩阵相对于索引矩阵较小,并且 (ii) 您的索引列等于 1:nrow(ind_df),则应考虑存储在稀疏矩阵中。


    关于对矩阵的强制转换,它只需要很少的时间,并且可以避免以后必须为任何矩阵运算进行强制转换的麻烦。这是一个例子:

    n    = 1e4
    nind = 1e3
    y    <- rnorm(n)
    x    <- matrix(sample(0:1,size=n*nind,replace=TRUE),ncol=nind)
    xd   <- data.frame(1:nrow(x),x)
    
    # timing: 0.04 seconds on my computer
    system.time(as.matrix(xd[,-1]))
    
    # messiness, e.g., for OLS y~0+x: immense
    solve(t(as.matrix(xd[,-1]))%*%as.matrix(xd[,-1]))%*%(t(as.matrix(xd[,-1]))%*%y)
    

    最后一行让您避免保留matrix;我不明白这一点。

    【讨论】:

    • 我认为答案之间没有太大区别。此外,as.matrix 可能会有开销。这里最大的问题是你没有匹配到第一个数据集中的 Indx 列,它不一定是 1:4。
    • @DavidArenburg 好的,现在它匹配索引列。无论如何,使用矩阵和使用 data.frame 进行矩阵计算之间存在很大差异。避免强制等。
    • 嗯,downvoter:我已经纠正了大卫提到的“不匹配”的事情。
    • 嗯。好的,我会对此表示赞同,但我希望看到一些能够证明您所说的话的基准(其中将包括 as.matrix 开销)。
    • 如果您执行任何矩阵运算,例如t(as.matrix(ind_df[-1]))%*%as.matrix(ind_df[-1]) 或类似的,您将在以后强制转换为矩阵。 R 的 OLS 实现,在构建模型矩阵时大概还必须有效地强制转换为矩阵或 cbind 列。
    【解决方案3】:
    indicator <- data.frame(Index=1:4,Ind_A=rep(0,4),Ind_B=rep(0,4));
    values <- data.frame(Index=c(1,3,3,4),Indicators=c('Ind_A','Ind_A','Ind_B','Ind_A'));
    indicator[cbind(match(values$Index,indicator$Index),match(values$Indicators,names(indicator)))] <- 1;
    indicator;
    ##   Index Ind_A Ind_B
    ## 1     1     1     0
    ## 2     2     0     0
    ## 3     3     1     1
    ## 4     4     1     0
    

    编辑中最显着的变化是indicator$Index 现在包含唯一值(至少不是单独的),所以一个简单的match()values$Index 到@987654325 @ 不足。相反,我们实际上必须在IndexIndex2 上运行outer() 相等性测试,以获得一个逻辑矩阵,该矩阵表示indicator 中的哪些行每个values 行在两个键上都匹配。假设两列复合键是唯一的,那么我们可以根据which()返回的线性(向量)索引计算indicator中的行索引。

    indicator[cbind((which(outer(values$Index,indicator$Index,`==`)&outer(values$Index2,indicator$Index2,`==`))-1)%/%nrow(values)+1,match(values$Indicators,names(indicator)))] <- 1;
    indicator;
    ##   Index Index2 Ind_A Ind_B
    ## 1     1     10     1     1
    ## 2     1     11     1     0
    ## 3     2     10     0     1
    ## 4     2     12     1     0
    ## 5     3     10     1     0
    ## 6     3     12     1     0
    ## 7     4     10     1     1
    ## 8     4     12     1     0
    

    这是另一个使用merge()的解决方案:

    indicator[cbind(merge(values,cbind(indicator,row=1:nrow(indicator)))$row,match(values$Indicators,names(indicator)))] <- 1;
    indicator;
    ##   Index Index2 Ind_A Ind_B
    ## 1     1     10     1     1
    ## 2     1     11     1     0
    ## 3     2     10     0     1
    ## 4     2     12     1     0
    ## 5     3     10     1     0
    ## 6     3     12     1     0
    ## 7     4     10     1     1
    ## 8     4     12     1     0
    

    性能

    第一个解决方案性能更高:

    first <- function() indicator[cbind((which(outer(values$Index,indicator$Index,`==`)&outer(values$Index2,indicator$Index2,`==`))-1)%/%nrow(values)+1,match(values$Indicators,names(indicator)))] <<- 1;
    second <- function() indicator[cbind(merge(values,cbind(indicator,row=1:nrow(indicator)))$row,match(values$Indicators,names(indicator)))] <<- 1;
    N <- 10000;
    system.time({ replicate(N,first()); });
    ##    user  system elapsed
    ##   2.032   0.000   2.041
    system.time({ replicate(N,first()); });
    ##    user  system elapsed
    ##   2.047   0.000   2.038
    system.time({ replicate(N,second()); });
    ##    user  system elapsed
    ##  12.578   0.000  12.592
    system.time({ replicate(N,second()); });
    ##    user  system elapsed
    ##   12.64    0.00   12.66
    

    【讨论】:

    • 你能看看我的编辑并回答那个吗?我尝试在多个条件下使用 which 但没有帮助....
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-07-08
    • 2015-07-10
    • 2017-08-09
    • 1970-01-01
    • 1970-01-01
    • 2010-09-24
    • 1970-01-01
    相关资源
    最近更新 更多