ขยายปัจจัย R โดยอัตโนมัติไปยังชุดของตัวแปรตัวบ่งชี้ 1/0 สำหรับทุกระดับปัจจัย


108

ฉันมีกรอบข้อมูล R ที่มีปัจจัยที่ฉันต้องการ "ขยาย" เพื่อให้แต่ละระดับปัจจัยมีคอลัมน์ที่เกี่ยวข้องในกรอบข้อมูลใหม่ซึ่งมีตัวบ่งชี้ 1/0 เช่นสมมติว่าฉันมี:

df.original <-data.frame(eggs = c("foo", "foo", "bar", "bar"), ham = c(1,2,3,4))

ฉันต้องการ:

df.desired  <- data.frame(foo = c(1,1,0,0), bar=c(0,0,1,1), ham=c(1,2,3,4))

เนื่องจากสำหรับการวิเคราะห์บางอย่างที่คุณต้องมีกรอบข้อมูลที่เป็นตัวเลขทั้งหมด (เช่นการวิเคราะห์องค์ประกอบหลัก) ฉันคิดว่าฟีเจอร์นี้อาจมีอยู่ในตัวการเขียนฟังก์ชันเพื่อทำสิ่งนี้ไม่ควรยากเกินไป แต่ฉันสามารถมองเห็นได้ ความท้าทายเกี่ยวกับชื่อคอลัมน์และหากมีบางอย่างอยู่แล้วฉันควรใช้สิ่งนั้น

คำตอบ:


131

ใช้model.matrixฟังก์ชัน:

model.matrix( ~ Species - 1, data=iris )

1
ฉันสามารถเพิ่มได้castไหมว่าวิธีนี้เร็วกว่าที่ใช้สำหรับฉันมาก
Matt Weller

3
@GregSnow ฉันตรวจสอบย่อหน้าที่ 2 ของ?formulaเช่นเดียวกับ?model.matrixแต่ก็ไม่ชัดเจน (อาจเป็นเพราะฉันขาดความรู้เชิงลึกในพีชคณิตเมทริกซ์และการกำหนดแบบจำลอง) หลังจากขุดเพิ่มเติมฉันสามารถรวบรวมได้ว่า -1 เป็นเพียงการระบุไม่ให้รวมคอลัมน์ "สกัดกั้น" หากคุณไม่ใช้ -1 คุณจะเห็นคอลัมน์สกัดกั้นของ 1 ในผลลัพธ์โดยเหลือคอลัมน์ไบนารีไว้หนึ่งคอลัมน์ คุณสามารถดูว่าค่าใดที่คอลัมน์ที่ละไว้คือ 1 ตามแถวที่ค่าของคอลัมน์อื่น ๆ เป็น 0 เอกสารดูเหมือนเป็นความลับ - มีแหล่งข้อมูลอื่นที่ดีหรือไม่?
Ryan Chase

1
@RyanChase มีบทเรียนออนไลน์และหนังสือมากมายเกี่ยวกับ R / S (หลายเล่มที่มีคำอธิบายสั้น ๆ ในหน้าเว็บ r-project.org) การเรียนรู้ S และ R ของตัวเองค่อนข้างผสมผสาน (และยาวนาน) ดังนั้นฉันจึงไม่ดีที่สุดที่จะให้ความเห็นว่าหนังสือ / แบบฝึกหัดในปัจจุบันดึงดูดผู้เริ่มต้นอย่างไร อย่างไรก็ตามฉันเป็นแฟนตัวยงของการทดลอง การลองทำอะไรบางอย่างในเซสชัน R ใหม่สามารถให้ความกระจ่างได้มากและไม่เป็นอันตราย (สิ่งที่เลวร้ายที่สุดที่เกิดขึ้นกับฉันคือการขัดข้อง R และแทบจะไม่ทำให้เกิดการปรับปรุงใน R) Stackoverflow เป็นแหล่งข้อมูลที่ดีสำหรับการทำความเข้าใจว่าเกิดอะไรขึ้น
Greg Snow

7
และถ้าคุณต้องการแปลงคอลัมน์ปัจจัยทั้งหมดคุณสามารถใช้:model.matrix(~., data=iris)[,-1]
user890739

