【R】Advanced R —— 1 Introduction

1 Introduction

我现在已经在R编程领域工作了15年以上,过去5年一直全职从事这项工作。这使我有了足够的时间来深入研究这门语言的工作原理。我努力尝试将我所学传授给你,以便你能够尽快、尽量不费力地理解R的复杂性。阅读它将帮助你避免我曾经犯过的错误和我曾经走过的死胡同,它将教会你有用的工具、技巧和习惯用法,可以帮助你解决许多类型的问题。在这个过程中,我希望能够展示,尽管它有时会有令人沮丧的怪癖,但R在本质上是一门优雅而美丽的语言,非常适合数据科学领域。

1.1 为什么用 R?

如果你是R的新手,你可能会想知道是什么让这门独特的语言如此值得学习。对我来说,一些最好的特点包括:

  • 免费、开源且适用于所有主要平台。因此,如果你在R中进行分析,无论他们住在哪里或赚多少钱,任何人都可以轻松复制它。

  • R拥有一个多样且友好的社区,包括线上(例如#rstats Twitter社区),也包括在现实中(像许多R聚会)。两个特别令人鼓舞的社区是rweekly新闻通讯,它使您能够轻松跟上R的最新信息,以及R-Ladies,为女性和其他少数性别创造了一个非常友好的社区。

  • 强大的统计建模、机器学习、可视化以及导入和操作数据的包。无论你要尝试做什么样的模型或图形,都很有可能已经有人尝试过,你可以从他们的努力中学到东西。

  • 用于交流结果的强大工具。RMarkdown 使您可以轻松将结果转化为 HTML文件、PDF、Word文档、PowerPoint演示文稿、仪表板等。Shiny 允许您在不了解 HTML 或 JavaScript 的情况下创建漂亮的交互式应用程序。

  • RStudio,这个集成开发环境(IDE)专为数据科学、交互式数据分析和统计编程需求而设计。

  • 前沿工具。统计和机器学习领域的研究人员通常会发布一个 R 包来配合他们的文章。这意味着您可以立即访问最新的统计技术和实现。

  • 深入的数据分析语言支持,包括缺失值、数据框架和向量化等特性。

  • 坚实的函数式编程基础。函数式编程的思想非常适合数据科学的挑战,而R语言本质上是一种函数式语言,提供了许多有效的函数式编程原语。

  • RStudio 这家公司,通过向 R 用户团队销售专业产品而赚钱,然后将其中大部分资金重新投入到开源社区(RStudio 的软件工程师中有50%以上在开源项目上工作)。我为 RStudio 工作,因为我相信它的使命。

  • 强大的元编程工具。R的元编程能力使您可以编写神奇而简洁的函数,并为设计特定领域语言(如 ggplot2、dplyr、data.table等)提供了良好的环境。

  • R可以轻松连接高性能编程语言,如C、Fortran和C++。

当然,R也不是完美的。R最大的挑战(同时也是机遇!)就是,大多数 R 用户不是程序员。这意味着:

  • 许多在实际应用中看到的R代码都是匆忙编写用来解决紧急问题的。因此,代码不够优雅、快速或易于理解。大多数用户不会修改他们的代码来解决这些问题。

  • 与其他编程语言相比,R社区更注重结果而不是过程。对软件工程最佳实践的了解程度参差不齐。例如,很少有 R 程序员使用源代码控制或自动化测试。

  • 元编程是一把双刃剑。太多的 R 函数的使用技巧减少了代码量,但代价是使代码难以理解,并可能以意想不到的方式失败。

  • 不一致性在第三方包中普遍存在,甚至在基础 R 内部也有。每次使用 R 时,您都会面临超过25年的发展历程,这可能会使学习 R 变得困难,因为有太多需要记住的特殊情况。

  • R 不是特别快速的编程语言,编写不良的 R 代码可能会导致程序非常慢。R 还会浪费大量内存。

就个人而言,我认为这些挑战为有经验的程序员在 R 和 R 社区上产生深远积极的影响创造了巨大机会。R 用户确实关心编写高质量的代码,特别是对于可重复研究,但他们还没有掌握这样做的技能。我希望这本书不仅能帮助更多的 R 用户成为 R 程序员,还能鼓励来自其他编程语言的程序员为R做出贡献。

1.2 谁应该读此书

这本书针对两个互补的受众群体:

  • 中级 R 程序员,他们想深入了解 R,理解这门语言的工作原理,并学习解决各种问题的新策略。
  • 正在学习 R 并希望理解 R 为什么以其独特的方式工作的,其他编程语言的程序员。

为了充分利用这本书,你需要已经编写了相当数量的 R 代码或其他编程语言的代码。你应该熟悉基本的数据分析知识(例如数据导入、操作和可视化),已经编写过一些函数,并熟悉 CRAN 包的安装和使用。

这本书在成为参考书(主要用于查找)和线性可读性之间另辟蹊径。这涉及到一些权衡,因为在保持相关内容的同时保证内容的线性是难的,如果你已经熟悉特定的技术词汇,有些概念就会更容易解释。我尝试使用脚注和交叉引用,以确保即使你只是浏览某一章节,你仍然可以理解内容。

1.3 你将从此书中获得什么

我在本书中分享了我认为的高级 R 程序员应该掌握的知识:对基础原理的深刻理解,以及广泛的词汇量,这意味着你可以在需要时有针对性地学习更多关于某个主题的知识。

阅读完这本书后,你将会:

  • 对R的基础有所了解。你将理解复杂的数据类型以及操作它们的最佳方法。你将深刻理解函数的工作原理,了解什么是环境,以及如何使用条件系统。
  • 理解函数式编程的含义,以及为什么它是数据科学的有用工具。你将能够快速学习如何使用现有工具,并在需要时创建自己的函数式工具。
  • 了解 R 丰富多样的面向对象系统。你将熟悉S3,了解 S4 和 R6,并知道如何查找更多信息。
  • 了解元编程的利弊。具备创建使用整洁评估函数的能力,节省代码量,并创建优雅的代码来实现重要操作。同时了解其中的危险以及避免使用元编程的情况。
  • 对于 R 中哪些操作是慢的或使用了大量内存有良好的直觉。你将知道如何使用性能分析来找出性能瓶颈,并且你将了解足够的 C++ 知识,以将慢速的 R 函数转换为快速的 C++ 等效函数。

1.4 你学不到的是

这本书讨论的是 R 这门编程语言,而不是 R 这套数据分析工具。如果你想提高自己的数据科学技能,我建议你学习我和同事开发的一致性包 tidyverse。在这本书中,你将学习开发 tidyverse 包所使用的技术;如果你想学习如何使用它们,我建议阅读《R for Data Science》。

如果你想与他人分享你的R代码,你需要创建一个 R 包。这允许你将代码与文档和单元测试捆绑在一起,并通过 CRAN 轻松发布。在我看来,使用 devtools、roxygen2、testthat 和 usethis,是开发包的最简单方法。你可以在《R Packages》中了解如何使用这些包来制作你自己的包。

1.5 元技能(Meta-techniques)

提高 R 程序员的技能非常有帮助的两个元技能:阅读源代码和采用科学思维方式。

阅读源代码很重要,因为它将帮助你编写更好的代码。培养这种技能的一个很好的方法是查看你经常使用的函数和包的源代码。你会发现一些值得在你自己的代码中模仿的东西,还会培养出对什么是好的 R 代码的审美感。你还会看到一些你不喜欢的东西,要么因为它的优点不明显,要么因为它违反了你的审美感。尽管如此,这样的代码仍然有价值,因为它有助于明确你对好代码和坏代码的看法。

在学习 R 时,采用科学思维方式非常有帮助。如果你不理解某些东西是如何工作的,你应该提出一个假设,设计一些实验,运行它们,并记录结果。这个练习非常有用,因为如果你无法弄清楚某些事情并需要帮助,你可以轻松地向他人展示你尝试过的内容。此外,当你学到正确答案时,你会有心理准备刷新三观。

1.6 推荐阅读

因为 R 社区主要由数据科学家而非计算机专家构成,所以从技术上深入了解 R 的书籍相对较少。在我个人的学习过程中,我发现使用其他编程语言的资源特别有帮助。R 同时具有函数式编程和面向对象(OO)编程语言的一些特点。了解这些概念是如何在 R 中体现的,将有助于你充分利用对其他编程语言的现有知识,并帮助你找到可以提升的领域。

为了理解 R 对象系统的方式工作,我发现《计算机程序的构造和解释(The Structure and Interpretation of Computer Programs)》(SICP)特别有帮助。这是一本简洁而深刻的书,阅读后,我第一次感到我实际上可以设计自己的面向对象系统。这本书是我第一次接触到 R 中的封装式面向对象编程范例,并帮助我理解了这个系统的优点和缺点。SICP 还讲述了函数式思维方式,这使得你创建的函数在单独使用时非常简单,但组合在一起时变得非常强大。

为了了解 R 相对于其他编程语言所做的权衡,我发现《计算机编程的概念、技术和模型(Concepts, Techniques and Models of Computer Programming)》非常有帮助。它帮助我理解了R的复制-修改语义使得理解代码变得更加容易,并且尽管它的当前实现并不特别高效,但这是可以解决的问题。

如果你想成为一名更好的程序员,没有比《务实程序员(The Pragmatic Programmer)》更好的了。这本书与编程语言无关,提供了如何成为更好程序员的宝贵建议。

1.7 获取帮助

目前,在你陷入困境,无法找出问题根本原因时,有三个主要的途径可以获取帮助:RStudio 社区、StackOverflow 和 R-help 邮件列表。在每个场所都可以获得出色的帮助,但它们各自都有自己的文化和期望。通常,在你发表第一个帖子之前,花一点时间潜水,了解社区的期望是一个好主意。

一些好的通用建议:

  • 确保你使用的是最新版本的R和你遇到问题的包(或包)。也许你的问题是最近修复的错误导致的。
  • 花一些时间创建一个可重现示例,或称为reprex。这将有助于其他人帮助你,也经常会在不需要向其他人提问的情况下找到解决方案,因为你经常会在创建可重现的问题的过程中找到根本原因。我强烈推荐学习并使用 reprex 包。

如果你正在寻求解决本书中的练习的具体帮助,Malte Grosser 和 Henning Bumann 的解决方案可在 https://advanced-r-solutions.rbind.io上找到。

1.8 致谢

我想要感谢 R-devel、R-help 以及最近的 Stack Overflow 和 RStudio 社区的众多贡献者。个人无法一一列举,但我要特别感谢 Luke Tierney、John Chambers、JJ Allaire 和 Brian Ripley,他们慷慨地花时间纠正了我的无数误解。

这本书是在公开的环境中编写的,各章节在完成后会在Twitter上宣传。这确实是一个社区的努力:许多人阅读了草稿,纠正了错别字,提出了改进意见,并贡献了内容。没有这些贡献者,这本书将不会如今天这般优秀,我深感他们的帮助之深切。特别感谢 Jeff Hammerbacher、Peter Li、Duncan Murdoch 和 Greg Wilson,他们都阅读了整本书,提供了许多修正和建议。

同时非常感谢 386 名贡献者(按用户名字母顺序排序):Aaron Wolen (@aaronwolen), @absolutelyNoWarranty, Adam Hunt (@adamphunt), @agrabovsky, Alexander Grueneberg (@agrueneberg), Anthony Damico (@ajdamico), James Manton (@ajdm), Aaron Schumacher (@ajschumacher), Alan Dipert (@alandipert), Alex Brown (@alexbbrown), @alexperrone, Alex Whitworth (@alexWhitworth), Alexandros Kokkalis (@alko989), @amarchin, Amelia McNamara (@AmeliaMN), Bryce Mecum (@amoeba), Andrew Laucius (@andrewla), Andrew Bray (@andrewpbray), Andrie de Vries (@andrie), Angela Li (@angela-li), @aranlunzer, Ari Lamstein (@arilamstein), @asnr, Andy Teucher (@ateucher), Albert Vilella (@avilella), baptiste (@baptiste), Brian G. Barkley (@BarkleyBG), Mara Averick (@batpigandme), Byron (@bcjaeger), Brandon Greenwell (@bgreenwell), Brandon Hurr (@bhive01), Jason Knight (@binarybana), Brett Klamer (@bklamer), Jesse Anderson (@blindjesse), Brian Mayer (@blmayer), Benjamin L. Moore (@blmoore), Brian Diggs (@BrianDiggs), Brian S. Yandell (@byandell), @carey1024, Chip Hogg (@chiphogg), Chris Muir (@ChrisMuir), Christopher Gandrud (@christophergandrud), Clay Ford (@clayford), Colin Fay (@ColinFay), @cortinah, Cameron Plouffe (@cplouffe), Carson Sievert (@cpsievert), Craig Citro (@craigcitro), Craig Grabowski (@craiggrabowski), Christopher Roach (@croach), Peter Meilstrup (@crowding), Crt Ahlin (@crtahlin), Carlos Scheidegger (@cscheid), Colin Gillespie (@csgillespie), Christopher Brown (@ctbrown), Davor Cubranic (@cubranic), Darren Cusanovich (@cusanovich), Christian G. Warden (@cwarden), Charlotte Wickham (@cwickham), Dean Attali (@daattali), Dan Sullivan (@dan87134), Daniel Barnett (@daniel-barnett), Daniel (@danielruc91), Kenny Darrell (@darrkj), Tracy Nance (@datapixie), Dave Childers (@davechilders), David Vukovic (@david-vukovic), David Rubinger (@davidrubinger), David Chudzicki (@dchudz), Deependra Dhakal (@DeependraD), Daisuke ICHIKAWA (@dichika), david kahle (@dkahle), David LeBauer (@dlebauer), David Schweizer (@dlschweizer), David Montaner (@dmontaner), @dmurdoch, Zhuoer Dong (@dongzhuoer), Doug Mitarotonda (@dougmitarotonda), Dragoș Moldovan-Grünfeld (@dragosmg), Jonathan Hill (@Dripdrop12), @drtjc, Julian During (@duju211), @duncanwadsworth, @eaurele, Dirk Eddelbuettel (@eddelbuettel), @EdFineOKL, Eduard Szöcs (@EDiLD), Edwin Thoen (@EdwinTh), Ethan Heinzen (@eheinzen), @eijoac, Joel Schwartz (@eipi10), Eric Ronald Legrand (@elegrand), Elio Campitelli (@eliocamp), Ellis Valentiner (@ellisvalentiner), Emil Hvitfeldt (@EmilHvitfeldt), Emil Rehnberg (@EmilRehnberg), Daniel Lee (@erget), Eric C. Anderson (@eriqande), Enrico Spinielli (@espinielli), @etb, David Hajage (@eusebe), Fabian Scheipl (@fabian-s), @flammy0530, François Michonneau (@fmichonneau), Francois Pepin (@fpepin), Frank Farach (@frankfarach), @freezby, Frans van Dunné (@FvD), @fyears, @gagnagaman, Garrett Grolemund (@garrettgman), Gavin Simpson (@gavinsimpson), Brooke Anderson (@geanders), @gezakiss7, @gggtest, Gökçen Eraslan (@gokceneraslan), Josh Goldberg (@GoldbergData), Georg Russ (@gr650), @grasshoppermouse, Gregor Thomas (@gregorp), Garrett See (@gsee), Ari Friedman (@gsk3), Gunnlaugur Thor Briem (@gthb), Greg Wilson (@gvwilson), Hamed (@hamedbh), Jeff Hammerbacher (@hammer), Harley Day (@harleyday), @hassaad85, @helmingstay, Henning (@henningsway), Henrik Bengtsson (@HenrikBengtsson), Ching Boon (@hoscb), @hplieninger, Hörmet Yiltiz (@hyiltiz), Iain Dillingham (@iaindillingham), @IanKopacka, Ian Lyttle (@ijlyttle), Ilan Man (@ilanman), Imanuel Costigan (@imanuelcostigan), Thomas Bürli (@initdch), Os Keyes (@Ironholds), @irudnyts, i (@isomorphisms), Irene Steves (@isteves), Jan Gleixner (@jan-glx), Jannes Muenchow (@jannes-m), Jason Asher (@jasonasher), Jason Davies (@jasondavies), Chris (@jastingo), jcborras (@jcborras), Joe Cheng (@jcheng5), John Blischak (@jdblischak), @jeharmse, Lukas Burk (@jemus42), Jennifer (Jenny) Bryan (@jennybc), Justin Jent (@jentjr), Jeston (@JestonBlu), Josh Cook (@jhrcook), Jim Hester (@jimhester), @JimInNashville, @jimmyliu2017, Jim Vine (@jimvine), Jinlong Yang (@jinlong25), J.J. Allaire (@jjallaire), @JMHay, Jochen Van de Velde (@jochenvdv), Johann Hibschman (@johannh), John Baumgartner (@johnbaums), John Horton (@johnjosephhorton), @johnthomas12, Jon Calder (@jonmcalder), Jon Harmon (@jonthegeek), Julia Gustavsen (@jooolia), JorneBiccler (@JorneBiccler), Jeffrey Arnold (@jrnold), Joyce Robbins (@jtr13), Juan Manuel Truppia (@juancentro), @juangomezduaso, Kevin Markham (@justmarkham), john verzani (@jverzani), Michael Kane (@kaneplusplus), Bart Kastermans (@kasterma), Kevin D’Auria (@kdauria), Karandeep Singh (@kdpsingh), Ken Williams (@kenahoo), Kendon Bell (@kendonB), Kent Johnson (@kent37), Kevin Ushey (@kevinushey), 电线杆 (@kfeng123), Karl Forner (@kforner), Kirill Sevastyanenko (@kirillseva), Brian Knaus (@knausb), Kirill Müller (@krlmlr), Kriti Sen Sharma (@ksens), Kai Tang (唐恺) (@ktang), Kevin Wright (@kwstat), suo.lawrence.liu@gmail.com (@Lawrence-Liu), @ldfmrails, Kevin Kainan Li (@legendre6891), Rachel Severson (@leighseverson), Laurent Gatto (@lgatto), C. Jason Liang (@liangcj), Steve Lianoglou (@lianos), Yongfu Liao (@liao961120), Likan (@likanzhan), @lindbrook, Lingbing Feng (@Lingbing), Marcel Ramos (@LiNk-NY), Zhongpeng Lin (@linzhp), Lionel Henry (@lionel-), Lluís (@llrs), myq (@lrcg), Luke W Johnston (@lwjohnst86), Kevin Lynagh (@lynaghk), @MajoroMask, Malcolm Barrett (@malcolmbarrett), @mannyishere, @mascaretti, Matt (@mattbaggott), Matthew Grogan (@mattgrogan), @matthewhillary, Matthieu Gomez (@matthieugomez), Matt Malin (@mattmalin), Mauro Lepore (@maurolepore), Max Ghenis (@MaxGhenis), Maximilian Held (@maxheld83), Michal Bojanowski (@mbojan), Mark Rosenstein (@mbrmbr), Michael Sumner (@mdsumner), Jun Mei (@meijun), merkliopas (@merkliopas), mfrasco (@mfrasco), Michael Bach (@michaelbach), Michael Bishop (@MichaelMBishop), Michael Buckley (@michaelmikebuckley), Michael Quinn (@michaelquinn32), @miguelmorin, Michael (@mikekaminsky), Mine Cetinkaya-Rundel (@mine-cetinkaya-rundel), @mjsduncan, Mamoun Benghezal (@MoBeng), Matt Pettis (@mpettis), Martin Morgan (@mtmorgan), Guy Dawson (@Mullefa), Nacho Caballero (@nachocab), Natalya Rapstine (@natalya-patrikeeva), Nick Carchedi (@ncarchedi), Pascal Burkhard (@Nenuial), Noah Greifer (@ngreifer), Nicholas Vasile (@nickv9), Nikos Ignatiadis (@nignatiadis), Nina Munkholt Jakobsen (@nmjakobsen), Xavier Laviron (@norival), Nick Pullen (@nstjhp), Oge Nnadi (@ogennadi), Oliver Paisley (@oliverpaisley), Pariksheet Nanda (@omsai), Øystein Sørensen (@osorensen), Paul (@otepoti), Otho Mantegazza (@othomantegazza), Dewey Dunnington (@paleolimbot), Paola Corrales (@paocorrales), Parker Abercrombie (@parkerabercrombie), Patrick Hausmann (@patperu), Patrick Miller (@patr1ckm), Patrick Werkmeister (@Patrick01), @paulponcet, @pdb61, Tom Crockett (@pelotom), @pengyu, Jeremiah (@perryjer1), Peter Hickey (@PeteHaitch), Phil Chalmers (@philchalmers), Jose Antonio Magaña Mesa (@picarus), Pierre Casadebaig (@picasa), Antonio Piccolboni (@piccolbo), Pierre Roudier (@pierreroudier), Poor Yorick (@pooryorick), Marie-Helene Burle (@prosoitos), Peter Schulam (@pschulam), John (@quantbo), Quyu Kong (@qykong), Ramiro Magno (@ramiromagno), Ramnath Vaidyanathan (@ramnathv), Kun Ren (@renkun-ken), Richard Reeve (@richardreeve), Richard Cotton (@richierocks), Robert M Flight (@rmflight), R. Mark Sharp (@rmsharp), Robert Krzyzanowski (@robertzk), @robiRagan, Romain François (@romainfrancois), Ross Holmberg (@rossholmberg), Ricardo Pietrobon (@rpietro), @rrunner, Ryan Walker (@rtwalker), @rubenfcasal, Rob Weyant (@rweyant), Rumen Zarev (@rzarev), Nan Wang (@sailingwave), Samuel Perreault (@samperochkin), @sbgraves237, Scott Kostyshak (@scottkosty), Scott Leishman (@scttl), Sean Hughes (@seaaan), Sean Anderson (@seananderson), Sean Carmody (@seancarmody), Sebastian (@sebastian-c), Matthew Sedaghatfar (@sedaghatfar), @see24, Sven E. Templer (@setempler), @sflippl, @shabbybanks, Steven Pav (@shabbychef), Shannon Rush (@shannonrush), S’busiso Mkhondwane (@sibusiso16), Sigfried Gold (@Sigfried), Simon O’Hanlon (@simonohanlon101), Simon Potter (@sjp), Leo Razoumov (@slonik-az), Richard M. Smith (@Smudgerville), Steve (@SplashDance), Scott Ritchie (@sritchie73), Tim Cole (@statist7), @ste-fan, @stephens999, Steve Walker (@stevencarlislewalker), Stefan Widgren (@stewid), Homer Strong (@strongh), Suman Khanal (@sumanstats), Dirk (@surmann), Sebastien Vigneau (@svigneau), Steven Nydick (@swnydick), Taekyun Kim (@taekyunk), Tal Galili (@talgalili), @Tazinho, Tyler Bradley (@tbradley1013), Tom B (@tbuckl), @tdenes, @thomasherbig, Thomas (@thomaskern), Thomas Lin Pedersen (@thomasp85), Thomas Zumbrunn (@thomaszumbrunn), Tim Waterhouse (@timwaterhouse), TJ Mahr (@tjmahr), Thomas Nagler (@tnagler), Anton Antonov (@tonytonov), Ben Torvaney (@Torvaney), Jeff Allen (@trestletech), Tyler Rinker (@trinker), Chitu Okoli (@Tripartio), Kirill Tsukanov (@tskir), Terence Teo (@tteo), Tim Triche, Jr. (@ttriche), @tyhenkaline, Tyler Ritchie (@tylerritchie), Tyler Littlefield (@tyluRp), Varun Agrawal (@varun729), Vijay Barve (@vijaybarve), Victor (@vkryukov), Vaidotas Zemlys-Balevičius (@vzemlys), Winston Chang (@wch), Linda Chin (@wchi144), Welliton Souza (@Welliton309), Gregg Whitworth (@whitwort), Will Beasley (@wibeasley), William R Bauer (@WilCrofter), William Doane (@WilDoane), Sean Wilkinson (@wilkinson), Christof Winter (@winterschlaefer), Jake Thompson (@wjakethompson), Bill Carver (@wmc3), Wolfgang Huber (@wolfganghuber), Krishna Sankar (@xsankar), Yihui Xie (@yihui), yang (@yiluheihei), Yoni Ben-Meshulam (@yoni), @yuchouchen, Yuqi Liao (@yuqiliao), Hiroaki Yutani (@yutannihilation), Zachary Foster (@zachary-foster), @zachcp, @zackham, Sergio Oller (@zeehio), Edward Cho (@zerokarmaleft), Albert Zhao (@zxzb).

1.9 约定

在本书中,我使用f()来指代函数,g来指代变量和函数参数,h/来指代路径。

较大的代码块会混合输入和输出。输出是以(#>)开头的注释,因此如果你有这本书的电子版本,比如 https://adv-r.hadley.nz/,你可以轻松地将示例复制粘贴到 R 中。

许多示例使用了随机数。通过 set.seed(1014) 来使这些示例具有可重现性,这个命令会在每一章的开头自动执行。

1.10 版本

这本书是在 RStudio 中使用 bookdown 编写的。网站由 netlify 托管,并在每次提交后由 travis-ci 自动更新。完整的源代码可以从GitHub获取。印刷版书中的代码使用 inconsolata 字体。印刷版书中的表情图像来自于开放许可的 Twitter Emoji。

此书此版使用的 R 版本是 4.0.4(2021-02-15),以下各包的版本是:

packageversionsource
bench1.1.1standard (@1.1.1)
bookdown0.21.6Github (rstudio/bookdown@6b4665f)
bslib0.2.4.9002Github (rstudio/bslib@ed563f7)
dbplyr2.1.0standard (@2.1.0)
desc1.2.0standard (@1.2.0)
downlit0.2.1standard (@0.2.1)
emo0.0.0.9000Github (hadley/emo@3f03b11)
ggbeeswarm0.6.0standard (@0.6.0)
ggplot23.3.3standard (@3.3.3)
jsonlite1.7.2standard (@1.7.2)
knitr1.3standard (@1.31)
lobstr1.1.1standard (@1.1.1)
memoise2.0.0standard (@2.0.0)
png0.1-7standard (@0.1-7)
profvis0.3.7standard (@0.3.7)
Rcpp1.0.6standard (@1.0.6)
rlang0.4.10tandard (@0.4.10)
RSQLite2.2.3standard (@2.2.3)
scales1.1.1standard (@1.1.1)
sessioninfo1.1.1standard (@1.1.1)
sloop1.0.1standard (@1.0.1)
testthat3.0.2standard (@3.0.2)
tidyr1.1.2standard (@1.1.2)
vctrs0.3.6standard (@0.3.6)
xml21.3.2standard (@1.3.2)
zeallot0.1.0standard (@0.1.0)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值