【r<-效率】Rmarkdown与shiny

Rmarkdown

Rmarkdown扩展了markdown的语法,所以markdown能写的,Rmarkdown能写,后者还提供了一些新的特性,特别是图表,很nice。

markdown的语法非常非常简单,用上一天就熟悉了,还没学过的随便百度谷歌下,教程已经烂大街了,如果你实在要我推荐,就看看我之前写的【软件推荐|markdown】Typora简介及Markdown语法精讲吧。

嵌入表格和图表

这也是rmarkdown吸引人的地方,通过R代码直接输出表格和图!这有赖于益辉大神写的knitr包。

先出个表试试,写个数据框:

toys = data.frame(
    id = 1:3,
    name = c("Car", "Plane", "Motocycle"),
    price = c(15, 25, 14),
    share = c(0.3, 0.1, 0.2),
    stringsAsFactors = FALSE
)

纯文本输出为:

toys
#>   id      name price share
#> 1  1       Car    15   0.3
#> 2  2     Plane    25   0.1
#> 3  3 Motocycle    14   0.2

使用knitr::kable()生成markdown版本的表格:

knitr::kable(toys)
id name price share
1 Car 15 0.3
2 Plane 25 0.1
3 Motocycle 14 0.2

网页显示是上面这样的,实际markdown是下面这样:

| id|name      | price| share|
|--:|:---------|-----:|-----:|
|  1|Car       |    15|   0.3|
|  2|Plane     |    25|   0.1|
|  3|Motocycle |    14|   0.2|

还有其他一些扩展包可以渲染表格,例如xtable包可以将data.frame转换为LaTeX,还提供了呈现统计模型的模板:

xtable::xtable(lm(mpg ~ cyl + vs, data = mtcars))
#> % latex table generated in R 3.5.1 by xtable 1.8-2 package
#> % Fri Aug 31 18:39:26 2018
#> \begin{table}[ht]
#> \centering
#> \begin{tabular}{rrrrr}
#>   \hline
#>  & Estimate & Std. Error & t value & Pr($>$$|$t$|$) \\ 
#>   \hline
#> (Intercept) & 39.6250 & 4.2246 & 9.38 & 0.0000 \\ 
#>   cyl & -3.0907 & 0.5581 & -5.54 & 0.0000 \\ 
#>   vs & -0.9391 & 1.9775 & -0.47 & 0.6384 \\ 
#>    \hline
#> \end{tabular}
#> \end{table}

Excel是著名的分析软件,其中一个特性是条件化格式操作,任坤大神开发了formattable包来实现这样的特性,它能够使数据框中的单元格显示更多的比较信息:

install.packages("formattable")

下面使用看看:

library(formattable)
formattable(toys,
            list(price = color_bar("lightpink"), share = percent))
id name price share
1 Car 15 30.00%
2 Plane 25 10.00%
3 Motocycle 14 20.00%

将巨大的表格直接嵌入文档并不是个好主意,JavaScript库(例如DataTables)可以很方便将大数据集嵌入网页中,它可以自动执行分页,也支持搜索与筛选。名为DT的R包可以利用这个库,实现交互式操作,方便探索大数据集。

library(DT)
datatable(mtcars)
mpg cyl disp hp drat wt qsec vs am gear carb

R社区还有其他高质量的javascript库值得大家探索。

下面说说如何嵌入图。

一般的图非常简单,和平常写R代码一样,不过不在.R中写,而是在.Rmd中写,将你的代码写入如下的代码框中,使用Control+Alt+i可以直接插入一个代码框。就是说重点是代码,图R会帮我们自动生成,比如下面这个图:

set.seed(123)
x = rnorm(1000)
y = 2 * x + rnorm(1000)
m = lm(y ~ x)
plot(x, y, main = "Linear regression", col = "darkgray")
abline(coef(m))

img

除了基本的绘图函数与ggplot2包,我们还可以使用其他,例如DiagrammeR包绘制流程图等。

下面生成一个有向图:

