Trying to change a variable name of an XDF with rxSetVarInfo.
I want to merge several data sets with common var names. (I know rxMerge can/will append to filenames where needed. I want to have more control than that.)
This works:
outLetter<- "A"
exp <- list(pct.A = list(newName = paste0("X.pct.",outLetter)))
rxSetVarInfo(varInfo = exp, data = tempXDFFile)
That's where I know the original column name, pct.A. What if that's dynamic? What if this is in a function that gets called several times with different outLetter's. (The "A" isn't hardcoded.)
This does not work:
function(outLetter){
exp <- list(paste0("pct.",outLetter) = list(newName = paste0("X.pct.",outLetter)))
rxSetVarInfo(varInfo = exp, data = tempXDFFile)
}
Nor does:
exp <- parse(text = exp)
rxSetVarInfo(varInfo = exp, data = tempXDFFile)
Yes, I can hardcode all the permutations. Trying to find a more elegant approach.
Please try this code:
dynamicName <- function(outLetter){
exp <- vector(mode="list", length=1)
names(exp) <- paste0("pct.",outLetter)
exp[[paste0("pct.",outLetter)]] = list(newName = paste0("X.pct.",outLetter))
rxSetVarInfo(varInfo = exp, data = tempXDFFile)
}
Before the call to rxSetVarInfo(), "exp" contains:
$pct.A
$pct.A$newName
[1] "X.pct.A"
Running your "this works" case, I see:
> outLetter<- "A"
> exp <- list(pct.A = list(newName = paste0("X.pct.",outLetter)))
>
> exp
$pct.A
$pct.A$newName
[1] "X.pct.A"
Hope this helps!
Note, please make sure that your dynamic naming function has access to the variable "tempXDFFile", you may want to consider passing it as a parameter, like:
dynamicName <- function(outLetter, data){
exp <- vector(mode="list", length=1)
names(exp) <- paste0("pct.",outLetter)
exp[[paste0("pct.",outLetter)]] = list(newName = paste0("X.pct.",outLetter))
rxSetVarInfo(varInfo = exp, data = data)
}
Related
I am trying to create a loop to automatize exams generation using the examspackage....
I have created a series of exercices like this
gr1 <- c("ae1_IntroEst_1.Rmd","ae1_IntroEst_2.Rmd","ae1_IntroEst_3.Rmd","ae1_IntroEst_4.Rmd")
gr2 <- c("ae1_IntroProcEst_1.Rmd","ae1_IntroProcEst_2.Rmd","ae1_IntroProcEst_3.Rmd","ae1_IntroProcEst_4.Rmd")
...etc...
Now, I am creating a loop to export all the exercices to moodle xml:
for (i in 1:2){
grupo <- paste0("gr",i)
exams2moodle(grupo, name = paste0("mt1_",i, "_M"), dir = "nops_moodle", encoding = "UTF-8", schoice = list(answernumbering = "none", eval = ee))
}
But I am getting this error:
Error in xexams(file, n = n, nsamp = nsamp, driver = list(sweave = list(quiet = quiet, : The following files cannot be found: gr11.
If I replace "grupo" by "gr1" then it works... (but I am generating 20 exercices). I can't figure it out...
Any ideas?
Thanks!
Because grupo is a string: "gr1". The exams2moodle's first parameter is a string (in your case) and not the list of files (as you want).
If you want use a variable which name is in a string variable, you should use get (get: Return the Value of a Named Object)
Check the sample code:
> x <- 'foo'
> foo <- 'bar'
> x
[1] "foo"
> get(x)
[1] "bar"
>
In your case:
for (i in 1:2){
grupo <- paste0("gr",i)
exams2moodle(get(grupo), name = paste0("mt1_",i, "_M"), dir = "nops_moodle", encoding = "UTF-8", schoice = list(answernumbering = "none", eval = ee))
}
Why does the following MSR code not replace the original column "Var1"?
rxDataStep(inData = input_xdf, outFile = input_xdf, overwrite = TRUE,
transforms = list(Var1 = as.numeric(Var1)),
transformVars = c("Var1")
)
At the moment, RevoScaleR doesn't support changing the type of a variable in an xdf file (even if you write to a different file). The way to do it is to create a new variable, drop the old, and then rename the new variable to the old name.
I would suggest doing this with a transformFunc (see ?rxTransform for more information), so that you can create the new variable and drop the old, all in one step:
rxDataStep(inXdf, outXdf, transformFunc=function(varlst) {
varlst$Var1b <- as.numeric(varlst$Var1)
varlst$Var1 <- NULL
varlst
}, transformVars="Var1")
# this is fast as it only modifies the xdf metadata, not the data itself
names(outXdf)[names(outXdf) == "Var1b"] <- "Var1"
MSR doesn't allow you to overwrite a variable in place with a different variable type.
You have two options: Write to a different variable or write to a different file. I have added a bit of code that shows that both solutions work as stated in MRS 9.0.1. As stated in the comments, there is some point in earlier versions where this might not work. I am not totally sure where that point is, so the code should let you know.
input_xdf <- "test.xdf"
modified_xdf <- "test_out.xdf"
xdf_data <- data.frame(Var1 = as.character(1:10),
Var2 = 2:11,
stringsAsFactors = FALSE)
rxDataStep(inData = xdf_data,
outFile = input_xdf,
rowsPerRead = 5,
overwrite = TRUE)
rxDataStep(inData = input_xdf,
outFile = input_xdf,
overwrite = TRUE,
transforms = list(Var1b = as.numeric(Var1)),
transformVars = c("Var1")
)
rxGetInfo(input_xdf, getVarInfo = TRUE, numRows = 5)
rxDataStep(inData = input_xdf,
outFile = modified_xdf,
transforms = list(Var1 = as.numeric(Var1)),
transformVars = c("Var1")
)
rxGetInfo(modified_xdf, getVarInfo = TRUE, numRows = 5)
I'm searching for an existing solution to serialize records to query strings but found nothing. I know about F#'s pretty printing, but I have no idea how to access it manually.
In common I want something like this:
type Person = {first:string; last:string}
type Group = {name:string; size:int}
let person = {first="Mary"; last="Smith"}
let personQueryString = Something.toQueryString person
let group = {name="Full"; size=345}
let groupQueryString = Something.toQueryString group
where
personQueryString -> "first=Mary&last=Smith"
groupQueryString -> "name=Full&size=345"
I don't think such a function exists, but you can write one that uses Reflection:
open System.Reflection
module Something =
let toQueryString x =
let formatElement (pi : PropertyInfo) =
sprintf "%s=%O" pi.Name <| pi.GetValue x
x.GetType().GetProperties()
|> Array.map formatElement
|> String.concat "&"
Since it uses Reflection, it's not as efficient as specialised functions that know about the types in advance, so whether or not this is sufficient for your needs, only you know.
It produces the desired result, though:
> let person = {first="Mary"; last="Smith"};;
val person : Person = {first = "Mary";
last = "Smith";}
> let personQueryString = Something.toQueryString person;;
val personQueryString : string = "first=Mary&last=Smith"
> let group = {name="Full"; size=345};;
val group : Group = {name = "Full";
size = 345;}
> let groupQueryString = Something.toQueryString group;;
val groupQueryString : string = "name=Full&size=345"
"first part" &&&& fun _ ->
let ident
"second part" &&&& fun _ ->
ident ....
I need to use variable "ident".
I just need to pass value of variable from first part of test to second one...
I want to ask you if there is any easy way how to define and use global variable or even if you have better (and easy) idea of doing that
Keep in mind, please, that I am a beginner, so I would prefer easier ones.
Global variables will often make your code difficult to work with - particularly if they are mutable.
Instead, consider returning the values you need to keep track of as composite values. An easy data type to start with would be a tuple:
let ``first part`` id =
let someOtherValue = "Foo"
someOtherValue, id + 1
This function takes an int (the current ID) as input, and returns string * int (a tuple where the first element is a string, and the second element and int) as output.
You can call it like this:
> let other, newId = ``first part`` 42;;
val other : string = "Foo"
val newId : int = 43
Notice that you can use pattern matching to immediately destructure the values into two named symbols: other and newId.
Your second function could also take an ID as input:
let ``second part`` id otherArgument =
// use id here, if you need it
"Bar"
You can call it like this, with the newId value from above:
> let result = ``second part`` newId "Baz";;
val result : string = "Bar"
If you find yourself doing this a lot, you can define a record for the purpose:
type Identifiable<'a> = { Id : int; Value : 'a }
Now you can begin to define higher-order functions to deal with such a type, such as e.g. a map function:
module Identifiable =
let map f x = { Id = x.Id; Value = f x.Value }
// Other functions go here...
This is a function that maps the Value of an Identifiable from one value to another, but preserves the identity.
Here's a simple example of using it:
> let original = { Id = 42; Value = "1337" };;
val original : Identifiable<string> = {Id = 42;
Value = "1337";}
> let result' = original |> Identifiable.map System.Int32.Parse;;
val result' : Identifiable<int> = {Id = 42;
Value = 1337;}
As you can see, it preserves the value 42, but changes the Value from a string to an int.
You can still change the ID explicitly, if you want to do that:
> let result'' = { result' with Id = 7 };;
val result'' : Identifiable<int> = {Id = 7;
Value = 1337;}
Since this was getting out of hand for comments this is how I would do it for an example
let mutable t = 0
let first =
t <- 1 + 1
//other stuff
let second =
//can use t here and it will have a value of 2
In some cases you have to use a ref:
let t = ref 0
let first =
t := 1 + 1
//other stuff
let second =
//can use t here and it will have a value of 2 -
// you use "!t" to get the value
If you define ident at the top of your file like this :
let ident = "foo"
// rest of your code using ident
ident are global and you can use in the next part of your file.
EDIT :
If ident wil change in the next part of your code, use this :
let ident = ref "foo"
Given a number of functions test1, test2, ... belonging to a module:
module Checks =
let test1 x = ...
let test2 x = ...
...
how can the (?) operator be used to give access to both the function name and the function itself? The result should look like:
let name, func = Checks?test1
assert(name = "test1")
assert(func(x) = Checks.test1(x)) //whatever x is (test1 is known to be pure)
You cannot use the ? operator to access functions in a module, because the construct Checks?test1 is not syntactically correct (this would be translated to (?) Checks "test" and you cannot use module names as values).
However, it should be possible to do this for members of a type using an instance of the object (e.g. obj?test). Alternatively you could write a "fake" object instance (that knows the name of the module). The implementation of ? would then look for the module and search static members in the module.
The simplest implementation (of the first case) would look like this:
let (?) obj s =
let memb = obj.GetType().GetMethod(s)
// Return name and a function that runs the method
s, (fun args -> memb.Invoke(obj, args))
// Type that contains tests as members
type Check() =
member x.test1 () = 32
// We need to create instance in order to use '?'
let ch = Check()
let s,f = ch?test1
// Function 'f' takes array of objects as an argument and
// returns object, so the call is not as elegant as it could be
let n = ((f [| |]) :?> int)
You could also add some wrapping to make the function 'f' a little bit nicer, but I hope this demonstrates the idea. Unfortunately, this cannot work for modules.
Here's some sample code that shows off some of this. I use D as the 'dynamic' access of the Checks module plus function name.
module Checks =
let test1(x) = printfn "test1 %d" x
let test2(x,y) = printfn "test2 %s %d" x y
type MyDynamic() = class end
let D = new MyDynamic()
let (?) (md:MyDynamic) fname : (string * ('a -> 'r)) =
let a = md.GetType().Assembly
let t = a.GetType("Program+Checks")
let m = t.GetMethod(fname)
let f arg =
let at = arg.GetType()
let fsharpArgs =
if at.IsGenericType && at.GetGenericTypeDefinition().FullName.StartsWith("System.Tuple`") then
Microsoft.FSharp.Reflection.FSharpValue.GetTupleFields(arg)
else
[| box arg |]
unbox(m.Invoke(null, fsharpArgs))
fname, f
let Main() =
let x = 42
let s = "foo"
let name, func = D?test1
assert(name = "test1")
assert(func(x) = Checks.test1(x))
let name, func = D?test2
assert(name = "test2")
assert(func(s,x) = Checks.test2(s,x))
System.Console.ReadKey()
Main()