R: Как написать функцию для извлечения определенных значений из фрейма данных, чтобы передать их в другой фрейм данных

#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