【问题标题】:Issue with user defined function in RR中用户定义函数的问题
【发布时间】:2018-09-06 11:34:05
【问题描述】:

如果它们是“字符”,我正在尝试将数据框中的变量的数据类型更改为“因子”。我尝试使用如下示例数据复制问题

a <- c("AB","BC","AB","BC","AB","BC")
b <- c(12,23,34,45,54,65)
df <- data.frame(a,b)
str(df)

'data.frame':   6 obs. of  2 variables:
 $ a: chr  "AB" "BC" "AB" "BC" ...
 $ b: num  12 23 34 45 54 65

我写了下面的函数来实现这一点

abc <- function(x) {
  for(i in names(x)){
    if(is.character(x[[i]])) {
      x[[i]] <- as.factor(x[[i]])
    }
  }
}

如果我传递数据帧 (df),该函数将正确执行,但它仍然不会将“字符”更改为“因子”。

abc(df)

str(df)
'data.frame':   6 obs. of  2 variables:
 $ a: chr  "AB" "BC" "AB" "BC" ...
 $ b: num  12 23 34 45 54 65

注意:它与 for 循环和 if 条件完美配合。当我试图通过围绕它编写一个函数来概括它时,出现了问题。

请帮忙。我错过了什么?

【问题讨论】:

  • 让你的函数返回x,然后执行df &lt;- abc(df)
  • 正如@Roland 所说。 R 中的函数不是通过引用来执行的。如果您在函数内部更改函数参数,则对象在函数外部保持不变。另外,最后你需要你的函数return(x)
  • @Roland 和 Nicola 感谢您的建议。它奏效了。

标签: r function


【解决方案1】:

除了来自@Roland 的评论,您应该利用R 的良好索引可能性并了解*apply 系列。有了它,您可以将代码重写为

change_to_factor <- function(df_in) {
    chr_ind <- vapply(df_in, is.character, logical(1))
    df_in[, chr_ind] <- lapply(df_in[, chr_ind, drop = FALSE], as.factor)
    df_in
}

说明

  • vapply 循环遍历列表的所有元素,将函数应用于每个元素并返回给定类型的值(这里是布尔值logical(1))。由于R 中的数据帧实际上是lists,其中每个(列表)元素都需要具有相同的长度,因此您可以方便地循环遍历数据帧的所有列并将函数is.character 应用于每一列. vapply 然后返回一个布尔(逻辑)向量,其中包含 TRUE/FALSE 值,具体取决于该列是否为字符列。
  • 然后您可以使用此布尔向量对数据框进行子集化,以仅查看属于字符列的列。
  • lapply*apply 系列的另一个成员,循环遍历列表元素并返回一个列表。我们现在遍历字符列,将as.factor 应用于它们并返回它们的列表,我们方便地将其存储在数据框中的原始位置

顺便说一下,如果您查看str(df),您会看到b 列已经是一个因素。这是因为data.frame 自动将字符列转换为字符。为避免这种情况,您需要将stringsAsFactors = FALSE 传递给data.frame

a <- c("AB", "BC", "AB", "BC", "AB", "BC")
b <- c(12, 23, 34, 45, 54, 65)
df <- data.frame(a, b)

str(df) # column b is factor
# 'data.frame':   6 obs. of  2 variables:
# $ a: Factor w/ 2 levels "AB","BC": 1 2 1 2 1 2
# $ b: num  12 23 34 45 54 65

str(df2 <- data.frame(a, b, stringsAsFactors = FALSE))
# 'data.frame':   6 obs. of  2 variables:
#  $ a: chr  "AB" "BC" "AB" "BC" ...
#  $ b: num  12 23 34 45 54 65

str(change_to_factor(df2))
# 'data.frame':   6 obs. of  2 variables:
#  $ a: Factor w/ 2 levels "AB","BC": 1 2 1 2 1 2
#  $ b: num  12 23 34 45 54 65

学习tidyverse 语法可能也很值得,您可以简单地使用它

library(tidyverse)
df2 %>% 
  mutate_if(is.character, as.factor) %>% 
  str()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-13
    • 1970-01-01
    • 1970-01-01
    • 2011-02-17
    相关资源
    最近更新 更多