如何创建一个函数,仅将连续变量分成相等大小的组?

3
我希望能够在我的数据框中运行一个函数,该函数将仅查找连续变量,并根据将连续变量分为2个相等大小的组添加新的类别变量。 我有一段代码,用于将变量分成组并将其作为新的类别变量添加,但是当我尝试在函数中使用它时,它不起作用。可能是什么问题? 另外,如何避免运行非连续变量?以下是一个玩具数据框:
df <- read.table(text = "         birds    wolfs     
                                    9         7    
                                    8         4    
                                    2         8    
                                    2         3    
                                    8         3    
                                    1         2    
                                    7         1    
                                    1         5    
                                    9         7    
                                    8         7     ",header = TRUE)

我的函数是:

for (i in names(df)) function (x) { as.factor( as.numeric( cut(df$i,2)))  }

1
在你的函数中,你正在使用 df$i。我会使用 df[,i]。其次,输出需要存储在另一个对象中。它没有被定义。 - akrun
2
例如 lst <- vector('list', ncol(df)); for(i in seq_along(df)) {lst[[i]] <- as.factor(as.numeric(cut(df[,i], 2)))} - akrun
1
非常感谢@akrun的帮助,我很感激。 - mql4beginner
1
你应该能够像这样跳过非数字变量:df[paste0(names(df), 'new')] <- lapply(df[,sapply(names(df), function(x) is.numeric(df[,x]))], function(x) factor(cut(x, 2, labels=FALSE))) - ulfelder
1
尝试使用lapply(df1,function(x)!all(x%in%0:1)&is.numeric(x)) - akrun
显示剩余7条评论
1个回答

2
这里列出了您的函数可能存在的一些问题。
for (i in names(df)) function (x) { as.factor( as.numeric( cut(df$i,2)))  }
  1. 我会使用df[,i]来选择列,而不是df$i,因为后者不能正确地被评估。
  2. 不需要使用匿名函数调用function(x)
  3. 输出没有存储在另一个变量中。

前两个问题很容易解决。我们创建一个空的list对象,长度等于'df'的列数(ncol(df))。这可以用于存储结果('lst')。

lst <- vector('list', ncol(df))

现在,我们遍历'df'的每一列(假设所有列都是数字类型),并对每一列应用cut函数(cut(df[,i],..)。

for(i in seq_along(df)) {
        lst[[i]] <- as.factor(as.numeric(cut(df[,i], 2)))
 }

我们可以使用'lst'的输出来分配新列。
df[paste0(names(df), 'new')] <- lst

除了使用 for 循环之外,另一种选择是使用 lapply。从 lapply 中得到的结果可以直接分配给新列。

df[paste0(names(df), 'new')] <- lapply(df, function(x)
                   factor(cut(x, 2, labels=FALSE)))

根据提问者的评论,只过滤numeric列(甚至不包括二进制列)以应用cut。我们使用vapply创建一个逻辑索引。它循环遍历'df2'的列并检查它是否是'numeric' (is.numeric(x)) 以及是否包含0、1之外的值(!all(x %in% 0:1))。

 indx <- vapply(df2, function(x) !all(x %in% 0:1) & is.numeric(x), logical(1L))

使用与上面相同的代码,包括“indx”向量。
   lst <- vector('list', ncol(df2[indx]))
   for(i in seq_along(df2[indx])) {
       lst[[i]] <- as.factor(as.numeric(cut(df2[indx][,i], 2)))
    }
  df2[paste0(names(df2)[indx], 'new')] <- lst

或者使用 lapply 函数。
 df2[paste0(names(df2)[indx], 'new')] <- lapply(df2[indx],
                  function(x) factor(cut(x, 2, labels=FALSE)))

数据

set.seed(24)
df1 <- data.frame(col1=sample(0:1, 10, replace=TRUE),
           col2=rnorm(10), col3=letters[1:10])
#df - OP's dataset

df2 <- cbind(df1, df)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接