R function scope - function

I am trying to create a function for a series of rounding work in R, I have percentage, decimals, etc, each of them need to be rounded differently.
I start writing the function by first picking up the object I want, but I fail to do that already, here's the code:
roundings <- function(obj.head)
{obj.list <- ls(pattern=obj.head)
obj.list
}
Suppose I have two object A1 and B1, I suppose if I run roundings("A"), A1 should appear as the function output, but it didn't.
What have I done wrong? Thanks.

The call to ls is searching the current environment within the function and does not find any objects to match. You can specify the envir parameter in ls with .GlobalEnv. Thus your code becomes:
roundings <- function(obj.head)
{
obj.list <- ls(pattern = obj.head, envir = .GlobalEnv)
obj.list
}

I found the reason, I should have added envir=.GlobalEnv inside the ls parameters.

Related

Apply function (Jaccard similarity) on every row in R (using data from the previous row)

I would like to compute Jaccard Similarity on text using R.
I already found a way to compute JS using a function. Which works fine when I apply it stand-alone.
I have a dataset with utterances in conversation. I would like to add a column that presents the Jaccard similarity of each utterance with the (immediate) previous one.
Like I said I already use a function to compute JS.
jaccard <- function(a, b) {
intersection = length(intersect(a, b))
union = length(a) + length(b) - intersection
return (intersection/union)
}
I have already tried multiple things looking like this:
Text$J <- 0
# for every row in DT
for (i in 1:length(Text)) {
if(i==1) {
#using NA at first line
Text[i,2] <- NA
} else {
Text$J <- jaccard(Text$Utterance,Text$Utterance[i-1])
}
}
Is it possible to integrate a function like the above in a 'for every row' code? So far, my attempts are not successful, but that might be me. What happens in most cases is that is just pastes one Jaccard value to the whole column. Thank you in advance!

How to change the value of a variable that is declared out of a function?

Let's say you've a variable called "ENV.myvar" in your code. Then you've have written a function, "myfun", that has some goal and return an object (for example an array). ENV.myvar is used for computation and for some reason it has been modified during the process.
ENV.myvar <- 0;
myfun <- function(in1,in2,...,inN){
#declaring the output object
fun.myarray <- c(0,0,0);
#some code
...
#here ENV.myvar is modified for some reason
ENV.myvar = ENV.myvar + 20;
#code that works on fun.myarray
...
#return the object
fun.myarray
}
Finally we get to the point of the question: the function returns only the object but should overwrite permanently an external variable used during the process. Is it possible in some way?
Yes, you can, even though it's not recommended, because it's not the expected behaviour of a function to change anything outside its environment. Still, this is how you could do it:
myvar <- 0
myf <- function() {
assign("myvar", 10, envir = parent.env(environment()))
return("Value of 'myvar' changed to 10 in parent environment")
}
myf()
myvar
# [1] 10
You can change the parent.env(environment()) part to get a specific environment, or just .GlobalEnv, depending on the call stack and your needs.

MATLAB How to pass an Array from my base workspace to a function

I have been on a few forum posts now reading through trying to figure this out but I can't seem to crack it. To summarise my function I have 2 arrays searchDates and searchIds. Now all I want to do is do a comparison on the size of one of the elements to the other array and this is the code I have so far but I don't know how to carry over searchDates and searchIds
function a = compare(userNum)
if size(searchDates{1,userNum},2) == size(searchIds{1,userNum},2)
x = true
else x = false
end
TL;DR I just need to know how to pass from my BASE WORKSPACE to my FUNCTION WORKSPACE the two arrays from above.
Cheers!
You can rewrite your function so that you can directly pass the arrays:
function a = compare(userNum,searchDates,searchIds)
if size(searchDates{1,userNum},2) == size(searchIds{1,userNum},2)
x = true
else x = false
end
then call compare with your workspace variables in the 2nd and 3rd argument.
If for some reason you need compare to only have one argument, you can create an anonymous function in your workspace by using the above function compare and writing:
anon_compare = #(userNum) compare(userNum,searchDates,searchIds)
Provided searchDAtes and searchIds are in your workspace, you will now have the function anon_compare, which you can use directly as anon_compare(foo).
For more on anonymous functions (an important aspect of several MATLAB programming techniques) you can read this post.

Lua - How do I use a function from another script?

I've been looking around and I have not been able to find anything that has worked for me. I'm starting to learn more Lua and to start off I'm making a simple calculator. I was able to get each individual operation onto separate programs, but when I try to combine them I just can't get it to work. My script as it is now is
require "io"
require "operations.lua"
do
print ("Please enter the first number in your problem.")
x = io.read()
print ("Please enter the second number in your problem.")
y = io.read()
print ("Please choose the operation you wish to perform.")
print ("Use 1 for addition, 2 for subtraction, 3 for multiplication, and 4 for division.")
op = io.read()
op = 1 then
function addition
op = 2 then
function subtraction
op = 3 then
function multiplication
op = 4 then
function division
print (answer)
io.read()
end
and my operations.lua script is
function addition
return answer = x+y
end
function subtraction
return answer = x-y
end
function multiplication
return answer = x*y
end
function division
return answer = x/y
end
I've tried using
if op = 1 then
answer = x+y
print(answer)
if op = 2 then
answer = x-y
print(answer)
and I did that completing each operation. But it doesn't work. I can't even get the error code that it's returning because it closes so fast. What should I do?
In your example, make these changes: You require operations.lua without the extension. Include parameters in your operations function definitions. Return the operation expression directly versus returning a statement like answer = x+y.
All together:
Code for operations.lua
function addition(x,y)
return x + y
end
--more functions go here...
function division(x,y)
return x / y
end
Code for your hosting Lua script:
require "operations"
result = addition(5,7)
print(result)
result = division(9,3)
print(result)
Once you get that working, try re-adding your io logic.
Keep in mind that as it's coded, your functions will be defined globally. To avoid polluting the global table, consider defining operations.lua as a module. Take a look at the lua-users.org Modules Tutorial.
The right if-then-else syntax:
if op==1 then
answer = a+b
elseif op==2 then
answer = a*b
end
print(answer)
After: please check the correct function-declaration syntax.
After: return answer=x+y is incorrect. If you want set answer's value, set without return. If you want return the sum, please use return x+y.
And I think you should check Programming in Lua.
First of all, learn to use the command line so you can see the errors (on Windows that would be cmd.exe).
Second, change the second line to require("operations"). The way you did it the interpreter expects a directory operations with an underlying script lua.lua.

