Использование Knitr для создания сложных динамических документов

Приведенный ниже минимальный воспроизводимый пример (RE) является моей попыткой выяснить, как я могу использовать knitr для создания сложных динамических документов, где "сложный" здесь относится не к элементам документа. и их расположение, а с нелинейной логикой базовых фрагментов кода R. Хотя предоставленный RE и его результаты показывают, что решение, основанное на таком подходе, может работать хорошо, я хотел бы знать: 1) является ли это правильным< /em> подход к использованию knitr для таких ситуаций; 2) есть ли какие-либо оптимизации, которые можно внести для улучшения подхода; 3) каковы альтернативные подходы, которые могут снизить детализацию фрагментов кода.

Исходный код EDA (файл "reEDA.R"):

## @knitr CleanEnv
rm(list = ls(all.names = TRUE))

## @knitr LoadPackages
library(psych)
library(ggplot2)

## @knitr PrepareData

set.seed(100) # for reproducibility
data(diamonds, package='ggplot2')  # use built-in data


## @knitr PerformEDA

generatePlot <- function (df, colName) {

  df <- df
  df$var <- df[[colName]]

  g <- ggplot(data.frame(df)) +
    scale_fill_continuous("Density", low="#56B1F7", high="#132B43") +
    scale_x_log10("Diamond Price [log10]") +
    scale_y_continuous("Density") +
    geom_histogram(aes(x = var, y = ..density..,
                       fill = ..density..),
                   binwidth = 0.01)
  return (g)
}

performEDA <- function (data) {

  d_var <- paste0("d_", deparse(substitute(data)))
  assign(d_var, describe(data), envir = .GlobalEnv)

  for (colName in names(data)) {
    if (is.numeric(data[[colName]]) || is.factor(data[[colName]])) {
      t_var <- paste0("t_", colName)
      assign(t_var, summary(data[[colName]]), envir = .GlobalEnv)

      g_var <- paste0("g_", colName)
      assign(g_var, generatePlot(data, colName), envir = .GlobalEnv)
    }
  }
}

performEDA(diamonds)

Документ R Markdown отчета EDA (файл "reEDA.Rmd"):

```{r KnitrSetup, echo=FALSE, include=FALSE}
library(knitr)
opts_knit$set(progress = TRUE, verbose = TRUE)
opts_chunk$set(
  echo = FALSE,
  include = FALSE,
  tidy = FALSE,
  warning = FALSE,
  comment=NA
)
```

```{r ReadChunksEDA, cache=FALSE}
read_chunk('reEDA.R')
```

```{r CleanEnv}
```

```{r LoadPackages}
```

```{r PrepareData}
```

Narrative: Data description

```{r PerformEDA}
```

Narrative: Intro to EDA results

Let's look at summary descriptive statistics for our dataset

```{r DescriptiveDataset, include=TRUE}
print(d_diamonds)
```

Now, let's examine each variable of interest individually.

Varible Price is ... Decriptive statistics for 'Price':

```{r DescriptivePrice, include=TRUE}
print(t_price)
```

Finally, let's examine price distribution across the dataset visually:

```{r VisualPrice, include=TRUE, fig.align='center'}
print(g_price)
```

Результат можно найти здесь:

http://rpubs.com/abrpubs/eda1


