Как создать таблицу, подобную контрастам в 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 3

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