【问题标题】:Label Encoder functionality in R?R中的标签编码器功能?
【发布时间】:2016-07-27 18:18:01
【问题描述】:

在 python 中,scikit 有一个很棒的函数LabelEncoder,它将分类级别(字符串)映射到整数表示。

R 中有什么可以做到这一点?例如,如果有一个名为 color 的变量,其值为 {'Blue','Red','Green'},编码器会翻译:

Blue => 1
Green => 2
Red => 3

并使用此映射创建一个对象,然后用于以类似方式转换新数据。

添加: 似乎只有因素会起作用,因为映射没有持久性。如果新数据具有从训练数据中看不到的级别,则整个结构会发生变化。理想情况下,我希望以某种方式标记为缺失或“其他”的新关卡。

sample_dat <- data.frame(a_str=c('Red','Blue','Blue','Red','Green'))
sample_dat$a_int<-as.integer(as.factor(sample_dat$a_str))
sample_dat$a_int
#[1] 3 1 1 3 2
sample_dat2 <- data.frame(a_str=c('Red','Blue','Blue','Red','Green','Azure'))
sample_dat2$a_int<-as.integer(as.factor(sample_dat2$a_str))
sample_dat2$a_int
# [1] 4 2 2 4 3 1

【问题讨论】:

  • R 中的因子被编码为整数。不确定您的“要求”到底是什么。
  • 因子是否会作为字符串到整数的一致索引以用于未来数据?我将在我的问题中展示一个示例
  • 如果您明确列出因子可以保持的水平,它们可以。

标签: r


【解决方案1】:

创建数据向量:

colors <- c("red", "red", "blue", "green")

创建一个因子:

factors <- factor(colors)

将因子转换为数字:

as.numeric(factors)

输出:(注意这是按字母顺序排列的)

# [1] 3 3 1 2

您还可以设置自定义编号系统:(注意现在的输出遵循我定义的“彩虹色顺序”)

rainbow <- c("red","orange","yellow","green","blue","purple")
ordered <- factor(colors, levels = rainbow)
as.numeric(ordered)
# [1] 1 1 5 4

?factor

【讨论】:

  • 这似乎运作良好。我想知道是否有任何库已经创建了处理步骤(插入符号没有)或者需要从头开始编码(最初进行转换并创建字典以便以后应用编码)。
  • 如何做回映射?就像在第一个示例中一样,如果我发送 3,那么我应该得到“红色”。这怎么可能?谢谢
【解决方案2】:

试试CatEncoders 包。它复制了 Python sklearn.preprocessing 功能。

# variable to encode values
colors = c("red", "red", "blue", "green")
lab_enc = LabelEncoder.fit(colors)

# new values are transformed to NA
values = transform(lab_enc, c('red', 'red', 'yellow'))
values

# [1]  3  3 NA


# doing the inverse: given the encoded numbers return the labels
inverse.transform(lab_enc, values)
# [1] "red" "red" NA   

我会添加使用警告报告不匹配标签的功能。

PS:它还有OneHotEncoder功能。

【讨论】:

  • 这实际上是我要找的。​​span>
【解决方案3】:

如果我正确理解你想要什么:

# function which returns function which will encode vectors with values  of 'vec' 
label_encoder = function(vec){
    levels = sort(unique(vec))
    function(x){
        match(x, levels)
    }
}

colors = c("red", "red", "blue", "green")

color_encoder = label_encoder(colors) # create encoder

encoded_colors = color_encoder(colors) # encode colors
encoded_colors

new_colors = c("blue", "green", "green")  # new vector
encoded_new_colors = color_encoder(new_colors)
encoded_new_colors

other_colors = c("blue", "green", "green", "yellow") 
color_encoder(other_colors) # NA's are introduced

# save and restore to disk
saveRDS(color_encoder, "color_encoder.RDS")
c_encoder = readRDS("color_encoder.RDS")
c_encoder(colors) # same result

# dealing with multiple columns

# create data.frame
set.seed(123) # make result reproducible
color_dataframe = as.data.frame(
    matrix(
        sample(c("red", "blue", "green",  "yellow"), 12, replace = TRUE),
        ncol = 3)
)
color_dataframe

