提供一個在Nodejs中呼叫 R script 方法。我用的node框架是 eggjs,示例程式碼全是在Egg環境下實現的。你將會看到以前幾個方面的內容。
- R 簡介與在Node中呼叫R Script 的原因
- 相關環境的搭建與關鍵Node知識點
- 呼叫方式與相關程式碼
一、R 簡介與在Node中呼叫R Script 的原因
R是用於統計分析、繪圖的語言和操作環境。R是屬於GNU系統的一個自由、免費、原始碼開放的軟體,它是一個用於統計計算和統計製圖的優秀工具。簡單一下,應該要坐這樣操作的人都知道這種必備的背景知識。
需要在呼叫 Node 中呼叫 R Script,是因為應用中需要對比較複雜的計算公式做翻譯,其中會涉及到三角函式,開方或者求冪等數學運算。而直接用 Javascript 翻譯後,在公式計算過程中會因為精度的問題導致整個計算結果異常。具體表現如,Math.tan 結果為0.000000000000001等此類計算結果。
大家搜尋同類問題的時候,肯定看到排名靠前的 r-script、node-rscript、js-cal-r、rscript這些packages。他們寫的肯定是可以用的。燃鵝,具體實現的時候可能想到複雜,比如你的是一個長度在一萬的Json陣列,或者你的R Script在R studio中執行一切如常偏偏在node中呼叫就報錯,甚至你用packeage page上的示例程式碼都報錯。總之情況可能非常複雜。
二、相關環境的搭建與關鍵Node知識點
2.1 相關環境搭建
首先肯定機器上肯定需要搭建 Node 環境 和 R 的環境,node 環境就不給介紹了。如果你恰好也用的是Eggjs請參照官網。
R 環境則只需要安裝最新的 R 安裝包就可以了。目前最新的版本R version 3.5.1。官網 在官網如下位置。
安裝好了之後需要配置系統環境變數,移動要配置。這一步非常重要。
在系統便利中將bin
,include
兩個路徑加入到系統變數 Path 中,根據自己的安裝路徑,我是安裝在C盤所以路徑如下
C:\Program Files\R\R-3.5.1\bin
C:\Program Files\R\R-3.5.1\include
複製程式碼
2.2 Nodejs 知識點
其實,在 node 中呼叫 R script 的實現思路其實只有一個那就是 通過命令列來執行 R Script。我很粗略的檢視了之前提到的Package 原始碼。非常不嚴謹的下結論,他們的實現思路其實是一樣的,不一樣的是在引數處理,已經返回值的處理。
R Script 命令列執行指令碼是這樣的
Rscript R_File_Path Parameter
R_File_Path: .R 檔案的據對路徑
Parameter: 引數 型別為字串
複製程式碼
所以關鍵問題 “Node 呼叫R Script” 就成了如何在 "Node中執行命令列"。解決這個問題用的方法就是使用呼叫Node模組中子程式child_process
中的 exec
var child_process = require('child_process');
var exec = child_process.exec;
複製程式碼
child_process
具體是什麼,這裡就不展開了,不然就模糊重點了。因為很多時候,我看別人的文章,作者很好心的把相關知識點都列出來了,講的很細,很用心。但對我這種心急的工具黨來,真的太花時間了,反而模糊了焦點。我想立刻解決的我的問題。
給程式碼作為參考,詳細說明請看官網。
三、呼叫方式與相關程式碼
所以,下面直接提供程式碼。程式碼作為示例參考,並不十分規範,比如egg
中獲取資料的操作最好放在service
裡面。
'use strict';
const path = require("path")
const child_process = require('child_process');
const exec = child_process.exec;
const Controller = require('egg').Controller;
class TestRController extends Controller {
async echo() {
let Parameter = path.join(__dirname, "./../public/assets/csv/tilt.csv");
let R_File_Path = path.join(__dirname, "./../public/assets/r/tilt.R");
let cmd = 'Rscript' + ' "' + R_File_Path + '" ' + Parameter;
exec(cmd, (error, stdout, stderr) => {
if (error) {
consle.log(stderr);
} else {
console.log(stdout);
}
});
}
}
module.exports = TestRController;
複製程式碼
其中比較重要的exec方法的回撥結果,每個引數什麼意思,就看上圖需要解釋一下或者官網。解釋下如果執行後的返回結果,引數傳遞的小技巧。 如果資料量比較小那麼,直接放放在引數中
'Rscript R_File_Path "{a:1,b:'p1'}";
複製程式碼
這樣R Script 可以直接接受的引數字串,並且也能序列化成JSON後完成進一步的處理。
但是當引數太大的時候,直接這樣傳參是會出問題的。處理大量資料引數的技巧則是將在引數資料存放在
.txt
,.json
,.csv
檔案中,直接將引數檔案的絕對路徑傳遞R Script 來完成處理。 同樣的道理,在資料返回時也一樣會有資料量的限制,資料量較小時可直接返回為JSON字串,如果過大,則由R儲存成檔案並返回起絕對路徑。
此外還有兩點值得分享的
- R Script 中如何獲取引數
args <- commandArgs(trailingOnly = TRUE)
複製程式碼
- 在 Nodejs 中 exec 方法引數都對,程式碼拼好的
cmd
命令在cmd.exe
能正常執行。但在Node中執行時,就是報 R Script 中用到的Pakckage這個沒安裝那個沒安裝。並且在R Studio中無論重灌多少次都重複報錯。解決辦法:
檢查
library
路徑,如C:\Program Files\R\R-3.5.1\library
裡面到底有沒有這樣Package。沒有則,下載到引用的Package,然後後手動拷貝到這個路徑下。
以上是我解決在Nodejs 中Nodejs 呼叫 R 指令碼的方法。
————————————————
第一次寫技術類文章,如果對你有幫助的話,我會覺得高興。如果看到有可以改進的地方,請給我一點建議。希望自己能堅持,以後分享更多自己收穫的知識。