一种指示每行多个指标变量的有效方法?

时间:2015-05-13 15:07:17

标签: r dataframe indicator

给出“空”指标数据框:

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循环,有没有办法做到这一点?

3 个答案:

答案 0 :(得分:1)

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 1}}到indicator$Index是不够的。相反,我们实际上必须在outer()Index上运行Index2相等性测试,以获得表示indicator每个values行中哪些行匹配的逻辑矩阵在两个键上。假设双列复合键是唯一的,我们可以根据indicator返回的线性(向量)索引计算which()中的行索引。

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

答案 1 :(得分:1)

我使用矩阵:

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

你可能不需要&#34;索引&#34;作为列,可以将它们放在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左右;我不明白这一点。

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