# encode each column
for (column in colnames(color_dataframe)){
    color_dataframe[[column]] = color_encoder(color_dataframe[[column]])
}
color_dataframe

【讨论】:

  • 哇....我希望我明白这是在做什么,但似乎有效。是否可以运行多个列(应用)并将对象保存到磁盘以供以后编码?
  • @B_Miner 查看我的补充回答
  • 非常令人印象深刻!你能告诉我嵌套函数是如何工作的吗?
  • @B_Miner R 具有词法作用域。这意味着每个创建的编码器都将“看到”它自己的levels 变量,该变量位于封闭的编码器环境中。您可以在出色的 Hadley Wickham 指南中详细了解范围界定:adv-r.had.co.nz/Functions.html
  • 感觉这个功能很接近,但它需要的可能是一种单独处理每一列的方法。这样每个字符串和 int 之间的映射每列都是不同的。我可能没有很好地描述需求。如果您有兴趣,我可以提出另一个问题。
【解决方案4】:

我编写了以下我认为可行的代码,但尚未测试其效率和/或扩展方式

str2Int.fit_transform<-function(df, plug_missing=TRUE){

  list_of_levels=list()  #empty list   

  #loop through the columns
  for (i in 1: ncol(df))
  {

    #only   
    if (is.character(df[,i]) ||  is.factor(df[,i]) ){

      #deal with missing
      if(plug_missing){

        #if factor
        if (is.factor(df[,i])){
          df[,i] = factor(df[,i], levels=c(levels(df[,i]), 'MISSING'))
          df[,i][is.na(df[,i])] = 'MISSING' 


        }else{   #if character

          df[,i][is.na(df[,i])] = 'MISSING' 

        }
      }#end missing IF

      levels<-unique(df[,i]) #distinct levels
      list_of_levels[[colnames(df)[i]]] <- levels #set list with name of the columns to the levels
      df[,i] <- as.numeric(factor(df[,i], levels = levels))

    }#end if character/factor IF


  }#end loop

  return (list(list_of_levels,df)) #return the list of levels and the new DF

}#end of function



str2Int.transform<-function(df,list_of_levels,plug_missing=TRUE)
{
  #loop through the columns
  for (i in 1: ncol(df))
  {

    #only   
    if (is.character(df[,i]) ||  is.factor(df[,i]) ){


      #deal with missing
      if(plug_missing){

        #if factor
        if (is.factor(df[,i])){
          df[,i] = factor(df[,i], levels=c(levels(df[,i]), 'MISSING'))
          df[,i][is.na(df[,i])] = 'MISSING' 


        }else{   #if character

          df[,i][is.na(df[,i])] = 'MISSING' 

        }
      }#end missing IF

      levels=list_of_levels[[colnames(df)[i]]]

      if (! is.null(levels)){
        df[,i] <- as.numeric(factor(df[,i], levels = levels))
      }

    }# character or factor

  }#end of loop

  return(df)

}#end of function




######################################################
# Test the functions
######################################################



###Test fit transform

# as strings
sample_dat <- data.frame(a_fact=c('Red','Blue','Blue',NA,'Green'), a_int=c(1,2,3,4,5), a_str=c('a','b','c','a','v'),stringsAsFactors=FALSE)

result<-str2Int.fit_transform(sample_dat)
result[[1]] #list of levels
result[[2]] #transformed df

#as factors
sample_dat <- data.frame(a_fact=c('Red','Blue','Blue',NA,'Green'), a_int=c(1,2,3,4,5), a_str=c('a','b','c','a','v'),stringsAsFactors=TRUE)

result<-str2Int.fit_transform(sample_dat)
result[[1]] #list of levels
result[[2]] #transformed df



###Test transform
str2Int.transform(sample_dat,result[[1]])

【讨论】:

  • 最重要的是,您的解决方案适用于输入数据不完整、新数据和缺失数据的情况。做得好。我用这个测试过:new_dat &lt;- data.frame(a_fact=c('Green','purple', 'Blue'), a_int=c(1,2, 3), a_str=c('z', 'a', NA), stringsAsFactors=FALSE) ; str2Int.transform(new_dat, result[[1]]) ; # a_fact a_int a_str # 1 4 1 NA # 2 NA 2 1 # 3 2 3 NA(这很难读……但它是对的)
  • 我做了一些更改并添加了一些测试/示例。我肯定会在geneorama(我的个人包)中使用它。我唯一想要的另一件事是使用指标变量生成输出矩阵的方法。不过应该不会太难。 gist.github.com/geneorama/02e4e6edb2070d8873377e09d3ecc5d9
