簡體   English   中英

從多個因子列生成虛擬矩陣

[英]Generate a dummy matrix from multiple factor columns

我已經在網上搜索,沒有找到答案。 我有一個包含多個列的大data.frame。 每列都是一個因子變量。

我想對data.frame進行轉換,以使因子變量的每個可能值都是一個變量,如果該變量存在於因子列中,則該變量包含“ 1”,否則為“ 0”。

這是我的意思的一個例子。

labels <- c("1", "2", "3", "4", "5", "6", "7") 

#create data frame (note, not all factor levels have to be in the columns,
#NA values are possible)
input <- data.frame(ID = c(1, 2, 3), 
Cat1 = factor(c( 4, 1, 1), levels = labels), 
Cat2 = factor(c(2, NA, 4), levels = labels),
Cat3 = factor(c(7, NA, NA), levels = labels))

#the seven factor levels now are the variables of the data.frame
desired_output <- data.frame(ID = c(1, 2, 3),
Dummy1 = c(0, 1, 1),
Dummy2 = c(1, 0, 0),
Dummy3 = c(0, 0, 0),
Dummy4 = c(1, 0, 1),
Dummy5 = c(0, 0, 0),
Dummy6 = c(0, 0, 0),
Dummy7 = c(1, 0, 0))

input
ID Cat1 Cat2 Cat3
1    4    2    7
2    1 <NA> <NA>
3    1    4 <NA>

desired_output
ID Dummy1 Dummy2 Dummy3 Dummy4 Dummy5 Dummy6 Dummy7
1      0      1      0      1      0      0      1
2      1      0      0      0      0      0      0
3      1      0      0      1      0      0      0

我的實際data.frame具有3000多個行和100多個級別的因子。 希望您能幫助我將輸入轉換為所需的輸出。

問候

一種方法是使用矩陣索引。 您有數據指定輸出矩陣中的哪個位置應為1(其余位置應為零),因此我們將制作一個零矩陣,然后根據您的數據填寫1。 為此,您的數據需要在兩列矩陣中,第一列是輸出的行(ID),第二列是列。

將輸入數據以長格式放置,刪除缺失,將值轉換為與標簽匹配的整數,然后根據需要創建矩陣。

in2 <- reshape2::melt(input, id.vars="ID")
in2 <- subset(in2, !is.na(value))
in2$value <- match(in2$value, labels)
in2$variable <- NULL
in2 <- as.matrix(in2)

然后使新的輸出矩陣全為零,並使用該矩陣填充那些零。

out <- matrix(0, nrow=nrow(input), ncol=length(labels))
colnames(out) <- labels
rownames(out) <- input$ID
out[in2] <- 1

out
##   1 2 3 4 5 6 7
## 1 0 1 0 1 0 0 1
## 2 1 0 0 0 0 0 0
## 3 1 0 0 1 0 0 0

有兩種方法可以解決Gregor和Aaron的答案。

從亞倫的。 factorsAsStrings=FALSE保留因子變量,因此使用dcast時所有dcast

library(reshape2)
dcast(melt(input, id="ID", factorsAsStrings=FALSE), ID ~ value, drop=FALSE) 
  ID 1 2 3 4 5 6 7 NA
1  1 0 1 0 1 0 0 1  0
2  2 1 0 0 0 0 0 0  2
3  3 1 0 0 1 0 0 0  1

然后,您只需要刪除最后一列。

從格里戈爾的

na.replace <- function(x) replace(x, is.na(x), 0)
options(na.action='na.pass') # this keeps the NA's which are then converted to zero
Reduce("+", lapply(input[-1], function(x) na.replace(model.matrix(~ 0 + x))))
  x1 x2 x3 x4 x5 x6 x7
1  0  1  0  1  0  0  1
2  1  0  0  0  0  0  0
3  1  0  0  1  0  0  0

然后,您只需要cbind ID

這是使用model.matrix的方法。 我們將缺失值轉換為0,並指定0作為因子對比的參考水平。 然后,我們只需將各個模型矩陣加在一起並粘貼ID:

new_lab = as.character(0:7)
for (i in 2:4) {
  temp = as.character(input[[i]])
  temp[is.na(temp)] = "0"
  input[[i]] = factor(temp, levels = new_lab)
}

mm = 
  model.matrix(~ Cat1, data = input) +
  model.matrix(~ Cat2, data = input) +
  model.matrix(~ Cat3, data = input)

mm[, 1] = input$ID
colnames(mm) = c("ID", paste0("Dummy", 1:(ncol(mm) - 1)))
mm
#   ID Dummy1 Dummy2 Dummy3 Dummy4 Dummy5 Dummy6 Dummy7
# 1  1      0      1      0      1      0      0      1
# 2  2      1      0      0      0      0      0      0
# 3  3      1      0      0      1      0      0      0
# attr(,"assign")
# [1] 0 1 1 1 1 1 1 1
# attr(,"contrasts")
# attr(,"contrasts")$Cat1
# [1] "contr.treatment"

您可以將結果保留為模型矩陣,將其更改回數據框,或其他任何方式。

這應該適用於您的數據框。 我在運行ifelse語句之前將值轉換為數字。 希望它能工作:

# Make dummy df
Cat1 = factor(c( 4, 1, 1))
Cat2 = factor(c(2, NA, 4))
Cat3 = factor(c(7, NA, NA))

df <- data.frame(Cat1,Cat2,Cat3)

# Specify columns
cols <- c(1:length(df))

# Convert Values To Numeric 
df[,cols] %<>% lapply(function(x) as.numeric(as.character(x)))

# Perform ifelse. If its NA print 0, else print 1
df[,cols] %<>% lapply(function(x) ifelse(x == is.na(x) | (x) %in% NA, 0, 1))

根據輸入:

  Cat1 Cat2 Cat3
1    4    2    7
2    1 <NA> <NA>
3    1    4 <NA>

輸出看起來像這樣:

 Cat1 Cat2 Cat3
1    1    1    1
2    1    0    0
3    1    1    0

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM