#r #tidyverse #tidyr
#r #tidyverse #tidyr
Вопрос:
У меня есть фрейм данных, который включает нижнюю и верхнюю границы нескольких параметров для каждой категории фруктов. Это выглядит примерно так:
---------- ----------- ------- -------
| Category | Parameter | Upper | Lower |
---------- ----------- ------- -------
| Apple | alpha | 10 | 20 |
---------- ----------- ------- -------
| Apple | beta | 20 | 30 |
---------- ----------- ------- -------
| Orange | alpha | 10 | 20 |
---------- ----------- ------- -------
| Orange | beta | 30 | 40 |
---------- ----------- ------- -------
| Orange | gamma | 50 | 60 |
---------- ----------- ------- -------
| Pear | alpha | 10 | 30 |
---------- ----------- ------- -------
| Pear | beta | 20 | 40 |
---------- ----------- ------- -------
| Pear | gamma | 20 | 30 |
---------- ----------- ------- -------
| Banana | alpha | 40 | 50 |
---------- ----------- ------- -------
| Banana | beta | 20 | 40 |
---------- ----------- ------- -------
Я хотел бы написать функцию, которая:
- Ввод — это 1 название фрукта
function("Apple")
- Извлекает верхние и нижние значения всех параметров этого фрукта
- Введите верхнюю и нижнюю границы для альфа, бета и гамма (если применимо) выбранных фруктов в следующий процесс, чтобы создать один фрейм данных:
param_grid_[fruit_name] <- expand.grid(alpha = seq(lower, upper, length.out = 100),
beta = seq(lower, upper, length.out = 100),
gamma = seq(lower, upper, length.out = 100))
- гамма применима, только если у фрукта есть параметр gamma в исходной таблице
Например, если мой ввод в функцию — «Apple», то в итоге я должен иметь:
param_grid_Apple <- expand.grid(alpha = seq(10, 20, length.out = 100),
beta = seq(20, 30, length.out = 100))
Например, если мой ввод в функцию равен «Pear», то в итоге я должен иметь:
param_grid_Pear <- expand.grid(alpha = seq(10, 30, length.out = 100),
beta = seq(20, 40, length.out = 100),
gamma = seq(20, 30, length.out = 100))
Я попытался напрямую установить подмножество индекса row amp; col. Например, для верхней альфа-версии Apple я бы сделал df[2,3] . Но это довольно ручной и простой способ сделать это. Мне интересно, могу ли я обернуть все в функцию, чтобы упростить этот процесс.
Все еще новичок в R и пытается изучить способы оптимизации процедур путем написания функций. Большое спасибо за любую помощь!
PS (К вашему сведению — возможно, это не имеет прямого отношения к центральной проблеме этого поста) Я делаю это для того, чтобы я мог передавать param_grid в функцию nls2, чтобы соответствовать кривой для каждого фрукта:
nls2(formula = ...,
data = ...,
start = param_grid,
algorithm = "brute-force",
control = nls.control(maxiter = 1e4))
Ответ №1:
Вот еще один подход, который следует рассмотреть с purrr
помощью package .
Вы можете создать функцию и передать ей свой фрейм данных, название фрукта и желаемую длину для вашей последовательности.
Вы можете filter
использовать строки, соответствующие вашему фрукту, а затем использовать map2
для получения последовательностей для каждого параметра. cross_df
сопоставимо с expand.grid
фреймом данных и возвращает его.
library(purrr)
param_grid <- function(df, fruit, length) {
df_fruit <- df %>%
filter(Category == fruit)
map2(df_fruit$Upper, df_fruit$Lower, seq, length.out = length) %>%
set_names(df_fruit$Parameter) %>%
cross_df()
}
param_grid(df, "Apple", 100)
Вывод
# A tibble: 1,000,000 x 3
alpha beta gamma
<dbl> <dbl> <dbl>
1 10 20 20
2 10.2 20 20
3 10.4 20 20
4 10.6 20 20
5 10.8 20 20
6 11.0 20 20
7 11.2 20 20
8 11.4 20 20
9 11.6 20 20
10 11.8 20 20
# … with 999,990 more rows
Ответ №2:
Поехали! Основная часть работы выполняется с помощью assign()
которой можно создавать именованные переменные из строкового ввода для имен, eval(parse())
что позволяет нам вводить команды R в виде символьных строк (даже хранящихся в переменных!), И do.call()
которая может управлять функцией над списком аргументов, что позволяет нам программно создавать этот списоккаждый раз.
param_grid <- function(data, fruit_name) {
require(dplyr)
# Setting up the data
df <- data %>%
filter(Category == fruit_name) %>%
select(-Category)
# assigning seqences for each parameter
for(i in 1:nrow(df)) {
assign(df$Parameter[i], seq(df$Lower[i], df$Upper[i], length.out = 100))
}
#putting them in a list for do.call
list1 <-lapply(unique(df$Parameter), function(j) eval(parse(text = j)))
# setting up the data frame for expand.grid
df2 <- as.data.frame(do.call(cbind, list1))
names(df2) <- unique(df$Parameter)
df_expand <- expand.grid(df2)
return(df_expand)
}
Это работает!
param_grid_apple <- param_grid(fruit, "Apple")
head(param_grid_apple, 10)
alpha beta
1 20.00000 30
2 19.89899 30
3 19.79798 30
4 19.69697 30
5 19.59596 30
6 19.49495 30
7 19.39394 30
8 19.29293 30
9 19.19192 30
10 19.09091 30
dim(param_grid_apple)
[1] 10000 2
param_grid_pear <- param_grid(fruit, "Pear")
head(param_grid_pear, 10)
alpha beta gamma
1 30.00000 40 30
2 29.79798 40 30
3 29.59596 40 30
4 29.39394 40 30
5 29.19192 40 30
6 28.98990 40 30
7 28.78788 40 30
8 28.58586 40 30
9 28.38384 40 30
10 28.18182 40 30
dim(param_grid_pear)
[1] 10000 3