记一次.NET 与R语言交互
這是將近二年前,有一個項目使用.NET相關技術,但是項目中要將寫好的R語言的代碼,直接通過.NET調用,得到計算結果,遇到了這么多的坑,在此記下一些過程,文檔太少,英文不好!!!
如下為開發過程中可能出現的問題!
相關博客介紹
使用的類庫是 ?RDotNet ? ,開源地址:R.NET他有官網的:對R.NET的一些介紹 ,這個可能需要翻墻。
我找了很多博客,在CSDN上的代碼,基本都是重復的,也沒有太多的介紹,一般情況都是官網直接翻譯下來的,遇到一些問題時,根本查不到是什么原因。那么,遇到問題,怎么辦?
1、看官網,里面有一些示例的鏈接:這個相當于示例代碼庫
2、看github上,開源地址的Issue,看不懂英語,也要看,有些問題,看完你就會懂了。
R.NET是什么?
我的理解,R語言就像是SQL語言,用于數據計算,數據處理。R.Net這個類庫就類似ADO.NET的技術,幫助我們實現.NET程序訪問R語言代碼,R.NET就相當于一個驅動程序。當然,嚴格意義上,我也不知道RDotNet是不是這樣子,看他介紹,應該是起一R引擎。。。。(不懂.jpg)
使用RDotNet的步驟:
1、首先,你要看懂一些簡單的R程序,就像,你不懂sql 語句,你怎么寫ADO.NET程序一樣 (安裝R的環境,不要裝最新的3.5版本,因為,R.NET并沒有做到最新的版本,看他的github就知道了,我本地裝的3.3.3,一點問題都沒有。如果你安裝3.5版本,會一直報一個空指針異常,反正我被坑了。)
2、將我上面所說的示例代碼庫下載下來,從最簡單的代碼開始看起。
如下為開發過程中可能出現的問題!
而我遇到什么樣的問題呢?我是如何解決的?
還有哪些問題需要解決?
這個類庫還有哪些問題不能解決,他有哪些缺點?
回答上面的問題.
1.我遇到的問題。
1)、安裝過新的R環境3.5導致一直報錯,一點思路都沒有。如何解決:看github的issue,看到有人提的問題,大意是指。R.NET不能支持到最新的R語言版本。
2)、一個簡單的程序,在控制臺上執行,是OK的。然而在ASP.NET MVC程序上一直不成功。如何解決:第一步:先把R的環境變量配置好,類似JDK的環境變量配置 找到自己的R語言位置,將32位和64位的環境都配置至path中
?;C:\Program?Files\R\R-3.3.3\bin\i386;C:\Program?Files\R\R-3.3.3\bin\x64;第二步,如何還有問題的話:比如一直報StackOverflowException的異常,建議你看他的issue:這個是他們的討論原本我也遇到這個問題,但R的版本用了3.3,就沒這個錯了。
3)、當R的引擎正常結束后,調用 dispose后,下次調用 就會報錯,那就不調用 dispose方法吧。那個作者說:There can only be one R engine in a process, and R itself is largely not thread-safe.
2.還有哪些問題需要解決?
以管理員權限運行Rgui,并指定包安裝的位置,防止安裝到其他目錄 此命令設置當前包安裝的位置,
此命令查看當前包會安裝的位置
.libPaths()如果有些包無法正常安裝,如果能找到那個包,可直接復制其至目錄C:/Program Files/R/R-3.3.3/library
運行和發布后的代碼都應運行在64位機子及平臺上。
3.這個類庫還有哪些問題不能解決,他有哪些缺點?
不能兼容所有的R版本,目前只兼容到R3.3.3。
如下代碼在本機windows10 專業版 中文版電腦上運行會亂碼
我研究下代碼,是這個類中的方法有問題InternalString ?下的方法 StringFromNativeUtf8
???????///?<summary>///?Convert?utf8?to?string///?</summary>///?<param?name="utf8">utf8?to?convert</param>public?static?string?StringFromNativeUtf8(IntPtr?utf8){int?len?=?0;while?(Marshal.ReadByte(utf8,?len)?!=?0)?++len;byte[]?buffer?=?new?byte[len];Marshal.Copy(utf8,?buffer,?0,?buffer.Length);return?Encoding.UTF8.GetString(buffer);}我在我本地調試源碼時,發現,如果包含中文時,采用Encoding.Default.GetString(buffer);轉換,這里就可以正常轉換,但這樣子,就只支持中文和英文了。而且,好像在測試過程中,改成Default后,如下方法中包含中文,反而亂碼了。
???????string[]?rownames?=?engine.GetSymbol("rownames").AsCharacter().ToArray();所以我準備直接用最簡單的方式 ,判斷buffer的編碼,如果不為UTF8,Convert為UTF8,然后返回,否則,這里就需要多此一舉,因為,在測試過程發現,判斷UTF8,不準確,明明不是UTF8,還是返回了UTF8,所以在這里需要判斷,轉換后的數據是否包含中文,如果包含,則直接返回,否則要從Default(根據系統的編碼決定),轉換為UTF8,就能返回中文 。
???????///?<summary>///?Convert?utf8?to?string///?</summary>///?<param?name="utf8">utf8?to?convert</param>public?static?string?StringFromNativeUtf8(IntPtr?utf8){int?len?=?0;while?(Marshal.ReadByte(utf8,?len)?!=?0)?++len;byte[]?buffer?=?new?byte[len];Marshal.Copy(utf8,?buffer,?0,?buffer.Length);Encoding?encoding?=?GetType(buffer);if?(encoding.Equals(Encoding.UTF8)){string?r?=?Encoding.UTF8.GetString(buffer);if?(System.Text.RegularExpressions.Regex.IsMatch(r,?@"[\u4e00-\u9fbb]+$")){return?r;}else{byte[]?newBuffer?=?Encoding.Convert(Encoding.Default,?Encoding.UTF8,?buffer);return?Encoding.UTF8.GetString(newBuffer);}}else{byte[]?newBuffer?=?Encoding.Convert(encoding,?Encoding.UTF8,?buffer);return?Encoding.UTF8.GetString(newBuffer);}}代碼已放到github
由于該 R.NET類庫 長期未維護,還是有很多BUG,所以我fork了一份,以便解決部分簡單BUG問題, github開源地址
相關博客介紹
用C#調用R語言開發.NET MVC Web服務 此文章中介紹了.NET啟動控制臺調用R代碼,這個思路非常好,一開始對R語言了解甚少,所以還是使用R.NET來實現.NET與R語言的交互,反而耗時耗力。
一鍵運行R腳本 這個文章讓我了解到Rscript.exe這個程序的作用,以及執行方式。
c#調用R語言(原創翻譯)
由于開發過程中,有個R程序運行時間非常長,最長可達2小時,所以只能以后臺任務方式執行,但 RDotNET,一次只能運行一個,不執行完,其他的程序在WEB項目下無法正常運行,看了上面的文章,有了思路 :使用.NET的進程Process起一個cmd命令,類似 java配置好環境變量后可使用java,javac命令一樣,配置到Path中后,可直接在cmd中使用如下命令
Rscript.exe?"某目錄下\test.R"??agruments?其中R程序包要有雙引號 ? 多個參數使用空格分隔 ,如下為.NET下使用Process啟動cmd命令,并執行Rscript.exe 命令啟動R引擎,讓其后臺運行,運行結束后,才會往后執行。
????public?void?Execute(){List<string>?arguments?=?new?List<string>{參數};Process?cmd?=?new?Process{StartInfo?={FileName?=?@"Rscript.exe",WorkingDirectory?=?AppFolders.RSourceCodeFolder,//.R代碼的位置?"E:\svn\CHNMed\CHNMed.Web\DataUsers\RSourceCode"UseShellExecute?=?false,RedirectStandardOutput?=?true,RedirectStandardError?=?true,Arguments?=?"?Test.r?"?+?string.Join("?",?arguments),CreateNoWindow?=?true,//不顯示程序窗口}};cmd.Start();//啟動程序var?output?=?cmd.StandardOutput.ReadToEnd();var?error?=?cmd.StandardError.ReadToEnd();cmd.WaitForExit();//等待控制臺程序執行完成cmd.Close();//關閉該進程Logger.InfoFormat($"參數:{output}出錯信息:{error}");}總結
以上是生活随笔為你收集整理的记一次.NET 与R语言交互的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 谷歌最终还是把Knative交了出来
- 下一篇: 软件如何优雅地向前兼容?