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))) }
Here are some possible problems in your function
for (i in names(df)) function (x) { as.factor( as.numeric( cut(df$i,2))) }
df[,i] to subset the column instead of df$i as it is not evaluated properlyfunction(x). 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)))
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)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With