1
@colin ไม่อัตโนมัติ แต่คุณสามารถใช้ที่จะนำค่าที่หายไปกลับมาอยู่ในหลังการใช้naresid na.excludeตัวอย่างสั้น ๆ :tmp <- data.frame(x=factor(c('a','b','c',NA,'a'))); tmp2 <- na.exclude(tmp); tmp3 <- model.matrix( ~x-1, tmp2); tmp4 <- naresid(attr(tmp2,'na.action'), tmp3)
Greg Snow

17

หากกรอบข้อมูลของคุณสร้างขึ้นจากปัจจัยเท่านั้น (หรือคุณกำลังทำงานกับตัวแปรย่อยซึ่งเป็นปัจจัยทั้งหมด) คุณยังสามารถใช้acm.disjonctifฟังก์ชันจากade4แพ็คเกจ:

R> library(ade4)
R> df <-data.frame(eggs = c("foo", "foo", "bar", "bar"), ham = c("red","blue","green","red"))
R> acm.disjonctif(df)
  eggs.bar eggs.foo ham.blue ham.green ham.red
1        0        1        0         0       1
2        0        1        1         0       0
3        1        0        0         1       0
4        1        0        0         0       1

ไม่ตรงกับกรณีที่คุณอธิบาย แต่มันก็มีประโยชน์เช่นกัน ...


ขอบคุณสิ่งนี้ช่วยฉันได้มากเพราะมันใช้หน่วยความจำน้อยกว่า model.matrix!
Serhiy

ฉันชอบวิธีตั้งชื่อตัวแปร ฉันไม่ชอบที่พวกเขาจะถูกส่งคืนเป็นตัวเลขที่หิวจัดเก็บเมื่อพวกเขาควร (IMHO) เป็นเพียงตรรกะ
dsz

9

วิธีที่รวดเร็วในการใช้reshape2แพ็คเกจ:

require(reshape2)

> dcast(df.original, ham ~ eggs, length)

Using ham as value column: use value_var to override.
  ham bar foo
1   1   0   1
2   2   0   1
3   3   1   0
4   4   1   0

โปรดทราบว่าสิ่งนี้สร้างชื่อคอลัมน์ที่คุณต้องการอย่างแม่นยำ


ดี. แต่ระวังเรื่องแฮมที่ซ้ำกัน พูด d <- data.frame (eggs = c ("foo", "bar", "foo"), ham = c (1,2,1)); dcast (d, แฮม ~ ไข่, ความยาว) ทำให้ foo = 2
kohske

@Kohske จริง แต่ฉันคิดว่าhamเป็น id แถวที่ไม่ซ้ำกัน ถ้าhamไม่ได้เป็น ID ที่ไม่ซ้ำกันจากนั้นหนึ่งต้องใช้บางส่วนอื่น ๆ ที่ไม่ซ้ำกัน-ID (หรือสร้างแบบจำลอง) hamและการใช้งานที่อยู่ในสถานที่ของ การแปลงป้ายกำกับหมวดหมู่เป็นตัวบ่งชี้ไบนารีจะเหมาะสมสำหรับรหัสเฉพาะเท่านั้น
ปราสาทชลาสนี

6

ตัวแปรจำลองอาจคล้ายกับสิ่งที่คุณต้องการ จากนั้น model.matrix มีประโยชน์:

> with(df.original, data.frame(model.matrix(~eggs+0), ham))
  eggsbar eggsfoo ham
1       0       1   1
2       0       1   2
3       1       0   3
4       1       0   4

6

รายการล่าช้าclass.indจากnnetแพ็คเกจ

library(nnet)
 with(df.original, data.frame(class.ind(eggs), ham))
  bar foo ham
1   0   1   1
2   0   1   2
3   1   0   3
4   1   0   4

4

เพิ่งเจอกระทู้เก่านี้และคิดว่าฉันจะเพิ่มฟังก์ชันที่ใช้ ade4 เพื่อใช้ dataframe ที่ประกอบด้วยปัจจัยและ / หรือข้อมูลตัวเลขและส่งคืนดาต้าเฟรมพร้อมแฟกเตอร์เป็นโค้ดดัมมี่

