jacky_learns_to_code
jacky_learns_to_code

Reputation: 824

Map specific columns to a function that takes in two arguments

After running k-means() on using different numbers of k = [2,3,4,5] on the iris dataset using the map() function, I would like to interpret the results for different k using a predefined function.

Below is my attempt:

library(dplyr)
library(purrr)

cluster_assignment <- map(2:5, function(k){
  result <- kmeans((x = iris[-5] %>%
                          scale()),
                    centers = k)

  # # return results to a list
  x <- list(result$cluster,
            result$tot.withinss,
            result$centers,
            result$size)
})


# assign cluster results back to the iris dataset
a <- map_dfc(cluster_assignment, 1)
colnames(a) <- paste0("result_", 2:5, "_cl")
iris <- bind_cols(iris, a)

> head(iris)
  Sepal.Length Sepal.Width Petal.Length Petal.Width Species result_2_cl result_3_cl result_4_cl result_5_cl
1          5.1         3.5          1.4         0.2  setosa           2           2           3           3
2          4.9         3.0          1.4         0.2  setosa           2           1           3           2
3          4.7         3.2          1.3         0.2  setosa           2           1           3           2
4          4.6         3.1          1.5         0.2  setosa           2           1           3           2
5          5.0         3.6          1.4         0.2  setosa           2           2           3           3
6          5.4         3.9          1.7         0.4  setosa           2           2           3           5

Now, I would apply a predefined function cluster_result2 to the newly assigned columns, i.e "result_2_cl", "result_3_cl", "result_4_cl", "result_5_cl"

# predefined function
cluster_result2 <- function(x, ...){
 x %>%
   group_by_(...) %>%
   summarise(size = n(),
             mean_spl = mean(Sepal.Length))
}

# tried this method, but did not get the expected output
map(iris[, colnames(a)], ~ cluster_result2(iris, .x))

How can I achieve this using the tidyverse approach? I found a very similar approach here, but couldn't get the expected output.

The expected output will be similar to the ones below, except they are stored in a nested list/dataframe:

> cluster_result2(iris, colnames(a)[1])
# A tibble: 2 x 3
  result_2_cl  size mean_spl
        <int> <int>    <dbl>
1           1   100     6.26
2           2    50     5.01
> cluster_result2(iris, colnames(a)[2])
# A tibble: 3 x 3
  result_3_cl  size mean_spl
        <int> <int>    <dbl>
1           1    21     4.75
2           2    33     5.17
3           3    96     6.31

  > cluster_result2(iris, colnames(a)[3])
# A tibble: 4 x 3
  result_4_cl  size mean_spl
        <int> <int>    <dbl>
1           1    29     7.00
2           2    50     6.14
3           3    49     5.02
4           4    22     5.50

> cluster_result2(iris, colnames(a)[4])
# A tibble: 5 x 3
  result_5_cl  size mean_spl
        <int> <int>    <dbl>
1           1    47     6.78
2           2    17     4.69
3           3    26     5.07
4           4    53     5.80
5           5     7     5.53

Appreciate your answers!

Upvotes: 2

Views: 389

Answers (1)

akrun
akrun

Reputation: 887951

We can use group_by_at instead of group_by_ (it is deprecated). Here, we need to loop through the column names of 'a' instead of the columns of 'iris'

library(tidyverse)
map(colnames(a), ~ cluster_result2(iris, .x))

Or without using the ~, specify the 'x' parameter as 'iris'

map(colnames(a), cluster_result2, x = iris)
#[[1]]
# A tibble: 2 x 3
#  result_2_cl  size mean_spl
#        <int> <int>    <dbl>
#1           1    50     5.01
#2           2   100     6.26

#[[2]]
# A tibble: 3 x 3
#  result_3_cl  size mean_spl
#        <int> <int>    <dbl>
#1           1    47     6.78
#2           2    53     5.80
#3           3    50     5.01

#[[3]]
# A tibble: 4 x 3
#  result_4_cl  size mean_spl
#        <int> <int>    <dbl>
#1           1    50     6.14
#2           2    22     5.50
#3           3    29     7.00
#4           4    49     5.02

#[[4]]
# A tibble: 5 x 3
#  result_5_cl  size mean_spl
#        <int> <int>    <dbl>
#1           1    16     5.32
#2           2    29     7.00
#3           3    23     5.55
#4           4    34     4.86
#5           5    48     6.16

-checking with the output of function individually applied to columns

cluster_result2(iris, colnames(a)[4])
# A tibble: 5 x 3
#  result_5_cl  size mean_spl
#        <int> <int>    <dbl>
#1           1    16     5.32
#2           2    29     7.00
#3           3    23     5.55
#4           4    34     4.86
#5           5    48     6.16

NOTE: The output will be slightly different due to the randomness

Upvotes: 1

Related Questions