none
R言語エンジンがインスタンス化できない RRS feed

  • 質問

  • [質問]
    C#からR.NETを使用してR言語エンジンをインスタンス化しようとするとエラーが発生します。何らかの原因でR.NETがR.dllを見つけることができないように見えます。
    アドバイス宜しくお願いします。


    [症状]
    ・MyMean()メソッド内のusing句でREngineをインスタンス化しようとするとDLLが見つかりませんエラーが発生します。
    ・環境変数を設定しても改善しません。
    ・newpathに格納している文字列の位置にR.dllがインストールされているように見えます。


    [実行環境]
    ・Windows7 SP1 64bit
    ・Excel2010 64bit
    ・Excel-DNA 0.30
    ・R言語 Ver. 3.0.2
    ・R.NET Ver. 1.5.5
    ・Visual Studio 2013 (デバッグモード)
    ・Excel2010用のアドインを作成中です。Excel2010からExcel-DNA経由でクラスライブラリ(C#)を呼び出しています。C#ではR.NET経由でR言語エンジンにアクセスしています。
    ・アドインのデバッグ中にエラーが発生します。

    {ソースコード}


    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Collections;
    using ExcelDna.Integration;
    using System.Windows.Forms;
    using RDotNet;

    namespace AddinClassLibrary
    {
        public class MyAddin
        {

            public static double MyMean(object[] items)
            {
                // R.dllが見つからない対策
                string rhome = System.Environment.GetEnvironmentVariable("R_HOME");
                if (string.IsNullOrEmpty(rhome)) rhome = @"C:¥Program Files¥R¥R-3.0.2";
                string rpath = rhome + @"\bin\x64";
                System.Environment.SetEnvironmentVariable("R_HOME", rhome);
                string newpath = System.Environment.GetEnvironmentVariable("PATH") + ";" + rpath;
                System.Environment.SetEnvironmentVariable("PATH", newpath);

                double ret = 0;
                try
                {
      // DLLが見つからないエラーの発生場所
                    using (REngine r = REngine.CreateInstance("RDotNet"))
                    {
                        r.Initialize();
                        NumericVector x = r.CreateNumericVector(Array.ConvertAll(items, p => (double)p));
                        r.SetSymbol("x", x);
                        r.Evaluate("y <- mean(x)");
                        object ans = r.GetSymbol("y");
                        ret = (double)ans;
                    }
                }
                catch (System.ApplicationException ae)
                {
                    MessageBox.Show(ae.ToString());
                }
                catch (System.Exception e)
                {
                    // DLLが見つからないエラーをキャッチした場所
                    MessageBox.Show(e.ToString());
                }
                return ret;
            }

        }
    }


    C#開発者

    2014年1月21日 9:15

回答

  • パスの区切りの¥マークが間違ってますね。
    見た感じは区別つきませんが、文字コードで見ると(char)0x5Cでないといけないのに(char)0x9Dが使われています。

    public static void Main()
    {
        object[] os = new object[] { 2d, 3d, 4d ,5d};
        Console.WriteLine(MyMean(os));
    }
    
    public static double MyMean(object[] items)
    {
        // R.dllが見つからない対策
        string rhome = System.Environment.GetEnvironmentVariable("R_HOME");
        if (string.IsNullOrEmpty(rhome)) rhome = @"C:\Program Files\R\R-3.0.2"; //ここのパス区切りの¥記号が間違ってる
        string rpath = rhome + @"\bin\i386"; //32bitでテスト
        System.Environment.SetEnvironmentVariable("R_HOME", rhome);
        string newpath = System.Environment.GetEnvironmentVariable("PATH") + ";" + rpath;
        System.Environment.SetEnvironmentVariable("PATH", newpath);
    
        double ret = 0;
        try
        {
            // DLLが見つからないエラーの発生場所
            using (REngine r = REngine.CreateInstance("RDotNet"))
            {
                r.Initialize();
                NumericVector x = r.CreateNumericVector(Array.ConvertAll(items, p => (double)p));
                r.SetSymbol("x", x);
                r.Evaluate("y <- mean(x)");
                RDotNet.SymbolicExpression ans = r.GetSymbol("y"); //戻り値はdoubleにキャストできません
                ret = ans.AsNumeric().First();
            }
        }
        catch (System.ApplicationException ae)
        {
            MessageBox.Show(ae.ToString());
        }
        catch (System.Exception e)
        {
            // DLLが見つからないエラーをキャッチした場所
            MessageBox.Show(e.ToString());
        }
        return ret;
    }
    #コンソールアプリとしてデバッグすると、アッタチせずにデバッグできできるのでやりやすい

    個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)

    • 回答としてマーク MicroVAX 2014年1月23日 1:54
    2014年1月21日 13:29
  • Path区切り文字が原因だったとすると、Path.Combine()を使うことで区切り文字に依存することなく結合することができます。特に.NET 4以降であれば

    var rpath = Path.Combine(rhome, "bin", "x64");

    と書けるので確実です。

    • 回答としてマーク MicroVAX 2014年1月23日 1:54
    2014年1月21日 14:31