【解决方案5】:

很难相信为什么没有人提到caretdummyVars 函数。

这是一个被广泛搜索的问题,人们不想编写自己的方法或复制粘贴其他用户的方法,他们想要一个,而caret 是最接近的sklearn 在 R.

编辑:我现在意识到用户真正想要的是将字符串转换为计数,这只是as.numeric(as.factor(x)),但我将把它留在这里,因为使用热一编码是更准确的方法编码分类数据。

【讨论】:

    【解决方案6】:
    # input P to the function below is a dataframe containing only categorical variables
    numlevel <- function(P) { 
    
    n <- dim(P)[2]
    
    for(i in 1: n) {
    
      m <- length(unique(P[[i]]))
    
    levels(P[[i]]) <- c(1:m)
    
    }
    
    return(P)
    
    }
    
    Q <- numlevel(P) 
    

    【讨论】:

      【解决方案7】:
      df<- mtcars
      
      head(df)
      
      df$cyl  <- factor(df$cyl)
      
      df$carb <- factor(df$carb)
      vec <- sapply(df, is.factor)
      
      catlevels <- sapply(df[vec], levels)
      
      #store the levels for each category
      #level appearing first is coded as 1, second as 2 so on
      
      df <- sapply(df, as.numeric)
      
      class(df) #matrix
      
      df <- data.frame(df) 
      
      #converting back to dataframe
      
      head(df)
      

      【讨论】:

        【解决方案8】:
        # Data
        Country <- c("France", "Spain", "Germany", "Spain", "Germany", "France")
        Age <- c(34, 27, 30, 32, 42, 30)
        Purchased <- c("No", "Yes", "No", "No", "Yes", "Yes")
        df <- data.frame(Country, Age, Purchased)
        df
        
        # Output
          Country Age Purchased
        1  France  34        No
        2   Spain  27       Yes
        3 Germany  30        No
        4   Spain  32        No
        5 Germany  42       Yes
        6  France  30       Yes
        

        使用 CatEncoders 包:分类变量的编码器

        library(CatEncoders)
        
        # Saving names of categorical variables
        factors <- names(which(sapply(df, is.factor)))
        
        # Label Encoder
        for (i in factors){
          encode <- LabelEncoder.fit(df[, i])
          df[, i] <- transform(encode, df[, i])
        }
        df
        
        # Output
          Country Age Purchased
        1       1  34         1
        2       3  27         2
        3       2  30         1
        4       3  32         1
        5       2  42         2
        6       1  30         2
        

        使用 R 基础:因子函数

        # Label Encoder
        levels <- c("France", "Spain", "Germany", "No", "Yes")
        labels <- c(1, 2, 3, 1, 2)
        for (i in factors){
          df[, i] <- factor(df[, i], levels = levels, labels = labels, ordered = TRUE)
        }
        df
        
        # Output
          Country Age Purchased
        1       1  34         1
        2       2  27         2
        3       3  30         1
        4       2  32         1
        5       3  42         2
        6       1  30         2
        

        【讨论】:

          【解决方案9】:

          这是一个简单简洁的解决方案:

          来自 superml 包: https://www.rdocumentation.org/packages/superml/versions/0.5.3 有一个 LabelEncoder 类: https://www.rdocumentation.org/packages/superml/versions/0.5.3/topics/LabelEncoder

          install.packages("superml")
          library(superml)
          
          lbl <- LabelEncoder$new()
          lbl$fit(sample_dat$column)
          sample_dat$column <- lbl$fit_transform(sample_dat$column)
          decode_names <- lbl$inverse_transform(sample_dat$column)
          

          【讨论】:

            猜你喜欢
            • 2019-09-09
            • 2016-12-11
            • 1970-01-01
            • 2019-09-07
            • 2016-10-10
            • 2010-10-21
            • 2013-09-18
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多