Nodejs 呼叫 R 指令碼 / Nodejs Call R Script

藍波丶坎迪發表於2018-12-16

提供一個在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-scriptnode-rscriptjs-cal-rrscript這些packages。他們寫的肯定是可以用的。燃鵝,具體實現的時候可能想到複雜,比如你的是一個長度在一萬的Json陣列,或者你的R Script在R studio中執行一切如常偏偏在node中呼叫就報錯,甚至你用packeage page上的示例程式碼都報錯。總之情況可能非常複雜。

二、相關環境的搭建與關鍵Node知識點

2.1 相關環境搭建

首先肯定機器上肯定需要搭建 Node 環境 和 R 的環境,node 環境就不給介紹了。如果你恰好也用的是Eggjs請參照官網

R 環境則只需要安裝最新的 R 安裝包就可以了。目前最新的版本R version 3.5.1。官網 在官網如下位置。

R 官網

安裝好了之後需要配置系統環境變數,移動要配置。這一步非常重要。 在系統便利中將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 具體是什麼,這裡就不展開了,不然就模糊重點了。因為很多時候,我看別人的文章,作者很好心的把相關知識點都列出來了,講的很細,很用心。但對我這種心急的工具黨來,真的太花時間了,反而模糊了焦點。我想立刻解決的我的問題。 給程式碼作為參考,詳細說明請看官網

Nodejs 呼叫 R 指令碼 /  Nodejs Call R Script

三、呼叫方式與相關程式碼

所以,下面直接提供程式碼。程式碼作為示例參考,並不十分規範,比如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儲存成檔案並返回起絕對路徑。

此外還有兩點值得分享的

  1. R Script 中如何獲取引數
args <- commandArgs(trailingOnly = TRUE)
複製程式碼
  1. 在 Nodejs 中 exec 方法引數都對,程式碼拼好的cmd命令在cmd.exe能正常執行。但在Node中執行時,就是報 R Script 中用到的Pakckage這個沒安裝那個沒安裝。並且在R Studio中無論重灌多少次都重複報錯。解決辦法:

檢查 library路徑,如C:\Program Files\R\R-3.5.1\library裡面到底有沒有這樣Package。沒有則,下載到引用的Package,然後後手動拷貝到這個路徑下。

Nodejs 呼叫 R 指令碼 /  Nodejs Call R Script

以上是我解決在Nodejs 中Nodejs 呼叫 R 指令碼的方法。

————————————————

第一次寫技術類文章,如果對你有幫助的話,我會覺得高興。如果看到有可以改進的地方,請給我一點建議。希望自己能堅持,以後分享更多自己收穫的知識。

相關文章