모든 요인 수준에 대해 R 요인을 1/0 지표 변수 모음으로 자동 확장


108

각 요인 수준에 대해 1/0 지표를 포함하는 새 데이터 프레임에 관련 열이 있도록 "확장"하려는 요인이 포함 된 R 데이터 프레임이 있습니다. 예를 들어 다음이 있다고 가정합니다.

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 ?formula뿐만 아니라 의 두 번째 단락을 검토 ?model.matrix했지만 명확하지 않았습니다 (행렬 대수 및 모델 공식에 대한 지식이 부족할 수 있음). 더 많은 것을 파헤친 후, 나는 -1이 "절편"열을 포함하지 않도록 지정하고 있다는 것을 수집 할 수있었습니다. -1을 생략하면 출력에 1의 가로 채기 열이 표시되고 이진 열 하나는 생략됩니다. 다른 열의 값이 0 인 행을 기반으로 생략 된 열의 값이 1인지 확인할 수 있습니다. 문서가 모호해 보입니다-또 다른 좋은 리소스가 있습니까?
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, ham ~ eggs, length)는 foo = 2를 만듭니다.
kohske

@Kohske, 사실이지만 ham고유 한 행 ID 라고 가정했습니다 . ham고유 ID가 아닌 경우 다른 고유 ID를 사용하거나 더미 ID를 만들어야하며 ham. 범주 레이블을 이진 표시기로 변환하는 것은 고유 한 ID에만 의미가 있습니다.
Prasad Chalasani

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를 활용하는 함수를 추가 할 것이라고 생각했습니다.

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

좀 더 유연한 요소를 '폭발'하는 함수가 필요했고 ade4 패키지의 acm.disjonctif 함수를 기반으로 하나를 만들었습니다. 이렇게하면 acm.disjonctif에서 0과 1 인 분해 된 값을 선택할 수 있습니다. 레벨이 '적은'요인 만 폭발시킵니다. 숫자 열은 유지됩니다.

# 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.