使用purrr和预定义函数添加多个输出变量

时间:2018-08-23 04:00:58

标签: r function purrr

采用以下简单的数据集和功能(代表更复杂的问题):

orders

使用基数R的x <- data.frame(a = 1:3, b = 2:4) mult <- function(a,b,n) (a + b) * n 可以以矢量化的方式添加2个新列:

Map
通过ns <- 1:2 x[paste0("new",seq_along(ns))] <- Map(mult, x["a"], x["b"], n=ns) x # a b new1 new2 #1 1 2 3 6 #2 2 3 5 10 #3 3 4 7 14

purrr尝试通过列表输出结束:

pmap

我在这里尝试使用library(purrr) library(dplyr) x %>% select(a,b) %>% pmap(mult, n=1:2) #[[1]] #[1] 3 6 # #[[2]] #[1] 5 10 # #[[3]] #[1] 7 14 等尝试将其映射回新列时似乎都出错了。

如何最终再创建2个与当前pmap_dfr相匹配的变量?我确定这里有一个简单的咒语,但是我显然忽略了它或使用了错误的"new1"/"new2"函数。

这里有一些有用的讨论-How to use map from purrr with dplyr::mutate to create multiple new columns based on column pairs-但对于我想像的一个简单问题来说,似乎太过分了,而且不够灵活。

3 个答案:

答案 0 :(得分:3)

这里是一种可能性。

% 12

不漂亮,所以我也很想知道替代方法。 library(purrr) library(dplyr) n <- 1:2 x %>% mutate(val = pmap(., mult, n = n)) %>% unnest() %>% mutate(var = rep(paste0("new", n), nrow(.) / length(n))) %>% spread(var, val) # a b new1 new2 #1 1 2 3 6 #2 2 3 5 10 #3 3 4 7 14 unnest列和list插入新列会产生很多多余的结果。

这是使用spread加上丑陋的pmap_dfc通话的另一种可能性

as.data.frame(t(...))

样本数据

bind_cols(x, as.data.frame(t(pmap_dfc(x, mult, n = n))))
#  a b V1 V2
#1 1 2  3  6
#2 2 3  5 10
#3 3 4  7 14

答案 1 :(得分:3)

我发现最好的方法(仍然不是很优雅)是插入@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ButterKnife.bind(this); ((MyApplication) getApplication()).getComponent().inject(this); movieListViewModel = ViewModelProviders.of(this).get(MovieListViewModel.class); recyclerView.setHasFixedSize(true); gridLayoutManager = new GridLayoutManager(this, 2); recyclerView.setLayoutManager(gridLayoutManager); adapter = new MovieListAdapter(MainActivity.this); recyclerView.setAdapter(adapter); movieListViewModel.getMovieList(); observePopularMovieList(); } private void observePopularMovieList() { movieListViewModel.result.observe(this, new Observer<NetworkResponse>() { @Override public void onChanged(@Nullable NetworkResponse networkResponse) { if (networkResponse.getPostData() != null) { movieData = networkResponse.getPostData(); adapter.addData(movieData.getResults()); Handler handler = new Handler(); handler.postDelayed(new Runnable() { @Override public void run() { restoreState(); } },50); } else { Log.e(TAG, "failure"); } } }); } 。为了使bind_cols正常工作,该函数应返回一个命名列表(它可以是数据框,也可以不是数据框):

pmap_dfr

为避免更改library(tidyverse) x <- data.frame(a = 1:3, b = 2:4) mult <- function(a,b,n) as.list(set_names((a + b) * n, paste0('new', n))) x %>% bind_cols(pmap_dfr(., mult, n = 1:2)) #> a b new1 new2 #> 1 1 2 3 6 #> 2 2 3 5 10 #> 3 3 4 7 14 的定义,可以将其包装在匿名函数中:

mult

在这种特殊情况下,实际上并不需要遍历行,因为可以对mult <- function(a,b,n) (a + b) * n x %>% bind_cols(pmap_dfr( ., ~as.list(set_names( mult(...), paste0('new', 1:2) )), n = 1:2 )) #> a b new1 new2 #> 1 1 2 3 6 #> 2 2 3 5 10 #> 3 3 4 7 14 的输入进行矢量化,而对x进行遍历。优点是通常 n> p ,因此迭代次数将[可能大大减少]。显然,这种方法是否可行取决于函数可以接受矢量参数的参数。

仍然需要在n的变量上调用

mult。最简单的方法是显式地传递它们:

x

...但是这失去了x %>% bind_cols(map_dfc(1:2, ~mult(x$a, x$b, .x))) #> a b V1 V2 #> 1 1 2 3 6 #> 2 2 3 5 10 #> 3 3 4 7 14 的好处,即命名变量将自动传递给正确的参数。您可以使用pmap来找回它,这是一个副词,它会更改函数的域,因此它通过将列表包装在purrr::lift中来接受列表。可以在do.call上调用返回的函数,并为该迭代调用x的值:

n

这等效于

x %>% bind_cols(map_dfc(1:2, ~lift(mult)(x, n = .x)))

但是前者的优点是它返回可以x %>% bind_cols(map_dfc(1:2, ~invoke(mult, x, n = .x))) 应用于partial的函数,因此只剩下一个x参数,因此不需要显式引用到n,因此管道效果更好:

x

所有人都返回同一件事。如果需要,可以使用x %>% bind_cols(map_dfc(1:2, partial(lift(mult), .))) 固定名称。

答案 2 :(得分:1)

要模仿C:\python_try\python_proj\proj_1>tst Traceback (most recent call last): File "C:\Anaconda3\lib\site-packages\setuptools-27.2.0- py3.6.egg\pkg_resources \__init__.py", line 2266, in resolve AttributeError: module 'test' has no attribute 'main' During handling of the above exception, another exception occurred: Traceback (most recent call last): File "C:\Anaconda3\Scripts\tst-script.py", line 11, in <module> load_entry_point('PROJ-1', 'console_scripts', 'tst')() File "C:\Anaconda3\lib\site-packages\setuptools-27.2.0- py3.6.egg\pkg_resources \__init__.py", line 565, in load_entry_point File "C:\Anaconda3\lib\site-packages\setuptools-27.2.0- py3.6.egg\pkg_resources \__init__.py", line 2598, in load_entry_point File "C:\Anaconda3\lib\site-packages\setuptools-27.2.0- py3.6.egg\pkg_resources \__init__.py", line 2258, in load File "C:\Anaconda3\lib\site-packages\setuptools-27.2.0- py3.6.egg\pkg_resources \__init__.py", line 2268, in resolve ImportError: module 'test' has no attribute 'main' 的输入格式,我们可以通过以下方式从Map调用pmap

purrr

要使其适合管道:

x[paste0("new",seq_along(ns))] <- pmap(list(x['a'], x['b'], ns), mult)

显然,与简明的基础R代码相比,这看起来很丑。但是我想不出更好的方法。