Override a function that is imported in a namespace

As the termplot function in R is containing some weird code that is giving me annoying bugs, I want to override it in my own test code until I find a more permanent solution. Problem is that the changed function is not loaded by the mgcv package. The mgcv package loads termplot from the stats package in its namespace, using importFrom() in the NAMESPACE file.
How can I convince mgcv to use the changed termplot? I tried :
unlockBinding("termplot", as.environment("package:stats"))
assign("termplot", my.termplot, as.environment("package:stats"))
lockBinding("termplot", as.environment("package:stats"))
and when applied to lm-objects, this works and the altered termplot is used. But when using gam-objects made by the mgcv package, this doesn't work. I'm not really going to build the stats package from source if I can avoid it...
To clarify, I also tried with
assignInNamespace("termplot", my.termplot, ns="stats")
assignInNamespace("termplot", my.termplot, ns="mgcv")
in all possible combinations, before attaching mgcv, after attaching mgcv, and I didn't manage to get it working.
EDIT :
I tried all options given here (apart from rebuilding either package), and couldn't get it to work. The easy way out for me is using a wrapper function. That discussion can be found here. Thanks for all the tips.
A reproducible example :
my.termplot <- function (x) print("my new termplot")
unlockBinding("termplot", as.environment("package:stats"))
assignInNamespace("termplot", my.termplot, ns="stats", envir=as.environment("package:stats"))
assign("termplot", my.termplot, as.environment("package:stats"))
lockBinding("termplot", as.environment("package:stats"))
y <- 1:10
x <- 1:10
xx <- lm(y~x)
termplot(xx)
require(mgcv)
dat <- gamSim(1, n = 400, dist = "normal", scale = 2)
b <- gam(y ~ s(x0) + s(x1) + s(x2) + x3, data = dat)
plot(b,all=TRUE)
plot.gam calls termplot for the non-smooth terms (x3 in this case), but fails to find the new termplot function.
EDIT2 : apparently, my example works. I see now I solved my own question: In the first code, I didn't add both the namespace and the package in assignInNamespace. It is important to remember to change the function both in the namespace and the package before loading the other package. Thx #hadley for pointing me in the right direction, #Marek for testing the code and reporting it works, and the rest for taking the effort to answer.
I'm stumped - I can't figure out how plot.gam is locating termplot - it's not using the ordinary scoping rules as far as I can tell. This seems to need a deeper understanding of namespaces than I currently possess.
my.termplot <- function (x) print("my new termplot")
# where is it defined?
getAnywhere("termplot")
# in package and in namespace
unlockBinding("termplot", as.environment("package:stats"))
assign("termplot", my.termplot, "package:stats")
unlockBinding("termplot", getNamespace("stats"))
assign("termplot", my.termplot, getNamespace("stats"))
getAnywhere("termplot")[1]
getAnywhere("termplot")[2]
# now changed in both places
y <- 1:10
x <- 1:10 + runif(10)
xx <- lm(y ~ x)
termplot(xx) # works
library("mgcv")
b <- gam(y ~ s(x), data = data.frame(x, y))
plot(b) # still calls the old termplot
# I'm mystified - if try and find termplot as
# seen from the environment of plot.gam, it looks
# like what we want
get("termplot", environment(plot.gam))
Try overwriting the function that you are calling termplot from. At a guess, this is plot.gam in the mgcv package.
First load the necessary package.
library(mgcv)
Here's your alternate termplot function, added to the stats namespace.
my.termplot <- function (model, ...)
{
message("In my.termplot")
}
unlockBinding("termplot", as.environment("package:stats"))
assign("termplot", my.termplot, as.environment("package:stats"))
lockBinding("termplot", as.environment("package:stats"))
Likewise, here's the wrapper function, added to the mgcv namespace.
my.plot.gam <- function (x, ...)
{
message("In my.plot.gam")
my.termplot()
}
unlockBinding("plot.gam", as.environment("package:mgcv"))
assign("plot.gam", my.plot.gam, as.environment("package:mgcv"))
lockBinding("plot.gam", as.environment("package:mgcv"))
Here's an example to test it, taken from ?gam.
dat <- gamSim(1, n = 400, dist = "normal", scale = 2)
b <- gam(y ~ s(x0) + s(x1) + s(x2) + s(x3), data = dat)
plot(b)
I think the trace() function does automatically what is attempted above. Do:
trace('termplot', edit='gedit')
Where 'gedit' is the name of a text editor. The editor will open with the original code and you can paste whatever substitution code you desire.
To return to the original version just untrace('termplot')
Caveat: I tried using this when the text editor had many files open and it didn't work. So I use 'gedit', a text editor on my system that I don't use often. This way I am sure that R will open a new instance of 'gedit'.
I'm not positive this will help, but I think it's worth a try. The search sequence when there are namespaces is really confusing.