person Aleksandr Blekh    schedule 07.09.2014    source источник
comment
Это действительно интересный вопрос, но я боюсь, что он плохо подходит для stackoverflow в его нынешнем виде. Stackoverflow работает гораздо лучше для вопросов и ответов, чем для обсуждения. Итак, если вы можете сформулировать это больше как вопрос, который включает воспроизводимые данные и имеет четкую проблему, я думаю, что это было бы отлично.   -  person Andy Clifton    schedule 08.09.2014
comment
Согласен с Энди. А тем временем вы заглянули в brew? У меня не было возможности попробовать это, но я слышал, что он может выполнять циклы и более программные конструкции при создании документа.   -  person Aaron left Stack Overflow    schedule 08.09.2014
comment
@AndyClifton: Спасибо за ваш отзыв! Я понимаю вашу точку зрения, но я все еще время от времени вижу ответы на подобные вопросы здесь, на SO. Тем не менее, я посмотрю, смогу ли я придумать минимальный воспроизводимый пример для этого типа вопроса.   -  person Aleksandr Blekh    schedule 08.09.2014
comment
@Aaron: Спасибо за ваш отзыв и предложение! Я слышал о brew, когда мне его рекомендовали для другой задачи. Я посмотрел очень кратко. Я смог решить эту проблему, используя менее сложный подход. Я считаю, что knitr является достаточно гибким и мощным (и сложным), чтобы добавить дополнительный уровень сложности в мое решение, добавив механизм шаблонов, такой как brew. Его документация очень ограничена, плюс я считаю, что большую часть того, что может сделать brew, можно сделать с помощью хуков knitr. Кроме того, я не понимаю, как это решает проблему нелинейной логики в коде.   -  person Aleksandr Blekh    schedule 08.09.2014
comment
@Aaron: Несмотря на плохую документацию для brew, я только что нашел этот хороший пост в блоге с полным примером: learnr.wordpress.com/2009/09/09/. Теперь мне все ясно. Похоже, что brew стоит еще раз взглянуть (если только @Yihui не покажет, как делать то, что я хочу, используя только функциональность knitr).   -  person Aleksandr Blekh    schedule 08.09.2014
comment
Пожалуйста, не закрывайте этот вопрос - я подготовил минимальный воспроизводимый пример. Размещение в течении 5-10 минут.   -  person Aleksandr Blekh    schedule 08.09.2014
comment
Можно ли опубликовать минимальный воспроизводимый пример (RE) как часть моего ответа? Это работает хорошо, но я все же хотел бы, чтобы люди прокомментировали это, чтобы увидеть, можно ли сделать некоторые оптимизации. Кроме того, я хотел бы увидеть другие подходы, основанные на моем RE, для уменьшения детализации фрагментов кода.   -  person Aleksandr Blekh    schedule 08.09.2014
comment
Re: Держи. Я предоставил минимальный RE и сузил объем своего вопроса (все в моем ответе ниже). Вы все еще думаете, что этого недостаточно, или вы не против, если я заменю исходный вопрос содержанием моего текущего ответа? Пожалуйста, дай мне знать.   -  person Aleksandr Blekh    schedule 08.09.2014
comment
Александр, ваш вопрос слишком широк. Добавление примера в ответ не очень помогает. Этот пример должен быть в вопросе.   -  person Andy Clifton    schedule 08.09.2014
comment
@AndyClifton: Хорошо. Затем я заменю исходный широкий вопрос более сфокусированным вопросом с воспроизводимым примером, опубликованным в моем ответе.   -  person Aleksandr Blekh    schedule 08.09.2014
comment
[Сохранил этот комментарий из удаленного ответа.] Только что нашел этот связанный вопрос: stackoverflow.com/q/21729415/2872891. В ответе предлагается использовать Knitr_expand(), о котором я до сих пор не знал. Это хорошо, однако я не уверен, что этот подход лучше, чем мой упрощенный, упомянутый выше (даже если он используется в сочетании с read_chunk()).   -  person Aleksandr Blekh    schedule 08.09.2014
comment
@AndyClifton: вопрос переработан (перемещен и переформулирован для большего внимания). Ответ удален.   -  person Aleksandr Blekh    schedule 08.09.2014


Ответы (1)


Я не понимаю, что нелинейного в этом коде; возможно, потому что пример (кстати, спасибо за это) достаточно мал, чтобы продемонстрировать код, но недостаточно велик, чтобы продемонстрировать проблему.

В частности, я не понимаю причину функции performEDA. Почему бы не поместить эту функциональность в уценку? Казалось бы, проще и понятнее читать. (Это не проверено...)

Let's look at summary descriptive statistics for our dataset

```{r DescriptiveDataset, include=TRUE}
print(describe(diamonds))
```

Now, let's examine each variable of interest individually.

Varible Price is ... Decriptive statistics for 'Price':

```{r DescriptivePrice, include=TRUE}
print(summary(data[["Price"]]))
```

Finally, let's examine price distribution across the dataset visually:

```{r VisualPrice, include=TRUE, fig.align='center'}
print(generatePlot(data, "Price"))
```

Похоже, вы собирались показать графики для всех переменных; Вы, возможно, хотите зациклиться там?

Кроме того, это не изменит функциональность, но в идиоме R было бы намного лучше, если бы performEDA возвращал список с созданными им вещами, а не назначал их в глобальную среду. Мне потребовалось некоторое время, чтобы понять, что делает код, поскольку эти новые переменные нигде не были определены.

person Aaron left Stack Overflow    schedule 08.09.2014
comment
Аарон, я ценю ваше время и обратную связь. Вы правы (и я сказал это в своем первоначальном вопросе), что я сильно упростил свой код EDA для создания этого минимального RE, может быть, даже слишком. Я пытался добиться минимального количества кода для этого, пытаясь имитировать реальный код. Именно для этого и существует функция PerformEDA() в моем RE. Если вам интересно взглянуть на мой реальный код для модуля EDA (github.com/abnova/diss-floss/blob/master/analysis/eda.R), вы поймете и увидите всевозможные функции, циклы и возврат различных списков. (продолжение следует) - person Aleksandr Blekh; 09.09.2014
comment
(продолжение) Сказав это, я сейчас переосмысливаю ценность и осуществимость моего первоначального подхода, особенно недавно обнаружив пакеты gpairs и особенно GGally (поскольку я использую ggplot2 вместо стандартной R-графики). Мне нужно еще раз взглянуть на GGally, чтобы увидеть, достаточно ли легко настроить его для желаемого вывода EDA. - person Aleksandr Blekh; 09.09.2014