【问题标题】:Change the class from factor to numeric of many columns in a data frame将类从因子更改为数据框中许多列的数字
【发布时间】:2026-02-13 19:05:01
【问题描述】:

将大量列从因子更改为数字的最快/最佳方法是什么?

我使用了以下代码,但它似乎重新排序了我的数据。

> head(stats[,1:2])
  rk                 team
1  1 Washington Capitals*
2  2     San Jose Sharks*
3  3  Chicago Blackhawks*
4  4     Phoenix Coyotes*
5  5   New Jersey Devils*
6  6   Vancouver Canucks*

for(i in c(1,3:ncol(stats))) {
    stats[,i] <- as.numeric(stats[,i])
}

> head(stats[,1:2])
  rk                 team
1  2 Washington Capitals*
2 13     San Jose Sharks*
3 24  Chicago Blackhawks*
4 26     Phoenix Coyotes*
5 27   New Jersey Devils*
6 28   Vancouver Canucks*

最好的方法是什么,没有将每一列命名为:

df$colname <- as.numeric(ds$colname)

【问题讨论】:

  • 没有通用的解决方案吗?这里提出的一些解决方案只适用于因子,其他的总是除了因子之外,等等......

标签: r


【解决方案1】:

将因子更改为数字时必须小心。这是一行代码,可以将一组列从因子更改为数字。我在这里假设要更改为数字的列分别是 1、3、4 和 5。你可以相应地改变它

cols = c(1, 3, 4, 5);    
df[,cols] = apply(df[,cols], 2, function(x) as.numeric(as.character(x)));

【讨论】:

  • 这将无法正常工作。示例:x&lt;-as.factor(1:3); df&lt;-data.frame(a=x,y=runif(3),b=x,c=x,d=x)。我不认为apply 适合这类问题。
  • apply 在这些情况下完美运行。我的代码中的错误是使用margin = 1,而不是2,因为该函数需要按列应用。我已经相应地编辑了我的答案。
  • 现在可以了。但我认为没有apply 也可以做到。检查我的编辑。
  • ... 或 Joris 回答 unlist。并且您的解决方案中不需要as.character 转换,因为applydf[,cols] 转换为character,所以apply(df[,cols], 2, function(x) as.numeric(x)) 也可以工作。
  • @Ramnath,你为什么用=?为什么不用&lt;-
【解决方案2】:

除了 Ramnath 的回答,您遇到的行为是由于 as.numeric(x) 在 R 级别返回因子 x 的内部数字表示。如果要保留作为因子级别的数字(而不是它们的内部表示),则需要按照 Ramnath 的示例首先通过 as.character() 转换为字符。

您的for 循环与apply 调用一样合理,并且对于代码的意图可能更具可读性。只需更改此行:

stats[,i] <- as.numeric(stats[,i])

阅读

stats[,i] <- as.numeric(as.character(stats[,i]))

这是 R 常见问题解答中的 FAQ 7.10

HTH

【讨论】:

  • 不需要任何类型的循环。只需使用索引和 unlist()。编辑:我添加了一个答案来说明这一点。
  • 此方法仅适用于这种特定情况。我试图用它将列转换为factor,但它没有用。 sapplymutate_if 似乎是更普遍适用的解决方案。
  • @Leo Care 扩展,因为我知道这是有效的事实。它完全与下面的 Ramnath 的解决方案相同,除了他使用 apply 运行循环并且 OP 明确使用 for 循环。事实上,所有被高度评价的答案都使用as.numeric(as.character()) 成语。
  • 是的,它可以将多列的类更改为numeric,但它不能反向工作(将多列的类更改为factor)。如果您使用索引,则需要unlist(),并且当应用于具有字符的列时,它会取消列出每个字符,这使得将输出放回stats[,i] 时不再起作用。在这里查看答案:*.com/questions/45713473/…
  • @Leo 当然它不能反过来工作!到底是什么给了你这样的印象?它从未被设计过,OP 也从未要求过。很难回答没有被问到的问题。如果您想将 转换为 因子,请在此处使用 as.factor() 代替 as.numeric(as.character()),它会正常工作。当然,如果您有多个列,则需要有选择地选择i,但这也是微不足道的。
【解决方案3】:

这可以在一行中完成,不需要循环,无论是 for 循环还是应用。使用 unlist() 代替:

# testdata
Df <- data.frame(
  x = as.factor(sample(1:5,30,r=TRUE)),
  y = as.factor(sample(1:5,30,r=TRUE)),
  z = as.factor(sample(1:5,30,r=TRUE)),
  w = as.factor(sample(1:5,30,r=TRUE))
)
##

Df[,c("y","w")] <- as.numeric(as.character(unlist(Df[,c("y","w")])))

str(Df)

