Как заставить ExcelDNA работать с R.Net
Я новичок в C# и R, пытаюсь запустить пример http://mockquant.blogspot.com/2011/07/yet-another-way-to-use-r-in-excel-for.html
<DnaLibrary RuntimeVersion="v4.0" Name="My First XLL" Language="CS">
<ExternalLibrary Path="R.NET.dll" />
<Reference Name="R.NET" />
<![CDATA[using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ExcelDna.Integration;
using RDotNet;
namespace CSLib
{
public class CSLib
{
static REngine rengine = null;
static CSLib()
{
// Set the folder in which R.dll locates.
REngine.SetDllDirectory(@"C:\Program Files\R\R-2.13.0\bin\i386");
rengine = REngine.CreateInstance("RDotNet", new[] { "-q" });
}
[ExcelFunction(Description = "get random numbers obey to normal distribution")]
public static double [] MyRnorm(int number)
{
return (rengine.EagerEvaluate("rnorm(" + number + ")").AsNumeric().ToArray<double>());
}
}
}
Я обновил ссылку в строке SetDLLdirectory и попробовал 32-разрядную и 64-разрядную версии R (моя система процессора win7/64-разрядная)
Я пытался с более ранними стабильными версиями RDotNet и гуглил для обновления кода примера, например. Вот:
https://groups.google.com/d/msg/exceldna/7_wr8pwuCZ0/GLKlVFjr6l8J
<DnaLibrary RuntimeVersion="v4.0" Name="My First XLL" Language="CS">
<ExternalLibrary Path="RDotNet.dll" />
<ExternalLibrary Path="RDotNet.NativeLibrary.dll" />
<Reference Name="RDotNet" />
<Reference Name="RDotNet.NativeLibrary" />
<![CDATA[
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ExcelDna.Integration;
using RDotNet;
namespace CSLib
{
public class CSLib
{
static REngine rengine = null;
static CSLib()
{
// Set the folder in which R.dll locates.
var oldPath = System.Environment.GetEnvironmentVariable("PATH");
var rPath = @"C:\Program Files\R\R-3.0.1\bin\x64";
var newPath = string.Format("{0}{1}{2}", rPath, System.IO.Path.PathSeparator, oldPath);
System.Environment.SetEnvironmentVariable("PATH", newPath);
rengine = REngine.CreateInstance("RDotNet");
}
[ExcelFunction(Description = "get random numbers obey to normal distribution")]
public static double [] MyRnorm(int number)
{
return (rengine.Evaluate("rnorm(" + number + ")").AsNumeric().ToArray<double>());
}
}
}
]]>
</DnaLibrary>
Но я не мог заставить это работать...
Попробовав более старые версии r.net, я также попробовал самую новую версию со старым кодом, а затем попытался адаптировать пример кода, представленный на веб-сайте R.Net, к приведенному выше коду, предполагая, что при инициализации движка r теперь используется путь в реестр:
<DnaLibrary RuntimeVersion="v4.0" Name="R.NET" Description="R.NETExcel" Language="CS">
<Reference Path="RDotNet.NativeLibrary.dll" />
<Reference Path="RDotNet.dll" />
<Reference Path="DynamicInterop.dll" />
<![CDATA[
using System;
using System.IO;
using System.Linq;
using RDotNet;
using DynamicInterop;
namespace CSLib
{
public class CSLib
{
public static double[] MyRnorm(int number)
{
REngine.SetEnvironmentVariables();
REngine engine = REngine.GetInstance();
engine.Initialize();
return (engine.Evaluate("rnorm(" + number + ")").AsNumeric().ToArray<double>());
engine.Dispose();
}
}
}
]]>
</DnaLibrary>
Это также не дает никаких результатов. Функция Excel возвращает #num error.
Я уверен, что ExcelDNA работает, когда я закомментирую секцию, пытающуюся подключиться к R и вставить какую-то другую простую функцию, такую как сумма двух значений.
Я считаю, что мои проблемы могут быть связаны с новыми разработками в RdotNet, делающими приведенный выше пример кода устаревшим (например, это может быть новый способ инициализации экземпляра REngine). Меня также интересует возможность конфликта 32 или 64 бит, поэтому я также попытался заставить его работать на 32 битах, win xp, dot.net 4.0 - безрезультатно.
Каким тогда должен быть правильный способ подключения ExcelDNA к текущей версии R.NET?
Заранее большое спасибо за помощь.
1 ответ
Эти шаги хорошо работали для меня:
Убедитесь, что R установлен. В моем списке "Установка и удаление программ" для Windows я вижу "R для Windows 3.02".
Создайте новый проект "Библиотека классов" в Visual Studio.
В консоли диспетчера пакетов NuGet выполните команды:
PM> Install-Package Excel-DNA PM> Install-Package R.NET.Community
Добавьте следующий код в основной файл.cs:
using System; using System.Linq; using ExcelDna.Integration; using ExcelDna.Logging; using RDotNet; namespace UsingRDotNet { public class AddIn : IExcelAddIn { public void AutoOpen() { MyFunctions.InitializeRDotNet(); } public void AutoClose() { } } public static class MyFunctions { static REngine _engine; internal static void InitializeRDotNet() { try { REngine.SetEnvironmentVariables(); _engine = REngine.GetInstance(); _engine.Initialize(); } catch (Exception ex) { LogDisplay.WriteLine("Error initializing RDotNet: " + ex.Message); } } public static double[] MyRnorm(int number) { return (_engine.Evaluate("rnorm(" + number + ")").AsNumeric().ToArray<double>()); } public static object TestRDotNet() { // .NET Framework array to R vector. NumericVector group1 = _engine.CreateNumericVector(new double[] { 30.02, 29.99, 30.11, 29.97, 30.01, 29.99 }); _engine.SetSymbol("group1", group1); // Direct parsing from R script. NumericVector group2 = _engine.Evaluate("group2 <- c(29.89, 29.93, 29.72, 29.98, 30.02, 29.98)").AsNumeric(); // Test difference of mean and get the P-value. GenericVector testResult = _engine.Evaluate("t.test(group1, group2)").AsList(); double p = testResult["p.value"].AsNumeric().First(); return string.Format("Group1: [{0}], Group2: [{1}], P-value = {2:0.000}", string.Join(", ", group1), string.Join(", ", group2), p); } } }
F5 для запуска надстройки в Excel.
Введите формулу = TestRDotNet ()
and
= MyRNorm (5) `. Числа появляются в Excel.
Я добавил проект "UsingRDotNet" в образцы Excel-DNA на GitHub.