Эффективный способ указать несколько переменных индикатора в строке?
Учитывая "пустой" индикаторный фрейм данных:
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