如何使用purrr:map函数使用动态变量更改多列?

时间:2019-07-24 12:31:11

标签: r dictionary dplyr purrr

我的数据框如下:

df <- data.frame(
  id  = c(1:5),
  a   = c(3,10,4,0,15),
  b   = c(2,1,1,0,3),
  c   = c(12,3,0,3,1),
  d   = c(9,7,8,0,0),
  e   = c(1,2,0,2,2)
  )

我需要添加多列,其名称由a:c3:5组合给出。 3:5也用在sum函数中:

df %>% mutate(
  usa_3 = sum(1+3),
  usa_4 = sum(1+4),
  usa_5 = sum(1+5),
  canada_3 = sum(1+3),
  canada_4 = sum(1+4),
  canada_5 = sum(1+5),
  nz_3 = sum(1+3),
  nz_4 = sum(1+4),
  nz_5 = sum(1+5)
  )

结果真的很简单,但是我不想重复输入类似的代码。

  id  a b  c d e usa_3 usa_4 usa_5 canada_3 canada_4 canada_5 nz_3 nz_4 nz_5
1  1  3 2 12 9 1     4     5     6        4        5        6    4    5    6
2  2 10 1  3 7 2     4     5     6        4        5        6    4    5    6
3  3  4 1  0 8 0     4     5     6        4        5        6    4    5    6
4  4  0 0  3 0 2     4     5     6        4        5        6    4    5    6
5  5 15 3  1 0 2     4     5     6        4        5        6    4    5    6

变量是字母前缀,整数范围作为后缀。 Postfix也与sum功能相关,称为1+postfix。 在这种情况下,它们每个都有3个值,因此结果还有9列。

我不喜欢在大量代码之外定义函数,并且假设map中的purrr functino可能会有所帮助。

您知道如何使其工作吗? 特别是很难在管道中提供动态列名称。

我发现了一些类似的问题,但与我的需求不符。

Multivariate mutate
How to use map from purrr with dplyr::mutate to create multiple new columns based on column pairs