编辑:对于您的代码,这变成:

id <- c(1,3:ncol(stats))) 
stats[,id] <- as.numeric(as.character(unlist(stats[,id])))

显然,如果您有一个单列数据框,并且您不希望 R 的自动降维将其转换为向量,则必须添加 drop=FALSE 参数。

【讨论】:

  • 小改进可能是将unlistrecursiveuse.names参数都设置为FALSE
  • @Marek:是的。我喜欢这个游戏:-)
  • 我只是为那些在未来寻找答案的人添加,如果数据框只有一列,这不等同于 op + gavin 的方法。在这种情况下,它将转换为向量,而 op 仍然是数据帧。
  • 对于那些使用 tidyverse 的人:有趣的是,当对象也是 tibble 时,这似乎不起作用:代码在 Df &lt;- tibble::as_tibble(Df) 之后失败
  • @Tjebo 随着 tibble 的更新以及 tibble 和数据帧之间的转移,这种旧方法确实不是 tidyverse 中的最佳选择。您最好将 tidyselect 函数与mutate_if 结合使用。或者在dplyr 的下一次迭代中提供的任何新方法...
【解决方案4】:

我知道这个问题早就解决了,但我最近遇到了一个类似的问题,并认为我找到了一个更优雅和更实用的解决方案,尽管它需要 magrittr 包。

library(magrittr)
cols = c(1, 3, 4, 5)
df[,cols] %<>% lapply(function(x) as.numeric(as.character(x)))

%&lt;&gt;% 运算符管道重新分配,这对于保持数据清理和转换简单非常有用。现在列表应用功能更易于阅读,只需指定您希望应用的功能。