dummy <- function(df) {  

    NUM <- function(dataframe)dataframe[,sapply(dataframe,is.numeric)]
    FAC <- function(dataframe)dataframe[,sapply(dataframe,is.factor)]

    require(ade4)
    if (is.null(ncol(NUM(df)))) {
        DF <- data.frame(NUM(df), acm.disjonctif(FAC(df)))
        names(DF)[1] <- colnames(df)[which(sapply(df, is.numeric))]
    } else {
        DF <- data.frame(NUM(df), acm.disjonctif(FAC(df)))
    }
    return(DF)
} 

มาลองดูกัน.

df <-data.frame(eggs = c("foo", "foo", "bar", "bar"), 
            ham = c("red","blue","green","red"), x=rnorm(4))     
dummy(df)

df2 <-data.frame(eggs = c("foo", "foo", "bar", "bar"), 
            ham = c("red","blue","green","red"))  
dummy(df2)

3

นี่คือวิธีที่ชัดเจนยิ่งขึ้นในการทำ ฉันใช้ model.matrix เพื่อสร้างตัวแปรบูลีนดัมมี่แล้วรวมกลับเข้าไปในดาต้าเฟรมเดิม

df.original <-data.frame(eggs = c("foo", "foo", "bar", "bar"), ham = c(1,2,3,4))
df.original
#   eggs ham
# 1  foo   1
# 2  foo   2
# 3  bar   3
# 4  bar   4

# Create the dummy boolean variables using the model.matrix() function.
> mm <- model.matrix(~eggs-1, df.original)
> mm
#   eggsbar eggsfoo
# 1       0       1
# 2       0       1
# 3       1       0
# 4       1       0
# attr(,"assign")
# [1] 1 1
# attr(,"contrasts")
# attr(,"contrasts")$eggs
# [1] "contr.treatment"

# Remove the "eggs" prefix from the column names as the OP desired.
colnames(mm) <- gsub("eggs","",colnames(mm))
mm
#   bar foo
# 1   0   1
# 2   0   1
# 3   1   0
# 4   1   0
# attr(,"assign")
# [1] 1 1
# attr(,"contrasts")
# attr(,"contrasts")$eggs
# [1] "contr.treatment"

# Combine the matrix back with the original dataframe.
result <- cbind(df.original, mm)
result
#   eggs ham bar foo
# 1  foo   1   0   1
# 2  foo   2   0   1
# 3  bar   3   1   0
# 4  bar   4   1   0

# At this point, you can select out the columns that you want.

0

ฉันต้องการฟังก์ชันเพื่อ 'ระเบิด' ปัจจัยที่ยืดหยุ่นกว่าเล็กน้อยและสร้างขึ้นมาจากฟังก์ชัน acm.disjonctif จากแพ็คเกจ ade4 สิ่งนี้ช่วยให้คุณสามารถเลือกค่าที่ระเบิดได้ซึ่งเป็น 0 และ 1 ใน acm.disjonctif มันระเบิดเฉพาะปัจจัยที่มีระดับ 'น้อย' คอลัมน์ตัวเลขจะถูกเก็บรักษาไว้

# Function to explode factors that are considered to be categorical,
# i.e., they do not have too many levels.
# - data: The data.frame in which categorical variables will be exploded.
# - values: The exploded values for the value being unequal and equal to a level.
# - max_factor_level_fraction: Maximum number of levels as a fraction of column length. Set to 1 to explode all factors.
# Inspired by the acm.disjonctif function in the ade4 package.
explode_factors <- function(data, values = c(-0.8, 0.8), max_factor_level_fraction = 0.2) {
  exploders <- colnames(data)[sapply(data, function(col){
      is.factor(col) && nlevels(col) <= max_factor_level_fraction * length(col)
    })]
  if (length(exploders) > 0) {
    exploded <- lapply(exploders, function(exp){
        col <- data[, exp]
        n <- length(col)
        dummies <- matrix(values[1], n, length(levels(col)))
        dummies[(1:n) + n * (unclass(col) - 1)] <- values[2]
        colnames(dummies) <- paste(exp, levels(col), sep = '_')
        dummies
      })
    # Only keep numeric data.
    data <- data[sapply(data, is.numeric)]
    # Add exploded values.
    data <- cbind(data, exploded)
  }
  return(data)
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.