Closed tinoswe closed 9 years ago
Since your code sample is not a self-contained runnable example it is hard for me to see what the issue is. Which part of it is failing? Does it fail if you do this in a standalone script/executable? Is this an issue with calling R or returning it to Excel via ExcelDNA?
Hi hmanselll. I'll post a working example later today. Thanks.
Hi again, below you find a simplified working example (just copy and paste as an .fsx. I am using VS2012).
Just to be clear: everything is working fine with excelDNA and the current version of the code does what I want. But I need to modify the current implementation of the function so that it returns "fitted_values" when no exception is thrown. If any exception is thrown it should throw the exception the same way as it does now.
So... the last 15 lines within the function body should be changed and I need some help with this. Thanks in advance.
#r @"packages\R.NET.Community.1.5.15\lib\net40\RDotNet.dll"
#r @"packages\R.NET.Community.FSharp.0.1.8\lib\net40\RDotNet.FSharp.dll"
#r @"packages\R.NET.Community.1.5.15\lib\net40\RDotNet.NativeLibrary.dll"
#r @"packages\RProvider.1.0.13\lib\net40\RProvider.dll"
#r @"packages\RProvider.1.0.13\lib\net40\RProvider.Runtime.dll"
open System
open System.Collections.Generic
open System.Data
open System.IO
open RDotNet
open RProvider
open RProvider.``base``
open RProvider.stats
open RProvider.grDevices
open RProvider.graphics
open RProvider.utils
type public heatflux_int_type = { Name:string; Chosen:string; Values:float []; }
let rnlm_evolution( (q_arr:float[]),
(b1:string),
(n1:string),
(arr1:float[]),
(b2:string),
(n2:string),
(arr2:float[]),
(b3:string),
(n3:string),
(arr3:float[])) =
let records = [ { Name = "Q"; Chosen = "Yes"; Values = q_arr }
{ Name = n1; Chosen = b1; Values = arr1 }
{ Name = n2; Chosen = b2; Values = arr2 }
{ Name = n3; Chosen = b3; Values = arr3 } ] |> List.filter (fun x -> match x.Chosen with
| "Yes" -> true
| _ -> false)
let dataset =
match records.Length with
| 4 -> namedParams [records.[0].Name.Split('[').[0].Replace(" ",""), box records.[0].Values;
records.[1].Name.Split('[').[0].Replace(" ",""), box records.[1].Values;
records.[2].Name.Split('[').[0].Replace(" ",""), box records.[2].Values;
records.[3].Name.Split('[').[0].Replace(" ",""), box records.[3].Values;] |> R.data_frame
| 3 -> namedParams [records.[0].Name.Split('[').[0].Replace(" ",""), box records.[0].Values;
records.[1].Name.Split('[').[0].Replace(" ",""), box records.[1].Values;
records.[2].Name.Split('[').[0].Replace(" ",""), box records.[2].Values;] |> R.data_frame
| 2 -> namedParams [records.[0].Name.Split('[').[0].Replace(" ",""), box records.[0].Values;
records.[1].Name.Split('[').[0].Replace(" ",""), box records.[1].Values;] |> R.data_frame
let coef_names = R.names(dataset).GetValue<string []>()
let debug_coef_names = coef_names
let custom_formula =
match coef_names.Length with
| 4 -> R.paste( namedParams ["A", box coef_names.[0];
"B", box "~";
"C", box "p1 * (" ;
"D", box coef_names.[1];
"E", box "**p2)*(";
"F", box coef_names.[2];
"G", box "**p3)*(";
"H", box coef_names.[3];
"I", box "**p4)";];).GetValue<string>()
| 3 -> R.paste( namedParams ["A", box coef_names.[0];
"B", box "~";
"C", box "p1 * (" ;
"D", box coef_names.[1];
"E", box "**p2)*(";
"F", box coef_names.[2];
"G", box "**p3)";];).GetValue<string>()
| 2 -> R.paste( namedParams ["A", box coef_names.[0];
"B", box "~";
"C", box "p1 * (" ;
"D", box coef_names.[1];
"E", box "**p2)"];).GetValue<string>().Replace(" ","")
let debug_custom_formula = custom_formula
let init_params =
match coef_names.Length with
| 4 -> namedParams [ "p1", 1000; "p2", 2; "p3", 2; "p4", 2] |> R.list
| 3 -> namedParams [ "p1", 1000; "p2", 2; "p3", 2] |> R.list
| 2 -> namedParams [ "p1", 1000; "p2", 1] |> R.list
let ctrl_pars = namedParams [ "maxiter", box 1000;
"tol", box 1e-5; //"printEval", box true;
"warnOnly", box true ] //|> R.list
let test_ctrl = R.nls_control(ctrl_pars)
let result =
try
R.nls(namedParams ["formula", box custom_formula;
"start", box init_params;
"data", box dataset;
"control", box test_ctrl;]) |> ignore
with
| _ as exc -> raise (InvalidOperationException exc.Message) //printfn "Error 1: %s" exc.Message
//let result_fitted_values = R.fitted(result)
//let fitted_values = result_fitted_values.AsNumeric().GetValue<float[]>()
0.0 //I want to return fitted_values instead of 0.0 if no exception is thrown
//now I define input vectors
let SH = [| 28.0; 28.0; 28.0; 28.0; 31.0; 31.0; 31.0; 31.0; 31.0; 31.0 |]
let HF = [| 1398.31; 1319.65; 1385.41; 1376.9; 1175.89; 1191.41; 1198.86; 1209.61; 1197.23; 1328.33 |]
let CS = [| 0.602; 0.552; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6; 0.6 |]
let CE = [| 0.36; 0.36; 0.36; 0.36; 0.327; 0.327; 0.327; 0.327; 0.327; 0.327 |]
//no exception is thrown in this case. Function returns 0.0 as it should. But I would like to modify the function so that it returns the fitted_values array... and I don't know how to do this...
let outp1 = rnlm_evolution(HF,
"Yes","SH", SH,
"Yes", "CS", CS,
"No", "CE", CE)
//R exception is thrown. Fine. I can handle it
let outp2 = rnlm_evolution(HF,
"Yes","SH", SH,
"Yes", "CS", CS,
"Yes", "CE", CE)
Thanks for sending a full example!
The R.nls
function returns an object of class "nls" and I don't think the R provider understands this, so it does not give you an easy way of extracting the information from the result out-of-the-box. What does the result actually represent (I'm not an R expert....) and what do you want to get from it?
I had a look at the samples in the docs and they, for example, use coef(fm1DNase1)
. You could do that in R provider too - when you get the result
of R.nls
, you could write:
let result =
try
R.nls(namedParams ["formula", box custom_formula;
"start", box init_params;
"data", box dataset;
"control", box test_ctrl;])
with exc -> raise (InvalidOperationException exc.Message)
// Call the coef function and get the coefficients as a float array...
R.coef(result).GetValue<float[]>()
Hi, thanks for the reply. Your example illustrates very well what I am trying to do. What I am trying to get is
R.fitted(result).AsNumeric().GetValue<float[]>()
that is an array of float, i.e. an object that is identical to your:
R.coef(result).GetValue<float[]>()
but when trying to get the coefficients what I get is:
Error in coef.default() : argument "object" is missing, with no default
RDotNet.EvaluationException: Error in coef.default() : argument "object" is missing, with no default
at RDotNet.REngine.Parse(String statement, StringBuilder incompleteStatement)
at RDotNet.REngine.<Defer>d__0.MoveNext()
at System.Linq.Enumerable.LastOrDefault[TSource](IEnumerable`1 source)
at RDotNet.REngine.Evaluate(String statement)
at RProvider.RInteropInternal.eval(String expr) in c:\Tomas\Public\FSharp.RProvider\src\RProvider\RInterop.fs:line 288
at RProvider.RInterop.callFunc(String packageName, String funcName, IEnumerable`1 argsByName, Object[] varArgs) in c:\Tomas\Public\FSharp.RProvider\src\RProvider\RInterop.fs:line 458
at RProvider.RInterop.call(String packageName, String funcName, String serializedRVal, Object[] namedArgs, Object[] varArgs) in c:\Tomas\Public\FSharp.RProvider\src\RProvider\RInterop.fs:line 489
at FSI_0066.rnlm_evolution(Double[] q_arr, String b1, String n1, Double[] arr1, String b2, String n2, Double[] arr2, String b3, String n3, Double[] arr3) in C:\...\Script2.fsx:line 30
at <StartupCode$FSI_0068>.$FSI_0068.main@() in C:\...\Script2.fsx:line 135
Stopped due to error
and I don't understand it...
I'm not entirely sure what is going wrong here - the following works fine on my side:
let result =
try
R.nls(namedParams ["formula", box custom_formula;
"start", box init_params;
"data", box dataset;
"control", box test_ctrl;])
with exc -> raise (InvalidOperationException exc.Message) //printfn "Error 1: %s" exc.Message
R.coef(result).GetValue<float[]>(),
R.fitted(result).GetValue<float[]>(),
R.fitted(result).AsNumeric().GetValue<float[]>()
The call to AsNumeric
seemed to be the only difference between your & my code, but it has no effect...
ok, thanks for checking. Then I have to find out why it doesn't work for me...
I think I found out. You removed the "ignore" thing in the result calculation. If I do the same it works for me as well.
let result =
try
R.nls(namedParams ["formula", box custom_formula;
"start", box init_params;
"data", box dataset;
"control", box test_ctrl;]) //|> ignore
with
| _ as exc -> raise (InvalidOperationException exc.Message) //printfn "Error 1: %s" exc.Message
Thanks guys. I close the thread.
Oh, yes, of course, ignore
was ignoring the results! Glad you got it to work!
Hi all, I managed to handle R.nls exceptions and pass them on to an Excel spreadsheet using ExcelDNA with the following block of F# code:
In Excel a MessageBox will contain the exception string and this is exactly what I want. And it works fine so far. However I would like my function to return the array "fitted_values" (instead of 0.0) when available (i.e. when no exception is thrown) using:
Since I am not an F# expert could you please help me with this?