Как создать таблицу, подобную контрастам в r
Мне нужна помощь в преобразовании фрейма данных с определенными значениями в столбцы, которые выглядят как контрасты в R. Например.
code <- data.frame(code = c('R1111', 'R1112', 'R1111', 'R1111', 'R1113',
'R1112', 'R1112', 'R1112', 'R1113', 'R1115'))
Мне нужно преобразовать это в следующую таблицу
code R1111 R1112 R1113 R1115
1 R1111 1 0 0 0
2 R1112 0 1 0 0
3 R1111 2 0 0 0
4 R1111 3 0 0 0
5 R1113 0 0 1 0
6 R1112 0 2 0 0
7 R1112 0 3 0 0
8 R1112 0 4 0 0
9 R1113 0 0 2 0
10 R1115 0 0 0 1
У меня есть 1400 строк с такими кодами, которые мне нужно преобразовать. Если вы заметили, каждый столбец с кодом имеет увеличивающееся число. Я пытался сделать это с помощью reshape2
, но я продолжаю получать ошибки - это означает, что я не был в состоянии понять это. Как я могу получить такой результат?5 ответов:
Можно использовать
mapply
в сочетании сifelse
, чтобы получить желаемый результат в виде:cbind(code,mapply(function(x){ ifelse(code$code==x,cumsum(code$code==x),0) }, unique(as.character(code$code)))) # code R1111 R1112 R1113 R1115 # 1 R1111 1 0 0 0 # 2 R1112 0 1 0 0 # 3 R1111 2 0 0 0 # 4 R1111 3 0 0 0 # 5 R1113 0 0 1 0 # 6 R1112 0 2 0 0 # 7 R1112 0 3 0 0 # 8 R1112 0 4 0 0 # 9 R1113 0 0 2 0 # 10 R1115 0 0 0 1
Вы можете использовать
model.matrix
для создания фиктивной матрицы. Затем просто умножьте его на количество значений.# calculate indicator using base or data.table, more succinctly # code$tag = with(code, as.numeric(ave(as.character(code), code, # FUN=function(x) cumsum(duplicated(x))+1L))) code$tag = data.table::rowid(code$code) model.matrix(~ 0 + code, data=code)* code$tag # codeR1111 codeR1112 codeR1113 codeR1115 # 1 1 0 0 0 # 2 0 1 0 0 # 3 2 0 0 0 # 4 3 0 0 0 # 5 0 0 1 0 # 6 0 2 0 0 # 7 0 3 0 0 # 8 0 4 0 0 # 9 0 0 2 0 # 10 0 0 0 1
Подход Base R (он будет выдавать некоторые предупреждения, вы можете игнорировать их):
x <- code$code y <- rep(0, length(x)) DF <- data.frame(x, y, y, y, y) DF[,2][DF[,1]==unique(x)[1]] <- 1:length(x) DF[,3][DF[,1]==unique(x)[2]] <- 1:length(x) DF[,4][DF[,1]==unique(x)[3]] <- 1:length(x) DF[,5][DF[,1]==unique(x)[4]] <- 1:length(x)
Или оберните его в петлю, если у вас есть много столбцов для обработки:
DF <- data.frame(x, y, y, y, y) for(i in 1:4){ DF[,i+1][DF[,1]==unique(x)[i]] <- 1:length(x) }
A
sapply
способен сделать это: я сохраняюcode
в виде вектора и выполняю некоторую постобработку, чтобы сгенерировать фактическийdata.frame
.code <- c("R1111", "R1112", "R1111", "R1111", "R1113", "R1112", "R1112", "R1112", "R1113", "R1115") val <- sapply(sort(unique(code)), function(thiscode) (code==thiscode)*cumsum(code==thiscode) )
Выход-матрица
R1111 R1112 R1113 R1115 [1,] 1 0 0 0 [2,] 0 1 0 0 [3,] 2 0 0 0 [4,] 3 0 0 0 [5,] 0 0 1 0 [6,] 0 2 0 0 [7,] 0 3 0 0 [8,] 0 4 0 0 [9,] 0 0 2 0 [10,] 0 0 0 1
И форматирование его таким образом дает желаемый результат.
val <- data.frame(code=code, val)
Довольно простое базовое решение:
m <- sapply(unique(code$code),'==',code$code) m2 <- apply(m,2,cumsum) m2[!m] <- 0 cbind(code,`colnames<-`(m2,unique(code$code))) # code R1111 R1112 R1113 R1115 # 1 R1111 1 0 0 0 # 2 R1112 0 1 0 0 # 3 R1111 2 0 0 0 # 4 R1111 3 0 0 0 # 5 R1113 0 0 1 0 # 6 R1112 0 2 0 0 # 7 R1112 0 3 0 0 # 8 R1112 0 4 0 0 # 9 R1113 0 0 2 0 # 10 R1115 0 0 0 1