galaaz 0.4.10 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +26 -0
- data/LICENSE +0 -0
- data/README.md +3123 -882
- data/Rakefile +62 -41
- data/bin/galaaz-bootstrap +137 -0
- data/bin/galaaz-jruby +14 -0
- data/bin/galaaz_jruby_env.inc.sh +6 -0
- data/bin/gbookdown +64 -0
- data/bin/gknit +223 -6
- data/bin/gknit-draft +105 -0
- data/bin/gknit-draft.rb +28 -0
- data/bin/gknit_Rscript +127 -0
- data/bin/grun +27 -1
- data/bin/gstudio +49 -4
- data/bin/{gstudio.rb → gstudio_irb.rb} +0 -0
- data/bin/gstudio_pry.rb +7 -0
- data/bin/install-tinytex +6 -0
- data/bin/run_all_rspec +43 -0
- data/bin/run_example +14 -0
- data/bin/run_old_rspec +19 -0
- data/bin/run_rspec +23 -0
- data/bin/run_rspec_subset +38 -0
- data/bin/run_slow_rspec +19 -0
- data/blogs/R-on-Rails-Planning-Document.md +940 -0
- data/blogs/README.md +100 -0
- data/blogs/galaaz_ggplot/galaaz_ggplot.Rmd +38 -66
- data/blogs/galaaz_ggplot/galaaz_ggplot.log +754 -0
- data/blogs/galaaz_ggplot/galaaz_ggplot.md +364 -0
- data/blogs/galaaz_ggplot/galaaz_ggplot.tex +607 -0
- data/blogs/galaaz_ggplot/galaaz_ggplot_files/figure-html/midwest_rb.png +0 -0
- data/blogs/galaaz_ggplot/galaaz_ggplot_files/figure-html/scatter_plot_rb.png +0 -0
- data/blogs/galaaz_ggplot/galaaz_ggplot_files/figure-markdown_github/midwest_rb.png +0 -0
- data/blogs/galaaz_ggplot/galaaz_ggplot_files/figure-markdown_github/scatter_plot_rb.png +0 -0
- data/blogs/galaaz_ggplot/midwest.Rmd +3 -3
- data/blogs/galaaz_ggplot/midwest_external_png +0 -0
- data/blogs/gknit/gknit.Rmd +52 -55
- data/blogs/gknit/gknit.md +94 -94
- data/blogs/gknit/gknit_files/figure-html/bubble-1.png +0 -0
- data/blogs/gknit/gknit_files/figure-html/diverging_bar.png +0 -0
- data/blogs/gknit/lst.rds +0 -0
- data/blogs/gknit/model.rb +1 -1
- data/blogs/gknit/stats.bib +0 -0
- data/blogs/manual/include_model_local_repro.Rmd +14 -0
- data/blogs/manual/include_model_local_repro.md +75 -0
- data/blogs/manual/lst.rds +0 -0
- data/blogs/manual/manual.Rmd +1582 -196
- data/blogs/manual/manual.log +1786 -0
- data/blogs/manual/manual.md +3107 -890
- data/blogs/manual/manual.tex +3018 -1086
- data/blogs/manual/manual_files/figure-html/bubble-1.png +0 -0
- data/blogs/manual/manual_files/figure-html/diverging_bar.png +0 -0
- data/blogs/manual/manual_files/figure-latex/bubble-1.png +0 -0
- data/blogs/manual/model.rb +41 -0
- data/blogs/nse_dplyr/nse_dplyr.Rmd +277 -151
- data/blogs/nse_dplyr/nse_dplyr.log +928 -0
- data/blogs/nse_dplyr/nse_dplyr.md +457 -293
- data/blogs/oh_my/not_so.rb +0 -0
- data/blogs/oh_my/oh_my.Rmd +1234 -25
- data/blogs/oh_my/oh_my.log +804 -0
- data/blogs/oh_my/oh_my.md +1808 -228
- data/blogs/oh_my/oh_my.tex +821 -0
- data/blogs/oh_my/old.Rmd +15 -14
- data/blogs/ruby_plot/ruby_plot.Rmd +58 -82
- data/blogs/ruby_plot/ruby_plot.log +885 -0
- data/blogs/ruby_plot/ruby_plot.md +71 -103
- data/blogs/ruby_plot/ruby_plot.tex +940 -0
- data/blogs/ruby_plot/ruby_plot_files/figure-html/dose_len.png +0 -0
- data/blogs/ruby_plot/ruby_plot_files/figure-html/facet_by_delivery.png +0 -0
- data/blogs/ruby_plot/ruby_plot_files/figure-html/facet_by_dose.png +0 -0
- data/blogs/ruby_plot/ruby_plot_files/figure-html/facets_by_delivery_color.png +0 -0
- data/blogs/ruby_plot/ruby_plot_files/figure-html/facets_by_delivery_color2.png +0 -0
- data/blogs/ruby_plot/ruby_plot_files/figure-html/facets_with_decorations.png +0 -0
- data/blogs/ruby_plot/ruby_plot_files/figure-html/facets_with_jitter.png +0 -0
- data/blogs/ruby_plot/ruby_plot_files/figure-html/facets_with_points.png +0 -0
- data/blogs/ruby_plot/ruby_plot_files/figure-html/final_box_plot.png +0 -0
- data/blogs/ruby_plot/ruby_plot_files/figure-html/final_violin_plot.png +0 -0
- data/blogs/ruby_plot/ruby_plot_files/figure-html/violin_with_jitter.png +0 -0
- data/blogs/ruby_plot/ruby_plot_files/figure-latex/dose_len.png +0 -0
- data/blogs/ruby_plot/ruby_plot_files/figure-latex/facet_by_delivery.png +0 -0
- data/blogs/ruby_plot/ruby_plot_files/figure-latex/facet_by_dose.png +0 -0
- data/blogs/ruby_plot/ruby_plot_files/figure-latex/facets_by_delivery_color.png +0 -0
- data/blogs/ruby_plot/ruby_plot_files/figure-latex/facets_by_delivery_color2.png +0 -0
- data/blogs/ruby_plot/ruby_plot_files/figure-latex/facets_with_decorations.png +0 -0
- data/blogs/ruby_plot/ruby_plot_files/figure-latex/facets_with_jitter.png +0 -0
- data/blogs/ruby_plot/ruby_plot_files/figure-latex/facets_with_points.png +0 -0
- data/blogs/ruby_plot/ruby_plot_files/figure-latex/final_box_plot.png +0 -0
- data/blogs/ruby_plot/ruby_plot_files/figure-latex/final_violin_plot.png +0 -0
- data/blogs/ruby_plot/ruby_plot_files/figure-latex/violin_with_jitter.png +0 -0
- data/blogs/test/test.Rmd +14 -0
- data/examples/50Plots_MasterList/Images/midwest-scatterplot.PNG +0 -0
- data/examples/50Plots_MasterList/ScatterPlot.rb +0 -0
- data/examples/50Plots_MasterList/scatter_plot.rb +0 -0
- data/examples/Bibliography/master.bib +50 -0
- data/examples/Bibliography/stats.bib +72 -0
- data/examples/R/calc.R +0 -0
- data/examples/R/java_interop.R +0 -0
- data/examples/bioconductor_deseq2_airway/Documentation/DESeq2-airway-walkthrough.md +56 -0
- data/examples/bioconductor_deseq2_airway/bench_galaaz_three_same_process.rb +53 -0
- data/examples/bioconductor_deseq2_airway/bench_r_three_same_process.R +34 -0
- data/examples/bioconductor_deseq2_airway/deseq2_airway_galaaz.rb +33 -0
- data/examples/bioconductor_deseq2_airway/deseq2_airway_galaaz_optimized.rb +34 -0
- data/examples/bioconductor_deseq2_airway/deseq2_airway_minimal.R +30 -0
- data/examples/bioconductor_deseq2_airway/deseq2_airway_pipeline_for_bench.R +36 -0
- data/examples/islr/all.rb +13 -0
- data/examples/islr/ch2.spec.rb +37 -7
- data/examples/islr/ch3.spec.rb +11 -2
- data/examples/islr/ch3_boston.rb +27 -0
- data/examples/islr/ch3_multiple_regression.rb +0 -0
- data/examples/islr/ch6.spec.rb +24 -1
- data/examples/islr/x_y_rnorm.jpg +0 -0
- data/examples/latex_templates/Test-acm_article/Makefile +16 -0
- data/examples/latex_templates/Test-acm_article/Test-acm_article.Rmd +65 -0
- data/examples/latex_templates/Test-acm_article/acm_proc_article-sp.cls +1670 -0
- data/examples/latex_templates/Test-acm_article/sensys-abstract.cls +703 -0
- data/examples/latex_templates/Test-acm_article/sigproc.bib +59 -0
- data/examples/latex_templates/Test-acs_article/Test-acs_article.Rmd +260 -0
- data/examples/latex_templates/Test-acs_article/acs-Test-acs_article.bib +11 -0
- data/examples/latex_templates/Test-acs_article/acs-my_output.bib +11 -0
- data/examples/latex_templates/Test-acs_article/acstest.bib +17 -0
- data/examples/latex_templates/Test-aea_article/AEA.cls +1414 -0
- data/{blogs/gknit/marshal.dump → examples/latex_templates/Test-aea_article/BibFile.bib} +0 -0
- data/examples/latex_templates/Test-aea_article/Test-aea_article.Rmd +108 -0
- data/examples/latex_templates/Test-aea_article/aea.bst +1269 -0
- data/examples/latex_templates/Test-aea_article/multicol.sty +853 -0
- data/examples/latex_templates/Test-aea_article/references.bib +0 -0
- data/examples/latex_templates/Test-aea_article/setspace.sty +546 -0
- data/examples/latex_templates/Test-amq_article/Test-amq_article.Rmd +256 -0
- data/examples/latex_templates/Test-amq_article/Test-amq_article.pdfsync +3397 -0
- data/examples/latex_templates/Test-ams_article/Test-ams_article.Rmd +215 -0
- data/examples/latex_templates/Test-ams_article/amstest.bib +436 -0
- data/examples/latex_templates/Test-asa_article/Test-asa_article.Rmd +153 -0
- data/examples/latex_templates/Test-asa_article/agsm.bst +1353 -0
- data/examples/latex_templates/Test-asa_article/bibliography.bib +233 -0
- data/examples/latex_templates/Test-ieee_article/IEEEtran.bst +2409 -0
- data/examples/latex_templates/Test-ieee_article/IEEEtran.cls +6346 -0
- data/examples/latex_templates/Test-ieee_article/Test-ieee_article.Rmd +175 -0
- data/examples/latex_templates/Test-ieee_article/mybibfile.bib +20 -0
- data/examples/latex_templates/Test-rjournal_article/RJournal.sty +335 -0
- data/examples/latex_templates/Test-rjournal_article/RJreferences.bib +18 -0
- data/examples/latex_templates/Test-rjournal_article/Test-rjournal_article.Rmd +52 -0
- data/examples/latex_templates/Test-springer_article/Test-springer_article.Rmd +65 -0
- data/examples/latex_templates/Test-springer_article/bibliography.bib +26 -0
- data/examples/latex_templates/Test-springer_article/spbasic.bst +1658 -0
- data/examples/latex_templates/Test-springer_article/spmpsci.bst +1512 -0
- data/examples/latex_templates/Test-springer_article/spphys.bst +1443 -0
- data/examples/latex_templates/Test-springer_article/svglov3.clo +113 -0
- data/examples/latex_templates/Test-springer_article/svjour3.cls +1431 -0
- data/examples/misc/baseball.csv +0 -0
- data/examples/misc/ggplot.rb +3 -2
- data/examples/misc/moneyball.rb +0 -0
- data/examples/misc/subsetting.rb +0 -0
- data/examples/multithread_shards_to_r/shards_to_r.rb +67 -0
- data/examples/rmarkdown/svm-rmarkdown-anon-ms-example/svm-rmarkdown-anon-ms-example.Rmd +73 -0
- data/examples/rmarkdown/svm-rmarkdown-article-example/svm-rmarkdown-article-example.Rmd +382 -0
- data/examples/rmarkdown/svm-rmarkdown-beamer-example/svm-rmarkdown-beamer-example.Rmd +164 -0
- data/examples/rmarkdown/svm-rmarkdown-cv/svm-rmarkdown-cv.Rmd +92 -0
- data/examples/rmarkdown/svm-rmarkdown-syllabus-example/attend-grade-relationships.csv +482 -0
- data/examples/rmarkdown/svm-rmarkdown-syllabus-example/svm-rmarkdown-syllabus-example.Rmd +280 -0
- data/examples/rmarkdown/svm-xaringan-example/svm-xaringan-example.Rmd +386 -0
- data/examples/sthda_ggplot/README.md +0 -0
- data/examples/sthda_ggplot/RUN.md +41 -0
- data/examples/sthda_ggplot/all.rb +0 -0
- data/examples/sthda_ggplot/one_variable_continuous/density_gg.rb +0 -0
- data/examples/sthda_ggplot/one_variable_continuous/geom_area.rb +0 -0
- data/examples/sthda_ggplot/one_variable_continuous/geom_density.rb +2 -0
- data/examples/sthda_ggplot/one_variable_continuous/geom_dotplot.rb +0 -0
- data/examples/sthda_ggplot/one_variable_continuous/geom_freqpoly.rb +0 -0
- data/examples/sthda_ggplot/one_variable_continuous/geom_histogram.rb +0 -0
- data/examples/sthda_ggplot/one_variable_continuous/histogram_density.rb +0 -0
- data/examples/sthda_ggplot/one_variable_continuous/stat.rb +0 -0
- data/examples/sthda_ggplot/one_variable_discrete/bar.rb +0 -0
- data/examples/sthda_ggplot/qplots/box_violin_dot.rb +0 -0
- data/examples/sthda_ggplot/qplots/scatter_plots.rb +0 -0
- data/examples/sthda_ggplot/scatter_gg.rb +0 -0
- data/examples/sthda_ggplot/two_variables_cont_bivariate/geom_bin2d.rb +0 -0
- data/examples/sthda_ggplot/two_variables_cont_bivariate/geom_density2d.rb +0 -0
- data/examples/sthda_ggplot/two_variables_cont_bivariate/geom_hex.rb +0 -0
- data/examples/sthda_ggplot/two_variables_cont_cont/geom_point.rb +0 -0
- data/examples/sthda_ggplot/two_variables_cont_cont/geom_smooth.rb +0 -0
- data/examples/sthda_ggplot/two_variables_cont_cont/misc.rb +0 -0
- data/examples/sthda_ggplot/two_variables_cont_function/geom_area.rb +4 -3
- data/examples/sthda_ggplot/two_variables_disc_cont/geom_bar.rb +0 -0
- data/examples/sthda_ggplot/two_variables_disc_cont/geom_boxplot.rb +0 -0
- data/examples/sthda_ggplot/two_variables_disc_cont/geom_dotplot.rb +0 -0
- data/examples/sthda_ggplot/two_variables_disc_cont/geom_jitter.rb +0 -0
- data/examples/sthda_ggplot/two_variables_disc_cont/geom_line.rb +0 -0
- data/examples/sthda_ggplot/two_variables_disc_cont/geom_violin.rb +0 -0
- data/examples/sthda_ggplot/two_variables_disc_disc/geom_jitter.rb +0 -0
- data/examples/sthda_ggplot/two_variables_error/geom_crossbar.rb +0 -0
- data/ext/new_bridge/Makefile +46 -0
- data/ext/new_bridge/galaaz_gatekeeper_phase0.cpp +12 -0
- data/ext/new_bridge/galaaz_gatekeeper_phase1.cpp +1639 -0
- data/lib/R_interface/galaaz_device.R +20 -0
- data/lib/R_interface/include_engine.R +109 -0
- data/lib/R_interface/new_bridge_adapter.rb +824 -0
- data/lib/R_interface/r.rb +177 -25
- data/lib/R_interface/r_arrow.rb +113 -0
- data/lib/R_interface/r_libs.R +4 -4
- data/lib/R_interface/r_methods.rb +13 -116
- data/lib/R_interface/r_module_s.rb +0 -0
- data/lib/R_interface/rbinary_operators.rb +20 -2
- data/lib/R_interface/rclosure.rb +5 -1
- data/lib/R_interface/rdata_frame.rb +34 -70
- data/lib/R_interface/rdevice.rb +125 -0
- data/lib/R_interface/rdevices.R +0 -0
- data/lib/R_interface/renvironment.rb +10 -4
- data/lib/R_interface/rexpression.rb +5 -1
- data/lib/R_interface/rindexed_object.rb +41 -13
- data/lib/R_interface/rlanguage.rb +20 -62
- data/lib/R_interface/rlist.rb +115 -25
- data/lib/R_interface/rlogical_operators.rb +0 -0
- data/lib/R_interface/rmatrix.rb +2 -11
- data/lib/R_interface/rmd_indexed_object.rb +5 -1
- data/lib/R_interface/robject.rb +348 -290
- data/lib/R_interface/rpkg.rb +1 -0
- data/lib/R_interface/rsupport.rb +610 -331
- data/lib/R_interface/rsupport_scope.rb +2 -1
- data/lib/R_interface/rsymbol.rb +50 -0
- data/lib/R_interface/ruby_callback.rb +2 -3
- data/lib/R_interface/ruby_extensions.rb +225 -175
- data/lib/R_interface/runary_operators.rb +0 -0
- data/lib/R_interface/rvector.rb +147 -31
- data/lib/galaaz.rb +0 -0
- data/lib/galaaz_jruby.rb +22 -0
- data/lib/gknit/diagnostics.rb +50 -0
- data/lib/gknit/draft.rb +111 -0
- data/lib/gknit/include_engine.rb +15 -7
- data/lib/gknit/knitr_engine.rb +223 -107
- data/lib/gknit/rb_engine.rb +3 -3
- data/lib/gknit/ruby_engine.rb +0 -0
- data/lib/gknit.rb +3 -0
- data/lib/new_bridge/bootstrap/windows_bootstrap.rb +285 -0
- data/lib/new_bridge/envelope.rb +51 -0
- data/lib/new_bridge/eval_result.rb +26 -0
- data/lib/new_bridge/framing.rb +39 -0
- data/lib/new_bridge/instance_pool_client.rb +38 -0
- data/lib/new_bridge/r_instance_manager.rb +404 -0
- data/lib/new_bridge/session_client.rb +530 -0
- data/lib/new_bridge/tcp_framed.rb +44 -0
- data/lib/new_bridge.rb +9 -0
- data/lib/util/exec_ruby.rb +95 -46
- data/lib/util/inline_file.rb +35 -30
- data/new_bridge_specs/benchmark_phase5_5_unboxing_spec.rb +96 -0
- data/new_bridge_specs/eval_r_async_spec.rb +113 -0
- data/new_bridge_specs/integration_phase5_1_concurrent_spec.rb +50 -0
- data/new_bridge_specs/integration_phase5_1_eval_spec.rb +16 -0
- data/new_bridge_specs/integration_phase5_1_r_api_spec.rb +25 -0
- data/new_bridge_specs/integration_phase5_1_smoke_spec.rb +31 -0
- data/new_bridge_specs/integration_phase5_2_dataframe_unboxing_spec.rb +19 -0
- data/new_bridge_specs/integration_phase5_2_handle_eval_unboxing_spec.rb +25 -0
- data/new_bridge_specs/integration_phase5_3_callback_args_spec.rb +28 -0
- data/new_bridge_specs/integration_phase5_3_callback_error_spec.rb +22 -0
- data/new_bridge_specs/integration_phase5_3_callback_timeout_spec.rb +28 -0
- data/new_bridge_specs/integration_phase5_3_callbacks_smoke_spec.rb +22 -0
- data/new_bridge_specs/integration_phase5_3_edge_cases_spec.rb +52 -0
- data/new_bridge_specs/integration_phase5_3_nested_spec.rb +30 -0
- data/new_bridge_specs/integration_phase5_4_concurrent_sessions_spec.rb +53 -0
- data/new_bridge_specs/integration_phase5_4_nested_session_callbacks_spec.rb +49 -0
- data/new_bridge_specs/integration_phase5_4_session_routing_spec.rb +38 -0
- data/new_bridge_specs/integration_phase5_5_stress_concurrency_spec.rb +52 -0
- data/new_bridge_specs/integration_phase5_5_unbox_walk_spec.rb +46 -0
- data/new_bridge_specs/phase0_protocol_spec.rb +96 -0
- data/new_bridge_specs/phase1_req_ret_spec.rb +66 -0
- data/new_bridge_specs/phase2_multi_instance_spec.rb +67 -0
- data/new_bridge_specs/phase3_callbacks_spec.rb +71 -0
- data/new_bridge_specs/phase4_2_hardening_spec.rb +252 -0
- data/new_bridge_specs/phase4_3_r_instance_manager_spec.rb +85 -0
- data/new_bridge_specs/phase4_nested_callbacks_spec.rb +123 -0
- data/r_requires/ggplot.rb +0 -0
- data/r_requires/knitr.rb +0 -0
- data/specs/all.rb +15 -11
- data/specs/arrow_from_ruby_batches_spec.rb +50 -0
- data/specs/arrow_semantics_spec.rb +64 -0
- data/specs/bridge_concurrent_spec.rb +46 -0
- data/specs/bridge_nested_spec.rb +25 -0
- data/specs/dataframe_semantics_spec.rb +122 -0
- data/specs/dataframe_single_index_logical_filter_spec.rb +21 -0
- data/specs/dispatch_probe_cache_spec.rb +38 -0
- data/specs/dispatch_probe_error_class_fallback_spec.rb +20 -0
- data/specs/dispatch_probe_fallback_spec.rb +18 -0
- data/specs/environment_semantics_spec.rb +89 -0
- data/specs/field_access_spec.rb +31 -0
- data/specs/figures/bg.jpeg +0 -0
- data/specs/figures/bg.png +0 -0
- data/specs/figures/bg.svg +168 -57
- data/specs/figures/dose_len.png +0 -0
- data/specs/figures/no_args.jpeg +0 -0
- data/specs/figures/no_args.png +0 -0
- data/specs/figures/no_args.svg +168 -57
- data/specs/figures/width_height.jpeg +0 -0
- data/specs/figures/width_height.png +0 -0
- data/specs/figures/width_height_units1.jpeg +0 -0
- data/specs/figures/width_height_units1.png +0 -0
- data/specs/figures/width_height_units2.jpeg +0 -0
- data/specs/figures/width_height_units2.png +0 -0
- data/specs/formula_semantics_spec.rb +81 -0
- data/specs/galaaz_util_exec_ruby_spec.rb +85 -0
- data/specs/galaaz_util_inline_file_spec.rb +54 -0
- data/specs/gknit_cli_option_permutation_spec.rb +24 -0
- data/specs/gknit_include_engine_spec.rb +72 -0
- data/specs/gknit_install_timeout_report_spec.rb +69 -0
- data/specs/gknit_internal_error_report_spec.rb +57 -0
- data/specs/gknit_vector_map_output_spec.rb +59 -0
- data/specs/globalenv_guardrail_spec.rb +52 -0
- data/specs/language_expression_semantics_spec.rb +145 -0
- data/specs/list_semantics_spec.rb +111 -0
- data/specs/new_bridge_bulk_dataframe_transfer_spec.rb +44 -0
- data/specs/new_bridge_bulk_vector_transfer_spec.rb +73 -0
- data/specs/new_bridge_callback_timeout_spec.rb +69 -0
- data/specs/new_bridge_eval_r_fallback_spec.rb +55 -0
- data/specs/nil_null_spec.rb +42 -0
- data/specs/object_build_phase2_spec.rb +53 -0
- data/specs/phase1_callback_bridge_spec.rb +84 -0
- data/specs/phase2_gknit_generic_rendering_guardrail_spec.rb +46 -0
- data/specs/phase2_gknit_no_raw_code_leakage_spec.rb +43 -0
- data/specs/phase3_gknit_generic_graphics_capture_spec.rb +71 -0
- data/specs/plot_device_semantics_spec.rb +28 -0
- data/specs/plot_snapshot_semantics_spec.rb +58 -0
- data/specs/protocol_result_spec.rb +236 -0
- data/specs/r_batch_fail_fast_spec.rb +47 -0
- data/specs/r_bridge_bootstrap_spec.rb +11 -0
- data/specs/r_devices.spec.rb +1 -1
- data/specs/r_eval.spec.rb +16 -18
- data/specs/r_function.spec.rb +1 -1
- data/specs/r_instance_manager_spec.rb +285 -0
- data/specs/r_list_apply.spec.rb +15 -15
- data/specs/r_matrix.spec.rb +0 -0
- data/specs/r_nse.spec.rb +5 -5
- data/specs/r_object_send_dispatch_spec.rb +13 -0
- data/specs/r_vector_comparator_spec.rb +8 -0
- data/specs/r_vector_creation.spec.rb +0 -0
- data/specs/r_vector_functions.spec.rb +0 -0
- data/specs/r_vector_object.spec.rb +0 -0
- data/specs/r_vector_operators.spec.rb +0 -0
- data/specs/r_vector_structured_scalar_reads_spec.rb +35 -0
- data/specs/r_vector_subsetting.spec.rb +0 -0
- data/specs/range_helper_spec.rb +21 -0
- data/specs/rsupport_scope_spec.rb +28 -0
- data/specs/rsupport_var_name_thread_safety_spec.rb +24 -0
- data/specs/scalar_character_spec.rb +44 -0
- data/specs/scoped_symbol_dsl_refinement_spec.rb +40 -0
- data/specs/session_env_bridge_spec.rb +25 -0
- data/specs/simplecov_bootstrap_spec.rb +10 -0
- data/specs/spec_helper.rb +10 -0
- data/specs/tmp.rb +41 -20
- data/specs/unboxing_recursion_regression_spec.rb +30 -0
- data/specs/unboxing_spec.rb +49 -0
- data/specs/verify_callbacks.rb +42 -0
- data/sty/galaaz.sty +0 -0
- data/version.rb +1 -1
- metadata +239 -71
- data/blogs/galaaz_ggplot/galaaz_ggplot.aux +0 -41
- data/blogs/galaaz_ggplot/galaaz_ggplot.html +0 -705
- data/blogs/galaaz_ggplot/galaaz_ggplot.out +0 -10
- data/blogs/galaaz_ggplot/galaaz_ggplot.pdf +0 -0
- data/blogs/galaaz_ggplot/galaaz_ggplot_files/figure-latex/midwest_rb.pdf +0 -0
- data/blogs/galaaz_ggplot/galaaz_ggplot_files/figure-latex/scatter_plot_rb.pdf +0 -0
- data/blogs/galaaz_ggplot/midwest.html +0 -188
- data/blogs/gknit/gknit.html +0 -2266
- data/blogs/gknit/gknit.pdf +0 -0
- data/blogs/gknit/gknit.tex +0 -1358
- data/blogs/manual/graph.rb +0 -29
- data/blogs/manual/manual.html +0 -2995
- data/blogs/manual/manual.pdf +0 -0
- data/blogs/manual/manual_files/figure-latex/diverging_bar.pdf +0 -0
- data/blogs/nse_dplyr/nse_dplyr.html +0 -960
- data/blogs/nse_dplyr/nse_dplyr.pdf +0 -0
- data/blogs/nse_dplyr/nse_dplyr.tex +0 -1373
- data/blogs/oh_my/oh_my.html +0 -680
- data/blogs/ruby_plot/ruby_plot.Rmd_external_figs +0 -662
- data/blogs/ruby_plot/ruby_plot.html +0 -729
- data/blogs/ruby_plot/ruby_plot.pdf +0 -0
- data/blogs/ruby_plot/ruby_plot_files/figure-html/dose_len.svg +0 -57
- data/blogs/ruby_plot/ruby_plot_files/figure-html/facet_by_delivery.svg +0 -106
- data/blogs/ruby_plot/ruby_plot_files/figure-html/facet_by_dose.svg +0 -110
- data/blogs/ruby_plot/ruby_plot_files/figure-html/facets_by_delivery_color.svg +0 -174
- data/blogs/ruby_plot/ruby_plot_files/figure-html/facets_by_delivery_color2.svg +0 -236
- data/blogs/ruby_plot/ruby_plot_files/figure-html/facets_with_jitter.svg +0 -296
- data/blogs/ruby_plot/ruby_plot_files/figure-html/facets_with_points.svg +0 -236
- data/blogs/ruby_plot/ruby_plot_files/figure-html/final_box_plot.svg +0 -218
- data/blogs/ruby_plot/ruby_plot_files/figure-html/final_violin_plot.svg +0 -128
- data/blogs/ruby_plot/ruby_plot_files/figure-html/violin_with_jitter.svg +0 -150
- data/examples/paper/paper.rb +0 -36
- data/specs/r_dataframe.spec.rb +0 -379
- data/specs/r_environment.spec.rb +0 -140
- data/specs/r_formula.spec.rb +0 -232
- data/specs/r_language.spec.rb +0 -112
- data/specs/r_list.spec.rb +0 -293
- data/specs/r_plots.spec.rb +0 -72
- data/specs/ruby_expression.spec.rb +0 -315
|
@@ -3,8 +3,8 @@ title: "Non Standard Evaluation in dplyr with Galaaz"
|
|
|
3
3
|
author:
|
|
4
4
|
- "Rodrigo Botafogo"
|
|
5
5
|
- "Daniel Mossé - University of Pittsburgh"
|
|
6
|
-
tags: [Tech, Data Science, Ruby, R,
|
|
7
|
-
date: "10/05/2019"
|
|
6
|
+
tags: [Tech, Data Science, Ruby, R, JRuby, "GNU R", Galaaz, dplyr]
|
|
7
|
+
date: "10/05/2019 (narrative updated for Galaaz 2.0, 2026)"
|
|
8
8
|
output:
|
|
9
9
|
html_document:
|
|
10
10
|
self_contained: true
|
|
@@ -21,80 +21,104 @@ fontsize: 11pt
|
|
|
21
21
|
---
|
|
22
22
|
|
|
23
23
|
```{r setup, echo=FALSE, message = FALSE}
|
|
24
|
+
#R.options(crayon__enabled: false)
|
|
25
|
+
options(crayon.enabled = FALSE)
|
|
24
26
|
library('dplyr')
|
|
25
27
|
library('tibble')
|
|
26
28
|
```
|
|
27
29
|
|
|
28
30
|
# Introduction
|
|
29
31
|
|
|
30
|
-
|
|
32
|
+
According to Steven Sagaert’s answer on Quora about “Is programming language R overrated?”:
|
|
31
33
|
|
|
32
|
-
|
|
34
|
+
> R is a sophisticated language with an unusual (i.e. non-mainstream) set of features. It‘s
|
|
35
|
+
> an impure functional programming language with sophisticated metaprogramming and 3
|
|
36
|
+
> different OO systems.
|
|
37
|
+
|
|
38
|
+
> Just like common lisp you can completely customise how things work via metaprogramming.
|
|
39
|
+
> The biggest example is the tidyverse: by creating it’s own evaluation system (tidyeval)
|
|
40
|
+
> was able to create a custom syntax for dplyr.
|
|
41
|
+
|
|
42
|
+
> Mastering R (the language) and its ecosystem is not a matter of weeks or months but
|
|
43
|
+
> takes years. The rabbit hole goes pretty deep…
|
|
44
|
+
|
|
45
|
+
Although a highly configurable language can give programmers a great deal of power,
|
|
46
|
+
it can also take years to master—as noted above. Programming with _dplyr_, for instance,
|
|
47
|
+
means learning evaluation rules that are not always approachable for **statisticians and
|
|
48
|
+
analysts who are not full-time software engineers**. That is not a criticism: R was **built**
|
|
49
|
+
for **statisticians** who need trustworthy results on a deadline, not necessarily for building
|
|
50
|
+
large applications.
|
|
51
|
+
|
|
52
|
+
**Unfortunately**, when such a user moves on to more **sophisticated** programming patterns,
|
|
53
|
+
the learning curve can become a real hurdle.
|
|
54
|
+
|
|
55
|
+
In this post we will see how to program with _dplyr_ in Galaaz and how Ruby can simplify
|
|
56
|
+
the learning curve of mastering _dplyr_ coding.
|
|
57
|
+
|
|
58
|
+
# But first, what is Galaaz??
|
|
33
59
|
|
|
34
60
|
Galaaz is a system for tightly coupling Ruby and R. Ruby is a powerful language, with
|
|
35
|
-
a large community, a very large set of libraries and great for web development.
|
|
61
|
+
a large community, a very large set of libraries and great for web development. It is also
|
|
62
|
+
easy to learn. However,
|
|
36
63
|
it lacks libraries for data science, statistics, scientific plotting and machine learning.
|
|
37
64
|
On the other hand, R is considered one of the most powerful languages for solving all of the
|
|
38
|
-
above problems.
|
|
39
|
-
|
|
65
|
+
above problems. **Python** is a strong competitor, with NumPy, pandas, SciPy, scikit-learn,
|
|
66
|
+
and **many thousands** of other packages on PyPI. We will not dwell on R **versus** Python here:
|
|
67
|
+
both are excellent languages with different strengths.
|
|
68
|
+
Our interest is to bring to yet another excellent language, Ruby, the data science libraries
|
|
69
|
+
that it lacks.
|
|
40
70
|
|
|
41
71
|
With Galaaz we do not intend to re-implement any of the scientific libraries in R. However, we
|
|
42
72
|
allow for very tight coupling between the two languages to the point that the Ruby
|
|
43
73
|
developer does not need to know that there is an R engine running. Also, from the point of
|
|
44
|
-
view of the R user/developer Galaaz looks a lot like R, with just minor syntactic difference,
|
|
45
|
-
so there is almost no learning
|
|
46
|
-
post
|
|
74
|
+
view of the R user/developer, Galaaz looks a lot like R, with just minor syntactic difference,
|
|
75
|
+
so there is almost no learning curve for the R developer. And as we will see in this
|
|
76
|
+
post that programming with _dplyr_ is easier in Galaaz than in R.
|
|
47
77
|
|
|
48
|
-
R users are probably quite knowledgeable about _dplyr_
|
|
78
|
+
R users are probably quite knowledgeable about _dplyr_. For the Ruby developer, _dplyr_ and
|
|
49
79
|
the _tidyverse_ libraries are a set of libraries for data manipulation in R, developed by
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
For the coupling of Ruby and R
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
* “That library is not available in my language. I need to rewrite it.”
|
|
74
|
-
* “That language would be the perfect fit for my problem, but we cannot
|
|
75
|
-
run it in our environment.”
|
|
76
|
-
* “That problem is already solved in my language, but the language is
|
|
77
|
-
too slow.”
|
|
78
|
-
|
|
79
|
-
With GraalVM we aim to allow developers to freely choose the right language
|
|
80
|
-
for the task at hand without making compromises.
|
|
81
|
-
|
|
82
|
-
Interested readers should also check out the following sites:
|
|
83
|
-
|
|
84
|
-
* [GraalVM Home](https://www.graalvm.org/)
|
|
85
|
-
* [TruffleRuby](https://github.com/oracle/truffleruby)
|
|
86
|
-
* [FastR](https://github.com/oracle/fastr)
|
|
87
|
-
* [Faster R with FastR](https://medium.com/graalvm/faster-r-with-fastr-4b8db0e0dceb)
|
|
88
|
-
* [How to make Beautiful Ruby Plots with Galaaz](https://medium.freecodecamp.org/how-to-make-beautiful-ruby-plots-with-galaaz-320848058857)
|
|
89
|
-
* [Ruby Plotting with Galaaz: An example of tightly coupling Ruby and R in GraalVM](https://towardsdatascience.com/ruby-plotting-with-galaaz-an-example-of-tightly-coupling-ruby-and-r-in-graalvm-520b69e21021)
|
|
90
|
-
* [How to do reproducible research in Ruby with gKnit](https://towardsdatascience.com/how-to-do-reproducible-research-in-ruby-with-gknit-c26d2684d64e)
|
|
91
|
-
* [R for Data Science](https://r4ds.had.co.nz/)
|
|
92
|
-
* [Advanced R](https://adv-r.hadley.nz/)
|
|
80
|
+
Hadley Wickham, Chief Scientist at Posit (formerly RStudio) and a prolific R coder and writer.
|
|
81
|
+
|
|
82
|
+
For the coupling of Ruby and R, **Galaaz 2.0** uses **[JRuby](https://www.jruby.org/)** (Ruby on the JVM)
|
|
83
|
+
together with **GNU R**. A **bridge** sends expressions and data between Ruby and an R process so that
|
|
84
|
+
Ruby can call **dplyr** and the rest of the tidyverse as if they were part of the same workflow.
|
|
85
|
+
An **earlier** Galaaz line of work used Oracle’s **GraalVM** with **TruffleRuby** and **FastR** in a single
|
|
86
|
+
runtime; that approach is **no longer** the supported stack—see the project **manual** for setup,
|
|
87
|
+
**`bin/galaaz-jruby`**, and **gKnit**.
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
# Tidyverse and dplyr
|
|
91
|
+
|
|
92
|
+
In [What is the tidyverse?](https://rviews.rstudio.com/2017/06/08/what-is-the-tidyverse/) the
|
|
93
|
+
tidyverse is explained as follows:
|
|
94
|
+
|
|
95
|
+
> The tidyverse is a coherent system of packages for data manipulation, exploration and
|
|
96
|
+
> visualization that share a common design philosophy. These were mostly developed by
|
|
97
|
+
> Hadley Wickham himself, but they are now being expanded by several contributors. Tidyverse
|
|
98
|
+
> packages are intended to make statisticians and data scientists more productive by
|
|
99
|
+
> guiding them through workflows that facilitate communication, and result in reproducible
|
|
100
|
+
> work products. Fundamentally, the tidyverse is about the connections between the tools
|
|
101
|
+
> that make the workflow possible.
|
|
93
102
|
|
|
94
|
-
|
|
103
|
+
_dplyr_ is one of the many packages that are part of the tidyverse. It is:
|
|
95
104
|
|
|
96
|
-
|
|
97
|
-
|
|
105
|
+
> a grammar of data manipulation, providing a consistent set of verbs that help you solve
|
|
106
|
+
> the most common data manipulation challenges:
|
|
107
|
+
|
|
108
|
+
> 1. mutate() adds new variables that are functions of existing variables
|
|
109
|
+
> 2. select() picks variables based on their names.
|
|
110
|
+
> 3. filter() picks cases based on their values.
|
|
111
|
+
> 4. summarise() reduces multiple values down to a single summary.
|
|
112
|
+
> 5. arrange() changes the ordering of the rows.
|
|
113
|
+
|
|
114
|
+
Very often R is used interactively and users use _dplyr_ to manipulate a single dataset
|
|
115
|
+
without programming. When users want to replicate their work for
|
|
116
|
+
multiple datasets, programming becomes necessary.
|
|
117
|
+
|
|
118
|
+
# Programming with dplyr
|
|
119
|
+
|
|
120
|
+
In the vignette ["Programming with dplyr"](https://dplyr.tidyverse.org/articles/programming.html),
|
|
121
|
+
Hadley Wickham states:
|
|
98
122
|
|
|
99
123
|
> Most dplyr functions use non-standard evaluation (NSE). This is a catch-all term that
|
|
100
124
|
> means they don’t follow the usual R rules of evaluation. Instead, they capture the
|
|
@@ -109,6 +133,8 @@ by Hardley Wickham. In it, Hardley states:
|
|
|
109
133
|
> database backends because dplyr itself doesn’t do any work, but instead generates the SQL
|
|
110
134
|
> that tells the database what to do.
|
|
111
135
|
|
|
136
|
+
But then he goes on:
|
|
137
|
+
|
|
112
138
|
> Unfortunately these benefits do not come for free. There are two main drawbacks:
|
|
113
139
|
|
|
114
140
|
> Most dplyr arguments are not referentially transparent. That means you can’t replace a value
|
|
@@ -132,8 +158,27 @@ filter(df, my_var == 1)
|
|
|
132
158
|
```
|
|
133
159
|
> This makes it hard to create functions with arguments that change how dplyr verbs are computed.
|
|
134
160
|
|
|
135
|
-
|
|
136
|
-
|
|
161
|
+
As a result of this, programming with _dplyr_ requires learning a set of new ideas and concepts.
|
|
162
|
+
In this vignette Hadley goes on showing how to program ever more difficult problems with _dplyr_,
|
|
163
|
+
showing the problems it faces and the new concepts needed to solve them.
|
|
164
|
+
|
|
165
|
+
In this blog, we will look at all the problems presented by Harley on the vignette and show how
|
|
166
|
+
those same problems can be solved using Galaaz and the Ruby language.
|
|
167
|
+
|
|
168
|
+
This blog is organized as follows: first we show how to write expressions using Galaaz.
|
|
169
|
+
Expressions are a fundamental concept in _dplyr_ and are not part of basic Ruby. We extend
|
|
170
|
+
the Ruby language create a manipulate expressions that will be used by _dplyr_ functions.
|
|
171
|
+
|
|
172
|
+
Then we show very succintly how Ruby and R can be integrated and how R functions are
|
|
173
|
+
transparently called from Ruby. Galaaz [user manual](https://github.com/rbotafogo/galaaz/wiki)
|
|
174
|
+
(still in development) goes in much deeper detail about this integration.
|
|
175
|
+
|
|
176
|
+
Next in section "Data manipulation wiht _dplyr_" we go through all the problems on the
|
|
177
|
+
_dplyr_ vignette and look at how they are solved in Galaaz. We then discuss why programming
|
|
178
|
+
with Galaaz and _dplyr_ is easier than programming with _dplyr_ in plain R.
|
|
179
|
+
|
|
180
|
+
The following section looks at another more advanced problem and shows that Galaaz can still
|
|
181
|
+
handle it without any difficulty. We then provide further reading and concluding remarks.
|
|
137
182
|
|
|
138
183
|
# Writing Expressions in Galaaz
|
|
139
184
|
|
|
@@ -142,37 +187,55 @@ Galaaz extends Ruby to work with expressions, similar to R's expressions build w
|
|
|
142
187
|
formulae. For instance, in mathematics, the expression $y = sin(x)$ describes a function but cannot
|
|
143
188
|
be computed unless the value of $x$ is bound to some value.
|
|
144
189
|
|
|
145
|
-
|
|
190
|
+
Expressions are fundamental in _dplyr_ programming as they are the input to _dplyr_ functions,
|
|
191
|
+
for instance, as we will see shortly, if a data frame has a column named 'x' and we want
|
|
192
|
+
to add another column, y, to this dataframe that has the values of 'x' times 2, then we would
|
|
193
|
+
call a _dplyr_ function with the expression 'y = x * 2'.
|
|
194
|
+
|
|
195
|
+
## A note on notation
|
|
196
|
+
|
|
197
|
+
This blog was written in Rmarkdown and automatically converted to HTML or PDF (depending on
|
|
198
|
+
where you are reading this blog) with gKnit (a tool provided by Galaaz). In Rmarkdown, it is
|
|
199
|
+
possible to write text and code blocks that are executed to generate the final report. Code
|
|
200
|
+
blocks appear inside a 'box' and the result of their execution appear either in another type
|
|
201
|
+
of 'box' with a different background (HTML) or as normal text (PDF). Every output line from
|
|
202
|
+
the code execution is preceded by '##'.
|
|
146
203
|
|
|
147
204
|
## Expressions from operators
|
|
148
205
|
|
|
149
|
-
The code
|
|
150
|
-
are not bound to any
|
|
206
|
+
The code below creates an expression summing two symbols. Note that :a and :b are Ruby symbols and
|
|
207
|
+
are not bound to any values at the time of expression definition:
|
|
151
208
|
|
|
152
209
|
```{ruby expressions}
|
|
153
210
|
exp1 = :a + :b
|
|
154
211
|
puts exp1
|
|
155
212
|
```
|
|
156
|
-
|
|
213
|
+
In Galaaz, we can build any complex mathematical expression such as:
|
|
157
214
|
|
|
158
215
|
```{ruby expr2}
|
|
159
|
-
exp2 = (:a + :b) * 2.0 + :c ** 2 / :z
|
|
216
|
+
exp2 = (R[:a] + R[:b]) * 2.0 + R[:c] ** 2 / R[:z]
|
|
160
217
|
puts exp2
|
|
161
218
|
```
|
|
162
|
-
|
|
219
|
+
Expressions are printed with the same format as the equivalent R expressions. The 'L' after
|
|
220
|
+
2 indicates that 2 is an integer.
|
|
221
|
+
|
|
222
|
+
The R developer should note that in R, if she writes the
|
|
223
|
+
number '2', the R interpreter will convert it to float. In order to get an interger she
|
|
224
|
+
should write '2L'. Galaaz follows Ruby notation and '2' is an integer, while '2.0' is a
|
|
225
|
+
float.
|
|
163
226
|
|
|
164
227
|
It is also possible to use inequality operators in building expressions:
|
|
165
228
|
|
|
166
229
|
```{ruby expr3}
|
|
167
|
-
exp3 = (:a + :b) >= :z
|
|
230
|
+
exp3 = (R[:a] + R[:b]) >= R[:z]
|
|
168
231
|
puts exp3
|
|
169
232
|
```
|
|
170
233
|
Expressions' definition can also make use of normal Ruby variables without any problem:
|
|
171
234
|
|
|
172
235
|
```{ruby expr_with_var}
|
|
173
236
|
x = 20
|
|
174
|
-
y = 30
|
|
175
|
-
exp_var = (:a + :b) * x <= :z - y
|
|
237
|
+
y = 30.0
|
|
238
|
+
exp_var = (R[:a] + R[:b]) * x <= R[:z] - y
|
|
176
239
|
puts exp_var
|
|
177
240
|
```
|
|
178
241
|
|
|
@@ -181,75 +244,82 @@ notation for those operators such as (.gt, .ge, etc.). So the same expression w
|
|
|
181
244
|
above can also be written as
|
|
182
245
|
|
|
183
246
|
```{ruby expr4}
|
|
184
|
-
exp4 = (:a + :b).ge :z
|
|
247
|
+
exp4 = (R[:a] + R[:b]).ge R[:z]
|
|
185
248
|
puts exp4
|
|
186
249
|
```
|
|
187
250
|
|
|
188
|
-
Two
|
|
189
|
-
of the operators
|
|
190
|
-
|
|
191
|
-
|
|
251
|
+
Two types of expressions, however, can only be created with the functional representation
|
|
252
|
+
of the operators. Those are expressions involving '==', and '='. This is the case since
|
|
253
|
+
those symbols have special meaning in Ruby and should not be redefined.
|
|
254
|
+
|
|
255
|
+
In order to write an expression involving '==' we
|
|
256
|
+
need to use the method '.eq' and for '=' we need the function '.assign':
|
|
192
257
|
|
|
193
258
|
```{ruby expr5}
|
|
194
|
-
exp5 = (:a + :b).eq :z
|
|
259
|
+
exp5 = (R[:a] + R[:b]).eq R[:z]
|
|
195
260
|
puts exp5
|
|
196
261
|
```
|
|
197
262
|
|
|
198
263
|
```{ruby expr6}
|
|
199
|
-
exp6 = :y.assign :a + :b
|
|
264
|
+
exp6 = R[:y].assign R[:a] + R[:b]
|
|
200
265
|
puts exp6
|
|
201
266
|
```
|
|
202
|
-
|
|
203
|
-
|
|
267
|
+
Users should be careful when writing expressions not to inadvertently use '==' or '=' as
|
|
268
|
+
this will generate an error, that might be a bit cryptic (in future releases of Galaza, we
|
|
269
|
+
plan to improve the error message).
|
|
204
270
|
|
|
205
271
|
```{ruby exp_wrong, warning=FALSE}
|
|
206
|
-
exp_wrong = (:a + :b) == :z
|
|
272
|
+
exp_wrong = (R[:a] + R[:b]) == R[:z]
|
|
207
273
|
puts exp_wrong
|
|
208
274
|
```
|
|
209
|
-
|
|
210
|
-
when using '==' we are comparing expression (:a + :b) to expression :z with '=='. When
|
|
211
|
-
comparison is executed, the system tries to evaluate :a, :b and :z, and those symbols at
|
|
212
|
-
this time are not bound to anything
|
|
213
|
-
If we only use functional notation, this type of error will not occur.
|
|
275
|
+
The problem lies with the fact that
|
|
276
|
+
when using '==' we are comparing expression (R[:a] + R[:b]) to expression R[:z] with '=='. When this
|
|
277
|
+
comparison is executed, the system tries to evaluate :a, :b and :z, and those symbols, at
|
|
278
|
+
this time, are not bound to anything giving the "object 'a' not found" message.
|
|
214
279
|
|
|
215
280
|
## Expressions with R methods
|
|
216
281
|
|
|
217
282
|
It is often necessary to create an expression that uses a method or function. For instance, in
|
|
218
283
|
mathematics, it's quite natural to write an expressin such as $y = sin(x)$. In this case, the
|
|
219
|
-
'sin' function is part of the expression and should not immediately
|
|
284
|
+
'sin' function is part of the expression and should not be immediately executed. When we want
|
|
220
285
|
the function to be part of the expression, we call the function preceeding it
|
|
221
286
|
by the letter E, such as 'E.sin(x)'
|
|
222
287
|
|
|
223
288
|
```{ruby method_expression}
|
|
224
|
-
exp7 = :y.assign E.sin(:x)
|
|
289
|
+
exp7 = R[:y].assign E.sin(R[:x])
|
|
225
290
|
puts exp7
|
|
226
291
|
```
|
|
227
|
-
|
|
228
|
-
Expressions can also be written using '.' notation:
|
|
292
|
+
Function expressions can also be written using '.' notation:
|
|
229
293
|
|
|
230
294
|
```{ruby expression_with_dot}
|
|
231
|
-
exp8 = :y.assign :x.sin
|
|
295
|
+
exp8 = R[:y].assign R[:x].sin
|
|
232
296
|
puts exp8
|
|
233
297
|
```
|
|
234
|
-
|
|
235
|
-
|
|
298
|
+
When a function has multiple arguments, the first one can be used before the '.'. For instance,
|
|
299
|
+
the R concatenate function 'c', that concatenates two or more arguments can be part of
|
|
300
|
+
an expression as:
|
|
236
301
|
|
|
237
302
|
```{ruby expression_multiple_args}
|
|
238
|
-
exp9 = :x.c(:y)
|
|
303
|
+
exp9 = R[:x].c(R[:y])
|
|
239
304
|
puts exp9
|
|
240
305
|
```
|
|
306
|
+
Note that this gives an OO feeling to the code, as if we were saying 'x' concatenates 'y'. As a
|
|
307
|
+
side note, '.' notation can be used as the R pipe operator '%>%', but is more general than the
|
|
308
|
+
pipe.
|
|
241
309
|
|
|
242
310
|
## Evaluating an Expression
|
|
243
311
|
|
|
244
|
-
|
|
245
|
-
with a
|
|
312
|
+
Although we are mainly focusing on expressions to pass them to _dplyr_ functions, expressions
|
|
313
|
+
can be evaluated by calling function 'eval' with a binding.
|
|
314
|
+
|
|
315
|
+
A binding can be provided with a list or a data frame as shown below:
|
|
246
316
|
|
|
247
317
|
```{ruby eval_expression_list}
|
|
248
|
-
exp = (:a + :b) * 2.0 + :c ** 2 / :z
|
|
318
|
+
exp = (R[:a] + R[:b]) * 2.0 + R[:c] ** 2 / R[:z]
|
|
249
319
|
puts exp.eval(R.list(a: 10, b: 20, c: 30, z: 40))
|
|
250
320
|
```
|
|
251
321
|
|
|
252
|
-
|
|
322
|
+
with a data frame:
|
|
253
323
|
|
|
254
324
|
```{ruby eval_expression_df}
|
|
255
325
|
df = R.data__frame(
|
|
@@ -269,8 +339,8 @@ this post, we do not have enough space to write a complete manual on Galaaz
|
|
|
269
339
|
(a short manual can be found at: https://www.rubydoc.info/gems/galaaz/0.4.9), so we will
|
|
270
340
|
present only a few examples scripts using Galaaz.
|
|
271
341
|
|
|
272
|
-
Basically, to call an R function from Ruby with Galaaz, one only needs to
|
|
273
|
-
with 'R.'. For instance, to create a vector in R, the 'c' function is used.
|
|
342
|
+
Basically, to call an R function from Ruby with Galaaz, one only needs to preced the function
|
|
343
|
+
with 'R.'. For instance, to create a vector in R, the 'c' function is used. In Galaaz, a
|
|
274
344
|
vector can be created by using 'R.c':
|
|
275
345
|
|
|
276
346
|
```{ruby vector}
|
|
@@ -294,32 +364,77 @@ the expression $y = sin(45^\circ)$, which is $y = 0.850...$. In this case,
|
|
|
294
364
|
we will use 'R.sin':
|
|
295
365
|
|
|
296
366
|
```{ruby eval_sin}
|
|
297
|
-
exp10 = :y.assign R.sin(45)
|
|
367
|
+
exp10 = R[:y].assign R.sin(45)
|
|
298
368
|
puts exp10
|
|
299
369
|
```
|
|
300
370
|
|
|
301
|
-
#
|
|
371
|
+
# Data manipulation wiht _dplyr_
|
|
372
|
+
|
|
373
|
+
In this section we will give a brief tour _dplyr_'s usage in Galaaz and how to manipulate
|
|
374
|
+
data in Ruby with it. This section will follow [_dplyr_'s vignette](https://dplyr.tidyverse.org/articles/dplyr.html) that explores the nycflights13 data set. This dataset contains all 336776
|
|
375
|
+
flights that departed from New York City in 2013. The data comes from the US Bureau of
|
|
376
|
+
Transportation Statistics.
|
|
377
|
+
|
|
378
|
+
Let's start by taking a look at this dataset:
|
|
379
|
+
|
|
380
|
+
```{ruby nycflights13}
|
|
381
|
+
R.library('nycflights13')
|
|
382
|
+
# check it's dimension
|
|
383
|
+
puts ~R[:flights].dim
|
|
384
|
+
# and the structure
|
|
385
|
+
~R[:flights].str
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
Now, let's use a first verb of _dplyr_: 'filter'. This verb, obviously, will filter the data
|
|
389
|
+
by the given expression. In the next block, we filter by columns 'month' and 'day'. The
|
|
390
|
+
first argument to the filter function is symbol ':flights'. A Ruby symbol, when given to
|
|
391
|
+
an R function will convert to the R variable of the same name, in this case 'flights', that
|
|
392
|
+
holds the nycflights13 data frame.
|
|
393
|
+
|
|
394
|
+
The second and third arguments are expressions that will be used by the filter function to
|
|
395
|
+
filter by columns, looking for entries in which the month and day are equal to 1.
|
|
396
|
+
|
|
397
|
+
```{ruby filter}
|
|
398
|
+
puts R.filter(:flights, (R[:month].eq 1), (R[:day].eq 1))
|
|
399
|
+
```
|
|
400
|
+
|
|
302
401
|
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
"Programming with dplyr"
|
|
402
|
+
## Programming with _dplyr_: problems and how to solve them in Galaaz
|
|
403
|
+
|
|
404
|
+
In this section we look at the list of problems that Hadley describes in the "Programming with dplyr"
|
|
405
|
+
vignette and show how those problems are solved and coded with Galaaz. Readers interested in
|
|
406
|
+
how those problems are treated in _dplyr_ should read the vignette and use it as a comparison with
|
|
407
|
+
this blog.
|
|
408
|
+
|
|
409
|
+
## Filtering using expressions
|
|
410
|
+
|
|
411
|
+
Now that we know how to write expressions and call R functions, let's do some data manipulation in
|
|
412
|
+
Galaaz. Let's first start by creating a data frame. In R, the 'data.frame' function creates a
|
|
413
|
+
data frame. In Ruby, writing 'data.frame' will not parse as a single object. To call R
|
|
414
|
+
functions that have a '.' in them, we need to substitute the '.' with '__'. So, method
|
|
415
|
+
'data.frame' in R, is called in Galaaz as 'R.data\_\_frame':
|
|
306
416
|
|
|
307
417
|
```{ruby df}
|
|
308
418
|
df = R.data__frame(x: (1..3), y: (3..1))
|
|
309
419
|
puts df
|
|
310
420
|
```
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
421
|
+
|
|
422
|
+
_dplyr_ provides the 'filter' function, that filters data in a data brame. The 'filter'
|
|
423
|
+
function can be called on this data frame either by using 'R.filter(df, ...)' or
|
|
424
|
+
by using dot notation.
|
|
425
|
+
|
|
426
|
+
-------FIX---------
|
|
427
|
+
|
|
428
|
+
We prefer to use dot notation as shown below. The argument to 'filter' should be an
|
|
429
|
+
expression. Note that if we gave to filter a Ruby expression such as
|
|
314
430
|
'x == 1', we would get an error, since there is no variable 'x' defined and if 'x' was a variable
|
|
315
431
|
then 'x == 1' would either be 'true' or 'false'. Our goal is to filter our data frame returning
|
|
316
|
-
all rows in which the 'x' value is equal to 1. To express this we want: ':x.eq 1', where :x will
|
|
432
|
+
all rows in which the 'x' value is equal to 1. To express this we want: 'R[:x].eq 1', where :x will
|
|
317
433
|
be interpreted by filter as the 'x' column.
|
|
318
434
|
|
|
319
435
|
```{ruby filter_exp}
|
|
320
|
-
puts df.filter(:x.eq 1)
|
|
436
|
+
puts df.filter(R[:x].eq 1)
|
|
321
437
|
```
|
|
322
|
-
|
|
323
438
|
In R, and when coding with 'tidyverse', arguments to a function are usually not
|
|
324
439
|
*referencially transparent*. That is, you can’t replace a value with a seemingly equivalent
|
|
325
440
|
object that you’ve defined elsewhere. In other words, this code
|
|
@@ -331,16 +446,16 @@ filter(df, my_var == 1)
|
|
|
331
446
|
Generates the following error: "object 'x' not found.
|
|
332
447
|
|
|
333
448
|
However, in Galaaz, arguments are referencially transparent as can be seen by the
|
|
334
|
-
code
|
|
449
|
+
code below. Note initially that 'my_var = R[:x]' will not give the error "object 'x' not found"
|
|
335
450
|
since ':x' is treated as an expression and assigned to my\_var. Then when doing (my\_var.eq 1),
|
|
336
|
-
my\_var is a variable that resolves to ':x' and it becomes equivalent to (:x.eq 1) which is
|
|
451
|
+
my\_var is a variable that resolves to ':x' and it becomes equivalent to (R[:x].eq 1) which is
|
|
337
452
|
what we want.
|
|
338
453
|
|
|
339
454
|
```{ruby my_var}
|
|
340
|
-
my_var = :x
|
|
455
|
+
my_var = R[:x]
|
|
341
456
|
puts df.filter(my_var.eq 1)
|
|
342
457
|
```
|
|
343
|
-
As stated by
|
|
458
|
+
As stated by Hadley
|
|
344
459
|
|
|
345
460
|
> dplyr code is ambiguous. Depending on what variables are defined where,
|
|
346
461
|
> filter(df, x == y) could be equivalent to any of:
|
|
@@ -352,9 +467,9 @@ df[x == df$y, ]
|
|
|
352
467
|
df[x == y, ]
|
|
353
468
|
```
|
|
354
469
|
In galaaz this ambiguity does not exist, filter(df, x.eq y) is not a valid expression as
|
|
355
|
-
expressions are build with symbols. In doing filter(df, :x.eq y) we are looking for elements
|
|
470
|
+
expressions are build with symbols. In doing filter(df, R[:x].eq y) we are looking for elements
|
|
356
471
|
of the 'x' column that are equal to a previously defined y variable. Finally in
|
|
357
|
-
filter(df, :x.eq :y) we are looking for elements in which the 'x' column value is equal to
|
|
472
|
+
filter(df, R[:x].eq R[:y]) we are looking for elements in which the 'x' column value is equal to
|
|
358
473
|
the 'y' column value. This can be seen in the following two chunks of code:
|
|
359
474
|
|
|
360
475
|
```{ruby disamb1}
|
|
@@ -362,15 +477,15 @@ y = 1
|
|
|
362
477
|
x = 2
|
|
363
478
|
|
|
364
479
|
# looking for values where the 'x' column is equal to the 'y' column
|
|
365
|
-
puts df.filter(:x.eq :y)
|
|
480
|
+
puts df.filter(R[:x].eq R[:y])
|
|
366
481
|
```
|
|
367
482
|
|
|
368
483
|
```{ruby disamb2}
|
|
369
484
|
# looking for values where the 'x' column is equal to the 'y' variable
|
|
370
485
|
# in this case, the number 1
|
|
371
|
-
puts df.filter(:x.eq y)
|
|
486
|
+
puts df.filter(R[:x].eq y)
|
|
372
487
|
```
|
|
373
|
-
|
|
488
|
+
## Writing a function that applies to different data sets
|
|
374
489
|
|
|
375
490
|
Let's suppose that we want to write a function that receives as the first argument a data frame
|
|
376
491
|
and as second argument an expression that adds a column to the data frame that is equal to the
|
|
@@ -395,11 +510,12 @@ Unfortunately, in R, this function can fail silently if one of the variables isn
|
|
|
395
510
|
in the data frame, but is present in the global environment. We will not go through here how
|
|
396
511
|
to solve this problem in R.
|
|
397
512
|
|
|
398
|
-
In Galaaz the method mutate_y
|
|
513
|
+
In Galaaz the method mutate_y below will work fine and will never fail silently.
|
|
399
514
|
|
|
400
515
|
```{ruby mutate_y, warning=FALSE}
|
|
401
516
|
def mutate_y(df)
|
|
402
|
-
|
|
517
|
+
# Mutate column names are Ruby kwargs (y: …). Use .assign only for R `<-` expressions.
|
|
518
|
+
df.mutate(y: R[:a] + R[:x])
|
|
403
519
|
end
|
|
404
520
|
```
|
|
405
521
|
Here we create a data frame that has only one column named 'x':
|
|
@@ -410,18 +526,18 @@ puts df1
|
|
|
410
526
|
```
|
|
411
527
|
|
|
412
528
|
Note that method mutate_y will fail independetly from the fact that variable 'a' is defined and
|
|
413
|
-
in the scope of the method. Variable 'a' has no relationship with the symbol
|
|
529
|
+
in the scope of the method. Variable 'a' has no relationship with the symbol `R[:a]` used in the
|
|
414
530
|
definition of 'mutate\_y' above:
|
|
415
531
|
|
|
416
532
|
```{ruby call_mutate_y, warning = FALSE}
|
|
417
533
|
a = 10
|
|
418
534
|
mutate_y(df1)
|
|
419
535
|
```
|
|
420
|
-
|
|
536
|
+
## Different expressions
|
|
421
537
|
|
|
422
|
-
Let's move to the next problem as presented by
|
|
538
|
+
Let's move to the next problem as presented by Hadley where trying to write a function in R
|
|
423
539
|
that will receive two argumens, the first a variable and the second an expression is not trivial.
|
|
424
|
-
|
|
540
|
+
Below we create a data frame and we want to write a function that groups data by a variable and
|
|
425
541
|
summarises it by an expression:
|
|
426
542
|
|
|
427
543
|
```{r diff_expr}
|
|
@@ -434,13 +550,13 @@ df <- data.frame(
|
|
|
434
550
|
b = sample(5)
|
|
435
551
|
)
|
|
436
552
|
|
|
437
|
-
as.data.frame(df)
|
|
553
|
+
as.data.frame(df)
|
|
438
554
|
|
|
439
555
|
d2 <- df %>%
|
|
440
556
|
group_by(g1) %>%
|
|
441
557
|
summarise(a = mean(a))
|
|
442
558
|
|
|
443
|
-
as.data.frame(d2)
|
|
559
|
+
as.data.frame(d2)
|
|
444
560
|
|
|
445
561
|
d2 <- df %>%
|
|
446
562
|
group_by(g2) %>%
|
|
@@ -449,7 +565,7 @@ d2 <- df %>%
|
|
|
449
565
|
as.data.frame(d2)
|
|
450
566
|
```
|
|
451
567
|
|
|
452
|
-
As shown by
|
|
568
|
+
As shown by Hadley, one might expect this function to do the trick:
|
|
453
569
|
|
|
454
570
|
```{r diff_exp_fnc}
|
|
455
571
|
my_summarise <- function(df, group_var) {
|
|
@@ -464,40 +580,40 @@ my_summarise <- function(df, group_var) {
|
|
|
464
580
|
|
|
465
581
|
In order to solve this problem, coding with dplyr requires the introduction of many new concepts
|
|
466
582
|
and functions such as 'quo', 'quos', 'enquo', 'enquos', '!!' (bang bang), '!!!' (triple bang).
|
|
467
|
-
Again, we'll leave to
|
|
583
|
+
Again, we'll leave to Hadley the explanation on how to use all those functions.
|
|
468
584
|
|
|
469
585
|
Now, let's try to implement the same function in galaaz. The next code block first prints the
|
|
470
|
-
'df' data frame
|
|
586
|
+
'df' data frame defined previously in R (to access an R variable from Galaaz, we use the tilde
|
|
471
587
|
operator '~' applied to the R variable name as symbol, i.e., ':df'. We then create the
|
|
472
588
|
'my_summarize' method and call it passing the R data frame and the group by variable ':g1':
|
|
473
589
|
|
|
474
590
|
```{ruby diff_exp_ruby_func}
|
|
475
|
-
puts
|
|
591
|
+
puts ~R[:df]
|
|
476
592
|
print "\n"
|
|
477
593
|
|
|
478
594
|
def my_summarize(df, group_var)
|
|
479
595
|
df.group_by(group_var).
|
|
480
|
-
summarize(a: :a.mean)
|
|
596
|
+
summarize(a: R[:a].mean)
|
|
481
597
|
end
|
|
482
598
|
|
|
483
|
-
puts my_summarize(:df, :g1)
|
|
599
|
+
puts my_summarize(~R[:df], R[:g1])
|
|
484
600
|
```
|
|
485
601
|
It works!!! Well, let's make sure this was not just some coincidence
|
|
486
602
|
|
|
487
603
|
```{ruby group_g2}
|
|
488
|
-
puts my_summarize(:df, :g2)
|
|
604
|
+
puts my_summarize(~R[:df], R[:g2])
|
|
489
605
|
```
|
|
490
606
|
|
|
491
607
|
Great, everything is fine! No magic, no new functions, no complexities, just normal, standard Ruby
|
|
492
608
|
code. If you've ever done NSE in R, this certainly feels much safer and easy to implement.
|
|
493
609
|
|
|
494
|
-
|
|
610
|
+
## Different input variables
|
|
495
611
|
|
|
496
612
|
In the previous section we've managed to get rid of all NSE formulation for a simple example, but
|
|
497
613
|
does this remain true for more complex examples, or will the Galaaz way prove inpractical for
|
|
498
614
|
more complex code?
|
|
499
615
|
|
|
500
|
-
In the next example
|
|
616
|
+
In the next example Hadley proposes us to write a function that given an expression such as 'a'
|
|
501
617
|
or 'a * b', calculates three summaries. What we want a function that does the same as these R
|
|
502
618
|
statements:
|
|
503
619
|
|
|
@@ -526,16 +642,16 @@ def my_summarise2(df, expr)
|
|
|
526
642
|
)
|
|
527
643
|
end
|
|
528
644
|
|
|
529
|
-
puts my_summarise2((
|
|
530
|
-
puts my_summarise2((
|
|
645
|
+
puts my_summarise2((~R[:df]), :a)
|
|
646
|
+
puts my_summarise2((~R[:df]), R[:a] * R[:b])
|
|
531
647
|
```
|
|
532
648
|
|
|
533
649
|
Once again, there is no need to use any special theory or functions. The only point to be
|
|
534
650
|
careful about is the use of 'E' to build expressions from functions 'mean', 'sum' and 'n'.
|
|
535
651
|
|
|
536
|
-
|
|
652
|
+
## Different input and output variable
|
|
537
653
|
|
|
538
|
-
Now the next challenge presented by
|
|
654
|
+
Now the next challenge presented by Hadley is to vary the name of the output variables based on
|
|
539
655
|
the received expression. So, if the input expression is 'a', we want our data frame columns to
|
|
540
656
|
be named 'mean\_a' and 'sum\_a'. Now, if the input expression is 'b', columns
|
|
541
657
|
should be named 'mean\_b' and 'sum\_b'.
|
|
@@ -561,7 +677,7 @@ mutate(df, mean_b = mean(b), sum_b = sum(b))
|
|
|
561
677
|
#> 4 2 2 5 4 3 15
|
|
562
678
|
#> # … with 1 more row
|
|
563
679
|
```
|
|
564
|
-
In order to solve this problem in R,
|
|
680
|
+
In order to solve this problem in R, Hadley needs to introduce some more new functions and notations:
|
|
565
681
|
'quo_name' and the ':=' operator from package 'rlang'
|
|
566
682
|
|
|
567
683
|
Here is our Ruby code:
|
|
@@ -575,8 +691,8 @@ def my_mutate(df, expr)
|
|
|
575
691
|
sum_name => E.sum(expr))
|
|
576
692
|
end
|
|
577
693
|
|
|
578
|
-
puts my_mutate((
|
|
579
|
-
puts my_mutate((
|
|
694
|
+
puts my_mutate((~R[:df]), :a)
|
|
695
|
+
puts my_mutate((~R[:df]), :b)
|
|
580
696
|
```
|
|
581
697
|
It really seems that "Non Standard Evaluation" is actually quite standard in Galaaz! But, you
|
|
582
698
|
might have noticed a small change in the way the arguments to the mutate method were called.
|
|
@@ -586,9 +702,9 @@ and variable mean\_name is not followed by ':' but by '=>'. This is standard Ru
|
|
|
586
702
|
|
|
587
703
|
[explain....]
|
|
588
704
|
|
|
589
|
-
|
|
705
|
+
## Capturing multiple variables
|
|
590
706
|
|
|
591
|
-
Moving on with new complexities,
|
|
707
|
+
Moving on with new complexities, Hadley proposes us to solve the problem in which the
|
|
592
708
|
summarise function will receive any number of grouping variables.
|
|
593
709
|
|
|
594
710
|
This again is quite standard Ruby. In order to receive an undefined number of paramenters
|
|
@@ -600,7 +716,7 @@ def my_summarise3(df, *group_vars)
|
|
|
600
716
|
summarise(a: E.mean(:a))
|
|
601
717
|
end
|
|
602
718
|
|
|
603
|
-
puts my_summarise3((
|
|
719
|
+
puts my_summarise3((~R[:df]), :g1, :g2)
|
|
604
720
|
```
|
|
605
721
|
|
|
606
722
|
# Why does R require NSE and Galaaz does not?
|
|
@@ -618,7 +734,7 @@ In Ruby, there is no lazy evaluation of parameters and 'a' is always a variable
|
|
|
618
734
|
Variables assume their value as soon as they are used, so 'x = a' is immediately evaluate and
|
|
619
735
|
variable 'x' will receive the value of variable 'a' as soon as the Ruby statement is executed.
|
|
620
736
|
Ruby also provides the notion of a symbol; ':a' is a symbol and does not evaluate to anything.
|
|
621
|
-
Galaaz uses Ruby symbols to build expressions that are not bound to anything: ':a.eq :b' is
|
|
737
|
+
Galaaz uses Ruby symbols to build expressions that are not bound to anything: 'R[:a].eq R[:b]' is
|
|
622
738
|
clearly an expression and has no relationship whatsoever with the statment 'a = b'. By using
|
|
623
739
|
symbols, variables and expressions all the possible ambiguities that are found in R are
|
|
624
740
|
eliminated in Galaaz.
|
|
@@ -628,12 +744,12 @@ of input they are expecting, they might be expecting regular variables or they m
|
|
|
628
744
|
expecting expressions and the R function will know how to deal with an input of the form
|
|
629
745
|
'a = b', now for the Ruby developer it might not be immediately clear if it should call the
|
|
630
746
|
function passing the value 'true' if variable 'a' is equal to variable 'b' or if it should
|
|
631
|
-
call the function passing the expression ':a.eq :b'.
|
|
747
|
+
call the function passing the expression 'R[:a].eq R[:b]'.
|
|
632
748
|
|
|
633
749
|
|
|
634
750
|
# Advanced dplyr features
|
|
635
751
|
|
|
636
|
-
In the blog: Programming with dplyr by using dplyr
|
|
752
|
+
In the blog: [Programming with dplyr by using dplyr](https://www.r-bloggers.com/programming-with-dplyr-by-using-dplyr/) Iñaki Úcar shows surprise that some R users are trying to code in dplyr avoiding
|
|
637
753
|
the use of NSE. For instance he says:
|
|
638
754
|
|
|
639
755
|
> Take the example of seplyr. It stands for standard evaluation dplyr, and enables us to
|
|
@@ -651,9 +767,9 @@ In the following examples, we show the use of functions 'group\_by\_at', 'summar
|
|
|
651
767
|
features of characters in the Starwars movies:
|
|
652
768
|
|
|
653
769
|
```{ruby starwars}
|
|
654
|
-
puts (
|
|
770
|
+
puts (~R[:starwars]).head
|
|
655
771
|
```
|
|
656
|
-
The grouped_mean function
|
|
772
|
+
The grouped_mean function below will receive a grouping variable and calculate summaries for
|
|
657
773
|
the value\_variables given:
|
|
658
774
|
|
|
659
775
|
```{r grouped_mean}
|
|
@@ -678,13 +794,23 @@ def grouped_mean(data, grouping_variables, value_variables)
|
|
|
678
794
|
data.
|
|
679
795
|
group_by_at(grouping_variables).
|
|
680
796
|
mutate(count: E.n).
|
|
681
|
-
summarise_at(E.c(value_variables, "count"),
|
|
797
|
+
summarise_at(E.c(value_variables, "count"), R[:mean], na__rm: true).
|
|
682
798
|
rename_at(value_variables, E.funs(E.paste0("mean_", value_variables)))
|
|
683
799
|
end
|
|
684
800
|
|
|
685
|
-
puts grouped_mean((
|
|
801
|
+
puts grouped_mean((~R[:starwars]), "eye_color", E.c("mass", "birth_year"))
|
|
686
802
|
```
|
|
687
803
|
|
|
804
|
+
# Further reading
|
|
805
|
+
|
|
806
|
+
* [JRuby](https://www.jruby.org/) — Ruby on the JVM (Galaaz 2.0)
|
|
807
|
+
* [How to make Beautiful Ruby Plots with Galaaz](https://medium.freecodecamp.org/how-to-make-beautiful-ruby-plots-with-galaaz-320848058857) (plots; narrative partly pre-2.0)
|
|
808
|
+
* [Ruby Plotting with Galaaz in GraalVM](https://towardsdatascience.com/ruby-plotting-with-galaaz-an-example-of-tightly-coupling-ruby-and-r-in-graalvm-520b69e21021) (older stack; ideas still useful)
|
|
809
|
+
* [How to do reproducible research in Ruby with gKnit](https://towardsdatascience.com/how-to-do-reproducible-research-in-ruby-with-gknit-c26d2684d64e)
|
|
810
|
+
* [R for Data Science](https://r4ds.had.co.nz/)
|
|
811
|
+
* [Advanced R](https://adv-r.hadley.nz/)
|
|
812
|
+
* Historical context: [GraalVM](https://www.graalvm.org/), [TruffleRuby](https://github.com/oracle/truffleruby), [FastR](https://github.com/oracle/fastr)
|
|
813
|
+
|
|
688
814
|
# Conclusion
|
|
689
815
|
|
|
690
816
|
Ruby and Galaaz provide a nice framework for developing code that uses R functions. Although R is
|