R中用户定义函数的问题

时间:2018-09-06 11:34:06

标签: r function

我试图将数据框中变量的数据类型更改为“ factor”(如果它们是“字符”)。我尝试使用以下示例数据来复制问题

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),该函数将正确执行,但仍不会将'character'更改为'factor'。

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条件完美配合。当我尝试通过围绕它编写一个函数来概括它时,出现了问题。

请帮助。我想念什么?

1 个答案:

答案 0 :(得分:2)

除了@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,其中每个(列表)元素都必须具有相同的长度,因此您可以方便地在数据帧的所有列上循环并应用函数{{ 1}}。然后is.character返回带有vapply值的布尔(逻辑)向量,具体取决于该列是否是字符列。
  • 然后您可以使用此布尔向量对数据框进行子集处理,以仅查看字符列。
  • TRUE/FALSElapply系列的另一个成员,它遍历列表元素并返回一个列表。现在,我们遍历字符列,将*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