【讨论】:

  • 简洁的解决方案。您忘记了一个括号,但我无法进行此编辑,因为它太短了:df[,cols] %&lt;&gt;% lapply(function(x) as.numeric(as.character(x)))
  • 我认为您甚至不需要将其包裹在 lappy df[,cols] %&lt;&gt;% as.numeric(as.character(.)) 中也一样
  • 当我尝试这个命令时,我收到以下错误Error in [.data.table(Results, , cols) : j (the 2nd argument inside [...]) is a single symbol but column name 'cols' is not found. Perhaps you intended DT[,..cols] or DT[,cols,with=FALSE]. This difference to data.frame is deliberate and explained in FAQ 1.1.
  • 代码如:cols &lt;- c("a","b"); df[,cols] %&lt;&gt;% lapply(function(x) as.numeric(as.character(x)))
  • 现在添加了括号。
【解决方案5】:

这里有一些dplyr 选项:

# by column type:
df %>% 
  mutate_if(is.factor, ~as.numeric(as.character(.)))

# by specific columns:
df %>% 
  mutate_at(vars(x, y, z), ~as.numeric(as.character(.))) 

# all columns:
df %>% 
  mutate_all(~as.numeric(as.character(.))) 

【讨论】:

    【解决方案6】:

    我认为ucfagls found why 你的循环不起作用。

    如果您仍然不想在此处使用循环,则使用 lapply 的解决方案:

    factorToNumeric <- function(f) as.numeric(levels(f))[as.integer(f)] 
    cols <- c(1, 3:ncol(stats))
    stats[cols] <- lapply(stats[cols], factorToNumeric)
    

    编辑。我找到了更简单的解决方案。似乎as.matrix 转换为字符。所以

    stats[cols] <- as.numeric(as.matrix(stats[cols]))
    

    应该做你想做的。

    【讨论】:

      【解决方案7】:

      lapply 就是为此而设计的

      unfactorize<-c("colA","colB")
      df[,unfactorize]<-lapply(unfactorize, function(x) as.numeric(as.character(df[,x])))
      

      【讨论】:

      • 嗨@transcom,欢迎来到*。请注意,这个问题是关于从一个因子转换为数字表示,而不是相反。请参阅 Marek 的解决方案。
      • @Aaron,明白了。由于 OP 的标题含糊不清,我发布了这个答案,假设其他人可能会在这里寻找一种轻松转换多列的方法,而不管类如何。无论如何,我已经编辑了我的答案以更恰当地解决这个问题:)
      【解决方案8】:

      我在其他几个重复的线程上发现了这个函数,并发现它是解决这个问题的一种优雅而通用的方法。这个主题首先出现在关于这个主题的大多数搜索中,所以我在这里分享它以节省人们一些时间。我对此不以为然,因此请参阅原始帖子 herehere 了解详细信息。

      df <- data.frame(x = 1:10,
                       y = rep(1:2, 5),
                       k = rnorm(10, 5,2),
                       z = rep(c(2010, 2012, 2011, 2010, 1999), 2),
                       j = c(rep(c("a", "b", "c"), 3), "d"))
      
      convert.magic <- function(obj, type){
        FUN1 <- switch(type,
                       character = as.character,
                       numeric = as.numeric,
                       factor = as.factor)
        out <- lapply(obj, FUN1)
        as.data.frame(out)
      }
      
      str(df)
      str(convert.magic(df, "character"))
      str(convert.magic(df, "factor"))
      df[, c("x", "y")] <- convert.magic(df[, c("x", "y")], "factor")
      

      【讨论】:

        【解决方案9】:

        我想指出,如果您在任何列中都有 NA,那么简单地使用下标是行不通的。如果 factor 中有 NA,则必须使用 Ramnath 提供的 apply 脚本。

        例如

        Df <- data.frame(
          x = c(NA,as.factor(sample(1:5,30,r=T))),
          y = c(NA,as.factor(sample(1:5,30,r=T))),
          z = c(NA,as.factor(sample(1:5,30,r=T))),
          w = c(NA,as.factor(sample(1:5,30,r=T)))
        )
        
        Df[,c(1:4)] <- as.numeric(as.character(Df[,c(1:4)]))
        

        返回以下内容:

        Warning message:
        NAs introduced by coercion 
        
            > head(Df)
               x  y  z  w
            1 NA NA NA NA
            2 NA NA NA NA
            3 NA NA NA NA
            4 NA NA NA NA
            5 NA NA NA NA
            6 NA NA NA NA
        

        但是:

        Df[,c(1:4)]= apply(Df[,c(1:4)], 2, function(x) as.numeric(as.character(x)))
        

        返回:

        > head(Df)
           x  y  z  w
        1 NA NA NA NA
        2  2  3  4  1
        3  1  5  3  4
        4  2  3  4  1
        5  5  3  5  5
        6  4  2  4  4
        

        【讨论】:

          【解决方案10】:

          您可以使用来自 CRAN 的“varhandle”包形式的 unfactor() 函数:

          library("varhandle")
          
          my_iris <- data.frame(Sepal.Length = factor(iris$Sepal.Length),
                                sample_id = factor(1:nrow(iris)))
          
          my_iris <- unfactor(my_iris)
          

          【讨论】:

            【解决方案11】:

            我喜欢这段代码,因为它非常方便:

              data[] <- lapply(data, function(x) type.convert(as.character(x), as.is = TRUE)) #change all vars to their best fitting data type
            

            这不完全是要求的(转换为数字),但在许多情况下甚至更合适。

            【讨论】:

              【解决方案12】:

              我在一个类似的问题上尝试了一堆这些,并不断得到 NA。 Base R 有一些非常恼人的强制行为,这些行为通常在 Tidyverse 包中得到修复。我过去常常避免使用它们,因为我不想创建依赖项,但它们让生活变得如此轻松,以至于现在我大部分时间都懒得去尝试找出 Base R 解决方案。

              这是 Tidyverse 解决方案,非常简单优雅:

              library(purrr)
              
              mydf <- data.frame(
                x1 = factor(c(3, 5, 4, 2, 1)),
                x2 = factor(c("A", "C", "B", "D", "E")),
                x3 = c(10, 8, 6, 4, 2))
              
              map_df(mydf, as.numeric)
              

              【讨论】:

              • 大多数答案(至少所有最热门的答案)确保进行as.numeric(as.character()) 转换,以避免all-too-common 将整数级别而不是值转换为数字。如果您显示该选项,我很乐意支持此答案。
              【解决方案13】:

              df$colname &lt;- as.numeric(df$colname)

              我尝试过这种方式来更改一种列类型,如果您不打算更改所有列类型,我认为它比许多其他版本更好

              df$colname &lt;- as.character(df$colname)

              反之亦然。

              【讨论】:

                【解决方案14】:

                我在使用apply() 调用将所有列转换为数字时遇到问题:

                apply(data, 2, as.numeric)
                

                问题原来是因为某些字符串中有逗号——例如“1,024.63”而不是“1024.63”——R 不喜欢这种格式化数字的方式。所以我删除了它们然后运行as.numeric()

                data = as.data.frame(apply(data, 2, function(x) {
                  y = str_replace_all(x, ",", "") #remove commas
                  return(as.numeric(y)) #then convert
                }))
                

                请注意,这需要加载 stringr 包。

                【讨论】:

                  【解决方案15】:

                  这对我有用。 apply() 函数试图将 df 强制转换为矩阵并返回 NA。

                  numeric.df &lt;- as.data.frame(sapply(df, 2, as.numeric))

                  【讨论】:

                    【解决方案16】:

                    根据@SDahm 的回答,这是我的tibble 的“最佳”解决方案:

                    data %<>% lapply(type.convert) %>% as.data.table()
                    

                    这需要dplyrmagrittr

                    【讨论】: