この前、Rを外部から実行するっていうの書いたけど、C#から呼ぶためのライブラリが普通にあったので、書き直し。探し方が悪かったかしらね。。。

R.Netっていうのを使う。NuGetからインスコ。「R.NET.Community」っていうのもあるんだけど、何が違うんだろうか?リンク先とかも一緒なんだけど。。。あー、もちろん使う場合は端末にR本体がインストールされてる必要あり。

そしたらとりあえず、呼び出しサンプル。

using RDotNet;
static void Main(string[] args)
{
    REngine.SetEnvironmentVariables();//これは省略可。
    using (REngine engine = REngine.GetInstance())
    {
        engine.Evaluate("sample.data <- iris");
        engine.Evaluate("str(sample.data)");
    }
    Console.WriteLine("おしまい");
    Console.ReadLine();
}

↑は呼び方的には公式のチュートリアルのまま。

まず、32bitか64bitでビルド変えないとだめかも。64bitでやる場合はプロジェクトのプロパティ⇒ビルドで「32ビットを優先」のチェックを外さないとだめそうですね。あと、使うR.dllのフォルダも設定が必要。さらに、Rのパスを通してない場合は、実行時に環境変数のPATHにRのパスを追加しておいた方が良さげ。で、色々したのが↓。パスを編集するメソッドはさすがのすたっくおーばーふろーがサンプル。

static void Main(string[] args)
{
    string rpath = SetupPath("R-3.4.2");//インストールしたバージョンを指定
    REngine.SetEnvironmentVariables(rpath);
    using (REngine engine = REngine.GetInstance())
    {
        engine.Initialize();//最近はこれがいるらしい
        engine.AutoPrint = false;//これ付けないと代入してる式で中身が丸ごと出てきてうざい
        engine.Evaluate("sample.data <- iris");
        engine.Evaluate("str(sample.data)");
    }
    Console.WriteLine("おしまい");
    Console.ReadLine();
}
public static string SetupPath(string Rversion)
{
    string rDllPath = Environment.Is64BitProcess ?
                    string.Format(@"C:\Program Files\R\{0}\bin\x64", Rversion) :
                    string.Format(@"C:\Program Files\R\{0}\bin\i386", Rversion);
    //DLLのフォルダが無かったら例外
    if (!Directory.Exists(rDllPath))
    {
        throw new DirectoryNotFoundException(string.Format("Not found : {0}", rDllPath));
    }   
    var newPath = string.Format("{0}{1}{2}", rDllPath, System.IO.Path.PathSeparator, Environment.GetEnvironmentVariable("PATH"));
    Environment.SetEnvironmentVariable("PATH", newPath);
    return rDllPath;
}

でだ、ここまでやっても何故だか実行時に「Rlapack.dllがありません」みたいなエラーが出る端末が稀にいる。意味が分からん。どう見てもあるんだけどね。。。プローブ?がおかしいのだろうか。そういう時はとりあえず、実行ファイルと同じフォルダに「Rlapack.dll」をRのインストール先からコピーしてあげると動くようになる。なんだろね。

ほいで、あとは色々な呼び出し。

static void Main(string[] args)
{
    string rpath = SetupPath("R-3.4.2");
    REngine.SetEnvironmentVariables(rpath);

    using (REngine engine = REngine.GetInstance())
    {
        engine.Initialize();
        engine.AutoPrint = false;

        ////////////////////////////////////////
        //arulesでアソシエーション分析
        ////////////////////////////////////////

        //ライブラリの読み込み
        engine.Evaluate("library(arules)");
        //アソシエーション分析
        engine.Evaluate("data(\"Adult\")");
        engine.Evaluate("rules <- apriori(Adult,parameter=list(minlen=2, maxlen=4, support=0.5, confidence=0.9))");
        //結果のサマリー
        engine.Evaluate("summary(rules)");
        //結果の表示
        engine.Evaluate("inspect(rules)");
        //RのデータフレームをC#で扱えるデータにする
        var dd = engine.Evaluate("Adult@itemInfo").AsDataFrame();
        //つまみ食い
        Console.WriteLine(dd[1, 1]);


        ////////////////////////////////////////
        //kmeansの結果を取得
        ////////////////////////////////////////
        //irisデータ使う(いつものやつ)
        engine.Evaluate("iriswk <- iris[1:150, 1:4]");
        engine.Evaluate("iriswk.km <- kmeans(iriswk, 2)");
        engine.Evaluate("iriswk.km");
        engine.Evaluate("iriswk.km$cluster");
        var kmlist = engine.Evaluate("iriswk.km$cluster").AsNumeric();

        ////////////////////////////////////////
        //Plotの画像をファイルにはく
        ////////////////////////////////////////
        var path = Path.Combine(Path.GetTempPath(), Path.GetTempFileName() + ".png");
        string Code = @"plot(1:10, pch=1:10, col=1:10, cex=seq(1, 2, length=10))";
        engine.Evaluate(string.Format("png('{0}', {1}, {2})", path.Replace('\\', '/'), 420, 420));
        engine.Evaluate(Code);
        engine.Evaluate("dev.off()");
        
    }
    Console.WriteLine("おしまい");
    Console.ReadLine();

}