Эффективный способ указать несколько переменных индикатора в строке?

Учитывая "пустой" индикаторный фрейм данных:

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 ответа

Я бы сделал прямо:

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")

Я бы использовал матрицы:

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 вокруг; Я не вижу смысла.

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 в 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
Другие вопросы по тегам