programing

R 요인을 각 요인 수준에 대한 1/0 지시 변수 집합으로 자동 확장

starjava 2023. 7. 1. 07:57
반응형

R 요인을 각 요인 수준에 대한 1/0 지시 변수 집합으로 자동 확장

각 요인 수준에 대해 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))

완전한 숫자 데이터 프레임이 필요한 특정 분석(예: 주성분 분석)의 경우 이 기능이 내장되어 있을 수 있다고 생각했기 때문입니다.이를 위한 함수를 작성하는 것은 어렵지 않지만 열 이름과 관련된 몇 가지 문제를 예측할 수 있으며 이미 존재하는 것이 있다면 차라리 그것을 사용하고 싶습니다.

사용model.matrix함수:

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

데이터 프레임이 요인으로만 구성된 경우(또는 모든 요인인 변수의 부분 집합에 대해 작업하는 경우)에도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

당신이 설명하는 경우는 아니지만, 유용할 수도 있습니다.

빠른 사용 방법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

이렇게 하면 원하는 열 이름이 정확하게 생성됩니다.

아마도 더미 변수는 당신이 원하는 것과 유사합니다.그러면 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

늦은 입장.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

이 오래된 스레드를 우연히 발견하고 ad4를 활용하여 요인 및/또는 숫자 데이터로 구성된 데이터 프레임을 취하고 요인이 포함된 데이터 프레임을 더미 코드로 반환하는 기능을 추가하려고 생각했습니다.

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)

여기 그것을 하는 더 확실한 방법이 있습니다.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.

저는 조금 더 유연한 요소들을 '폭발'하는 기능이 필요했고, ade4 패키지의 acm.disjonctif 함수를 기반으로 만들었습니다.이렇게 하면 cm.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)
}

(문제는 10yo입니다, 하지만 완성도를 위해서는...)

패키지의 기능이 바로 그렇게 합니다.

요인과 같은 변수에서 설계 행렬을 생성하는 것 외에도 두 가지 추가 작업을 즉시 수행할 수 있습니다.

  • 바인딩 값('bin' 인수 포함),
  • 값 부 인 제 인 값 외 포 (함 일 수 요 인 함 포 ) ▁argument ▁the ( )ref).

이 을 위해 에, 을 리고이작위때에문만, 변숫면자라다그당, 그필없을끝으로 묶을 필요가 없습니다.factor(x_num)((으)와 model.matrix해결책).

다음은 예입니다.

library(fixest)
data(airquality)
table(airquality$Month)
#>  5  6  7  8  9 
#> 31 30 31 31 30

head(i(airquality$Month))
#>      5 6 7 8 9
#> [1,] 1 0 0 0 0
#> [2,] 1 0 0 0 0
#> [3,] 1 0 0 0 0
#> [4,] 1 0 0 0 0
#> [5,] 1 0 0 0 0
#> [6,] 1 0 0 0 0

#
# Binning (check out the help, there are many many ways to bin)
#

colSums(i(airquality$Month, bin = 5:6)))
#>  5  7  8  9 
#> 61 31 31 30 

#
# References
#

head(i(airquality$Month, ref = c(6, 9)), 3)
#>      5 7 8
#> [1,] 1 0 0
#> [2,] 1 0 0
#> [3,] 1 0 0

다음은 숫자가 아닌 모든 변수를 확장하는 작은 래퍼입니다(기본값).

library(fixest)

# data: data.frame
# var: vector of variable names // if missing, all non numeric variables
# no argument checking
expand_factor = function(data, var){
    
    if(missing(var)){
        var = names(data)[!sapply(data, is.numeric)]
        if(length(var) == 0) return(data)
    }
    
    data_list = unclass(data)
    new = lapply(var, \(x) i(data_list[[x]]))
    data_list[names(data_list) %in% var] = new
    
    do.call("cbind", data_list)
}

my_data = data.frame(eggs = c("foo", "foo", "bar", "bar"), ham = c(1,2,3,4))

expand_factor(my_data)
#>      bar foo ham
#> [1,]   0   1   1
#> [2,]   0   1   2
#> [3,]   1   0   3
#> [4,]   1   0   4

에게, 그는 마막으로사, 궁한들게에, 그는시기와 .model.matrix해결책

library(microbenchmark)
my_data = data.frame(x = as.factor(sample(100, 1e6, TRUE)))

microbenchmark(mm = model.matrix(~x, my_data),
               i = i(my_data$x), times = 5)
#> Unit: milliseconds
#>  expr      min       lq     mean   median       uq      max neval
#>    mm 155.1904 156.7751 209.2629 182.4964 197.9084 353.9443     5
#>     i 154.1697 154.7893 159.5202 155.4166 163.9706 169.2550     5

sapply ==계란 초과는 더미 벡터를 생성하는 데 사용될 수 있습니다.

x <- with(df.original, data.frame(+sapply(unique(eggs), `==`, eggs), ham))
x
#  foo bar ham
#1   1   0   1
#2   1   0   2
#3   0   1   3
#4   0   1   4

all.equal(x, df.desired)
#[1] TRUE

더 빠른 변형 모델 - 결과가 가장 잘 사용됩니다.list또는data.frame:

. <- unique(df.original$eggs)
with(df.original, 
     data.frame(+do.call(cbind, lapply(setNames(., .), `==`, eggs)), ham))

에서 matrix결과는 다음과 같이 가장 잘 사용됩니다.matrix:

. <- unique(df.original$eggs)
i <- match(df.original$eggs, .)
nc <- length(.)
nr <- length(i)
cbind(matrix(`[<-`(integer(nc * nr), 1:nr + nr * (i - 1), 1), nr, nc,
                 dimnames=list(NULL, .)), df.original["ham"])

용사를 합니다.outer결과는 다음과 같이 가장 잘 사용됩니다.matrix:

. <- unique(df.original$eggs)
cbind(+outer(df.original$eggs, setNames(., .), `==`), df.original["ham"])

용사를 합니다.rep결과는 다음과 같이 가장 잘 사용됩니다.matrix:

. <- unique(df.original$eggs)
n <- nrow(df.original)
cbind(+matrix(df.original$eggs == rep(., each=n), n, dimnames=list(NULL, .)),
 df.original["ham"])

언급URL : https://stackoverflow.com/questions/5048638/automatically-expanding-an-r-factor-into-a-collection-of-1-0-indicator-variables

반응형