library(DiagrammeR)
grViz("
      digraph rmarkdown {
      A -> B
      B -> C
      C -> A
      }")

这个包使用Graphviz描述图的结构和样式。有这种需求就去看文档。

嵌入交互图

前面演示的都是静态的,现在咱们来玩动态的。

ggvis是RStudio开发的一个交互图扩展包,她利用Vega作为后端支持。

library(ggvis)
mtcars %>% 
    ggvis(~mpg, ~disp, opacity := 0.6) %>% 
    layer_points(size := input_slider(1, 100, value = 50, label = "size")) %>% 
    layer_smooths(span = input_slider(0.5, 1, value = 1, label = "span"))
#> Warning: Can't output dynamic/interactive ggvis plots in a knitr document.
#> Generating a static (non-dynamic, non-interactive) version of the plot.

10121416182022242628303234mpg100150200250300350400450disp

img

这个包的语法有点像ggplot2,最好配合管道符号使用。

还有一个扩展包dygraphs专门用于绘制交互功能的时间序列数据。

创建Shiny交互式应用程序

shiny由RStudio开发,不同于前面的动图,它可以在web浏览器中运行。

一个shiny应用程序基本由两个重要部分组成:一个是Web浏览器交互的HTTP服务器,另一个是HTTP服务器交互的R会话

下面我们写一个最小的shiny应用程序,写一个R脚本定义它的用户界面和服务器逻辑,用户界面是一个boostrapPage,它包含一个numericInput用于接收一个整数表示样本容量,一个textOutput用于返回随机样本的均值。服务器背后的逻辑是根据输入input的样本容量n生成随机数,计算随机样本的均值,并将结果放在output中。

library(shiny)

ui = bootstrapPage(
    numericInput("n", label = "Sample size", value = 10, min = 10, max = 100),
    textOutput("mean")
)

server = function(input, output){
    output$mean = renderText(mean(rnorm(input$n)))
}

app = shinyApp(ui, server)
runApp(app)

img

尽管这个例子很简单,但它演示了shiny应用程序的基本组件。

下面我们看一个复杂有用的例子:可视化几何布朗运动的许多路径,几何布朗运动常用于股票价格建模,运动的结果取决于初始值、预期增长率、波动率、持续时间和周期数。除了设定T=1外,我们允许用户修改其他所有参数。

我们可以根据想展示给用户的参数来定义shiny应用程序的用户界面,shiny提供了丰富的输入控件:

shiny_vars = ls(getNamespace("shiny"))
shiny_vars[grep("Input$", shiny_vars)]
#>  [1] "checkboxGroupInput"            "checkboxInput"                
#>  [3] "dateInput"                     "dateRangeInput"               
#>  [5] "fileInput"                     "numericInput"                 
#>  [7] "passwordInput"                 "restoreInput"                 
#>  [9] "selectInput"                   "selectizeInput"               
#> [11] "serializerFileInput"           "sliderInput"                  
#> [13] "snapshotPreprocessInput"       "snapshotPreprocessorFileInput"
#> [15] "textAreaInput"                 "textInput"                    
#> [17] "updateCheckboxGroupInput"      "updateCheckboxInput"          
#> [19] "updateDateInput"               "updateDateRangeInput"         
#> [21] "updateNumericInput"            "updateSelectInput"            
#> [23] "updateSelectizeInput"          "updateSliderInput"            
#> [25] "updateTextAreaInput"           "updateTextInput"

另外我们允许用户指定随机种子数来确保相同的种子生成相同的路径。

下面是shiny提供的输出控件:

shiny_vars[grep("Output$", shiny_vars)]
#>  [1] "cancelOutput"             "dataTableOutput"         
#>  [3] "htmlOutput"               "imageOutput"             
#>  [5] "missingOutput"            "plotOutput"              
#>  [7] "snapshotPreprocessOutput" "tableOutput"             
#>  [9] "textOutput"               "uiOutput"                
#> [11] "verbatimTextOutput"

下面写代码:

library(shiny)

ui = fluidPage(
    titlePanel("Random walk"),
    sidebarLayout(
        sidebarPanel(
            numericInput("seed", "Random seed", 123),
            sliderInput("paths", "Paths", 1, 100, 1),
            sliderInput("start", "Starting value", 1, 10, 1, 1),
            sliderInput("r", "Expected return", -0.1, 0.1, 0, 0.001),
            sliderInput("sigma", "Sigma", 0.001, 1, 0.01, 0.001),
            sliderInput("periods", "Periods", 10, 1000, 200, 10)
        ),
        mainPanel(
            plotOutput("plot", width = "100%", height = "600px")
        )
    )
)

接下来我们实现服务器逻辑,首先设置随机数,然后迭代调用sde::GBM,这个包要先安装。

GMB生成一条路径,sapply()将所有生成的路径组合成一个矩阵,矩阵的每一列代表一条路径,然后使用matplot()画图。

无论是文本,图形还是表格,计算都是在render*函数中完成,目前有下面一些:

shiny_vars[grep("^render", shiny_vars)]
#> [1] "renderDataTable" "renderImage"     "renderPage"      "renderPlot"     
#> [5] "renderPrint"     "renderReactLog"  "renderTable"     "renderText"     
#> [9] "renderUI"

这个例子我们只需要调用renderPlot()

server = function(input, output){
    output$plot = renderPlot({
        set.seed(input$seed)
        mat = sapply(seq_len(input$paths), function(i){
            sde::GBM(input$start,
                     input$r,
                     input$sigma,
                     1,
                     input$periods)
        })
        
        matplot(mat, type = "l", lty = 1, main = "Geometric Brownian motions")
    })
}

然后创建并运行shiny

app = shinyApp(ui, server)
runApp(app)

img

文章作者 王诗翔

上次更新 2018-08-31

许可协议 CC BY-NC-ND 4.0

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 161,601评论 4 369
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 68,367评论 1 305
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 111,249评论 0 254
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,539评论 0 217
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,967评论 3 295
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,929评论 1 224
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,098评论 2 317
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,825评论 0 207
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,609评论 1 249
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,796评论 2 253
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,282评论 1 265
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,603评论 3 261
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,277评论 3 242
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,159评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,959评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 36,079评论 2 285
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,874评论 2 277

推荐阅读更多精彩内容

  • 在学习R的时候,R的包众多,很多时候对于初学者会造成很大的困扰就是不知道用什么样的包比较合适。我会在不断使用...
    果果哥哥BBQ阅读 15,864评论 0 62
  • 工欲善其事,必先利其器。总结一下,方便多了。R语言还是很牛逼的,可以干很多事情。有一把顺手的刀还是很重要的。 0....
    Liam_ml阅读 4,516评论 1 59
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 170,594评论 25 707
  • 1.数据导入 以下R包主要用于数据导入和保存数据: feather:一种快速,轻量级的文件格式;在R和python...
    雨一流阅读 1,261评论 0 9
  • 今天进入周末了,我家捣蛋鬼在家,感觉啥都没干一天就过了,给他弄三顿饭都弄的我好心累,再加上他今天感冒发烧了,一天都...
    田妞GO阅读 177评论 0 0