=====其他信息=====
让我澄清一下此问题的一些条件。 实际上,sum(1+3)sum(1+4) ...部分已由as.factor(cutree(X,k=X))代替,其中X是聚类分析的重用,而Y是定义为{{1}的变量在示例中。 3:5是一个函数,用于定义我们将存储在聚类分析结果中的树状图切成哪一部分。

对于列名cutree(),国家名称由聚类分析方法代替,例如病房,McQuitty,中位数方法等(七个方法),并且整数3、4、5是参数定义我需要按照说明切割树状图的部分。

对于功能usa_3, usa_4 ... nz_5中的X,聚类分析的结果也具有对应于每种方法的几个数据框。我意识到另一个问题是如何将功能应用于每个数据框(聚类分析结果存储在不同的数据框中)。
我当前正在使用的实际脚本是这样的:

as.factor(cutree(X,k=X))

很遗憾,没有澄清实际问题;但是,由于上述原因,国家/地区的数量为cluste_number <- original_df %>% mutate( ## Ward ward_3=as.factor(cutree(clst.ward,k=3)), ward_4=as.factor(cutree(clst.ward,k=4)), ward_5=as.factor(cutree(clst.ward,k=5)), ward_6=as.factor(cutree(clst.ward,k=6)), ## Single sing_3=as.factor(cutree(clst.sing,k=3)), sing_4=as.factor(cutree(clst.sing,k=4)), sing_5=as.factor(cutree(clst.sing,k=5)), sing_6=as.factor(cutree(clst.sing,k=6))) 和参数数量为usa, canada, nz不匹配。 另外,由于在实际操作中使用了1:3函数,因此使用i + .的一些建议无法解决问题。

感谢您的支持。

4 个答案:

答案 0 :(得分:2)

我不确定是否理解问题的实质,但这是一种使用所需列名和值生成数据框的方法。

您可以将~ function(i) i + .更改为所需的i(正在突变的列)的任何功能,并更改n中的setNames(n, n)中的任何一个以合并您正在创建的函数中使用不同的值(第一个n)或更改结果列的名称(第二个n)。

countries <- c('usa', 'canada', 'nz')
n <- 3:5

as.data.frame(matrix(1, nrow(df), length(n))) %>% 
  rename_all(~countries) %>%
  mutate_all(map(setNames(n, n), ~ function(i) i + .)) %>% 
  select(-countries) %>% 
  bind_cols(df)

#   usa_3 canada_3 nz_3 usa_4 canada_4 nz_4 usa_5 canada_5 nz_5 id  a b  c d e
# 1     4        4    4     5        5    5     6        6    6  1  3 2 12 9 1
# 2     4        4    4     5        5    5     6        6    6  2 10 1  3 7 2
# 3     4        4    4     5        5    5     6        6    6  3  4 1  0 8 0
# 4     4        4    4     5        5    5     6        6    6  4  0 0  3 0 2
# 5     4        4    4     5        5    5     6        6    6  5 15 3  1 0 2

答案 1 :(得分:1)

不确定您要做什么,但这也许有助于弄清问题..

library(tidyverse)

df <- data.frame(
  id  = c(1:5),
  a   = c(3,10,4,0,15),
  b   = c(2,1,1,0,3),
  c   = c(12,3,0,3,1),
  d   = c(9,7,8,0,0),
  e   = c(1,2,0,2,2)
)

ctry <- rep(c("usa", "ca", "nz"), each = 3)
nr <- rep(seq(3,5), times = 3)
df %>%
  as_tibble() %>%
  bind_cols(map_dfc(seq_along(ctry), ~1+nr[.x] %>%
                      rep(nrow(df))) %>%
              set_names(str_c(ctry, nr, sep = "_")))

# A tibble: 5 x 15
     id     a     b     c     d     e usa_3 usa_4 usa_5  ca_3  ca_4  ca_5  nz_3  nz_4  nz_5
  <int> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1     1     3     2    12     9     1     4     5     6     4     5     6     4     5     6
2     2    10     1     3     7     2     4     5     6     4     5     6     4     5     6
3     3     4     1     0     8     0     4     5     6     4     5     6     4     5     6
4     4     0     0     3     0     2     4     5     6     4     5     6     4     5     6
5     5    15     3     1     0     2     4     5     6     4     5     6     4     5     6

答案 2 :(得分:1)

一个肮脏的解决方案的金达,但它可以满足您的要求。它结合了两个public class RouteConfig { public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); routes.Add(new Route("Home/qwe", new routeHandel())); routes.MapRoute( name: "Default", url: "{controller}/{action}/{id}", defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } ); } } 函数。

map_dfc

答案 3 :(得分:1)

这是基本的R解决方案。您可以根据需要重新排列列,但这应该可以开始:

# Create column names using an index and country names
idx <- 3:5
countries <- c("usa", "canada", "nz")
new_columns <- unlist(lapply(countries, paste0, "_", idx))

# Adding new values using index & taking advantage of recycling
df[new_columns] <- sort(rep(1+idx, nrow(df)))
df
  id  a b  c d e usa_3 usa_4 usa_5 canada_3 canada_4 canada_5 nz_3 nz_4 nz_5
1  1  3 2 12 9 1     4     5     6        4        5        6    4    5    6
2  2 10 1  3 7 2     4     5     6        4        5        6    4    5    6
3  3  4 1  0 8 0     4     5     6        4        5        6    4    5    6
4  4  0 0  3 0 2     4     5     6        4        5        6    4    5    6
5  5 15 3  1 0 2     4     5     6        4        5        6    4    5    6

或者,如果您愿意:

# All in one long line
df[unlist(lapply(countries, paste0, "_", idx))] <- sort(rep(1+idx, nrow(df)))