Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create a function that will split continuous variables only to groups equal size groups

Tags:

dataframe

r

I would like to run a function over my data frame that will find only continuous variables and add new categorial variables based on dividing the continuous variables to 2 equal size groups. I have a code that I use to split a variable to groups and add it as anew categorial variable but when I tried to use it in a function it does't work.What could be the problem? Also, how can I avoid from running over non continuous variables? Here is a toy data frame:

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)

my function is:

for (i in names(df)) function (x) { as.factor( as.numeric( cut(df$i,2)))  }
like image 479
mql4beginner Avatar asked Jul 23 '26 04:07

mql4beginner


1 Answers

Here are some possible problems in your function

for (i in names(df)) function (x) { as.factor( as.numeric( cut(df$i,2)))  }
  1. I would use df[,i] to subset the column instead of df$i as it is not evaluated properly
  2. There is no need for the anonymous function call function(x).
  3. Output is not stored in another variable.

The first two can be easily fixed. We create an empty list object with length equal to the number of columns of 'df' (ncol(df)). This can be used for storing the results ('lst')

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

Now, we loop through the columns of 'df' (assuming that all the columns are numeric) and apply the cut function to each of the columns (cut(df[,i],..).

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

We can assign new columns with the output of 'lst'

df[paste0(names(df), 'new')] <- lst

Another option instead of for loop would be lapply. The results from the lapply can be directly assigned to new columns.

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

Based on the OP's comments about filtering the numeric columns alone (even excluding the binary columns) for applying the cut. We create a logical index with vapply. It loops through the columns of 'df2' and check whether it is 'numeric' (is.numeric(x)) and if it contains values other than 0, 1 (!all(x %in% 0:1)).

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

Using the same code as above including the 'indx' vector

   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

Or with lapply

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

data

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)
like image 105
akrun Avatar answered Jul 24 '26 21:07

akrun



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!