すべての返信

  • パスの区切りの¥マークが間違ってますね。
    見た感じは区別つきませんが、文字コードで見ると(char)0x5Cでないといけないのに(char)0x9Dが使われています。

    public static void Main()
    {
        object[] os = new object[] { 2d, 3d, 4d ,5d};
        Console.WriteLine(MyMean(os));
    }
    
    public static double MyMean(object[] items)
    {
        // R.dllが見つからない対策
        string rhome = System.Environment.GetEnvironmentVariable("R_HOME");
        if (string.IsNullOrEmpty(rhome)) rhome = @"C:\Program Files\R\R-3.0.2"; //ここのパス区切りの¥記号が間違ってる
        string rpath = rhome + @"\bin\i386"; //32bitでテスト
        System.Environment.SetEnvironmentVariable("R_HOME", rhome);
        string newpath = System.Environment.GetEnvironmentVariable("PATH") + ";" + rpath;
        System.Environment.SetEnvironmentVariable("PATH", newpath);
    
        double ret = 0;
        try
        {
            // DLLが見つからないエラーの発生場所
            using (REngine r = REngine.CreateInstance("RDotNet"))
            {
                r.Initialize();
                NumericVector x = r.CreateNumericVector(Array.ConvertAll(items, p => (double)p));
                r.SetSymbol("x", x);
                r.Evaluate("y <- mean(x)");
                RDotNet.SymbolicExpression ans = r.GetSymbol("y"); //戻り値はdoubleにキャストできません
                ret = ans.AsNumeric().First();
            }
        }
        catch (System.ApplicationException ae)
        {
            MessageBox.Show(ae.ToString());
        }
        catch (System.Exception e)
        {
            // DLLが見つからないエラーをキャッチした場所
            MessageBox.Show(e.ToString());
        }
        return ret;
    }
    #コンソールアプリとしてデバッグすると、アッタチせずにデバッグできできるのでやりやすい

    個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)

    • 回答としてマーク MicroVAX 2014年1月23日 1:54
    2014年1月21日 13:29
  • Path区切り文字が原因だったとすると、Path.Combine()を使うことで区切り文字に依存することなく結合することができます。特に.NET 4以降であれば

    var rpath = Path.Combine(rhome, "bin", "x64");

    と書けるので確実です。

    • 回答としてマーク MicroVAX 2014年1月23日 1:54
    2014年1月21日 14:31
  • ご回答ありがとうございます。
    ご指摘の箇所を訂正したところ、解決できました。


    [修正箇所]
    ・rhomeおよびrpathの区切り記号の誤りを訂正しました。(ご指摘の方法)
    ・yシンボルの値の取得方法を訂正しました。(従来のままではdoubleキャストでエラーが発生する)

    [修正後のソースコード]

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Collections;
    using ExcelDna.Integration;
    using System.Windows.Forms;
    using System.IO;
    using RDotNet;

    namespace AddinClassLibrary
    {
        public class MyAddin
        {

            public static double MyMean(object[] items)
            {
                // R.dllが見つからない対策
                string rhome = System.Environment.GetEnvironmentVariable("R_HOME");
                if (string.IsNullOrEmpty(rhome)) rhome = Path.Combine("C"+Path.VolumeSeparatorChar+Path.DirectorySeparatorChar+"Program Files","R","R-3.0.2");
                string rpath = Path.Combine(rhome, "bin", "x64");
                System.Environment.SetEnvironmentVariable("R_HOME", rhome);
                string newpath = System.Environment.GetEnvironmentVariable("PATH") + Path.PathSeparator + rpath;
                System.Environment.SetEnvironmentVariable("PATH", newpath);

                double ret = 0;
                try
                {
                    using (REngine r = REngine.CreateInstance("RDotNet"))
                    {
                        r.Initialize();
                        NumericVector x = r.CreateNumericVector(Array.ConvertAll(items, p => (double)p));
                        r.SetSymbol("x", x);
                        r.Evaluate("y <- mean(x)");
                        NumericVector ans = r.GetSymbol("y").AsNumeric();
                        ret = (double)ans.First();
                    }
                }
                catch (System.ApplicationException ae)
                {
                    MessageBox.Show(ae.ToString());
                }
                catch (System.Exception e)
                {
                    MessageBox.Show(e.ToString());
                }
                return ret;
            }

        }
    }


    C#開発者

    2014年1月23日 1:53