I've got a function that uses readline to ask people to enter in data. But I'm at a loss as to the best method to insure that the data entered meet my criteria. I'm figuring "if" statements may be the best way to go to check for errors, but I'm not sure how to incorporate them. My attempt at using them is obviously flawed (see below).
As a simple example, 2 of the most likely problems I'm going to run into would be I'd like to insure that at least some value is entered in for x (and if a value is entered for x it is a number) and that V1 and V2 contain the same number of values.
fun<-function(){
T<-readline("What is x" )
if(T=="" | typeof(x)!=numeric)
{print("Input non-aceptable")
T<-readline("What is x ")}
else
V<-readline("Enter 4 values" )
V2<-readline("Enter 4 more values ")
if(length(V1)!=length(V2))
{print("V1 & V2 do not contain equal # of values")
V<-readline("Enter 4 values ")
V<-readline("Enter 4 more values ")}
else
T<-as.numeric(T)
V<-as.numeric(V)
V2<-as.numeric(V2)
return(list(x,V1,V2)
}
As you can see, my hope is to try and spot potential errors before they cause an actual error to happen, and then to give the person an opportunity to re-enter the data. If "if" statements are the way to go, can I get some help on using the correctly?
Thanks!
In R the boolean types TRUE and FALSE can also be represented by T and F. So first off try changing the variables that you have named T to something sensible... like x maybe???
Secondly, in your typeof(x) argument, you called the variable T, so that won't work. In addition there were no quotes around numeric. Try if(!(is.numeric(x)))
Thirdly, your variables are inconsistently named, V and V, and then V1 and V2. Aside from hard to read, it also just won't work.
Lastly, your return statement needs a second closing parenthesis, the function code block needs a closing curly brace.
Related
I'm trying to run an if statement, where I want to run something IF any of 23 values is below a certain value.
test.df<-as.data.frame(c(1:50))
if (test.df[,c(27:50)] <30){ print("hi")}
I get the error that the condition has length > 1 and only the first element will be used. Which is true... Does anyone know how I can test this if statement for 23 values, whithout having to type them one by one?
Thanks!
See the functions all or any, isTRUE and in newer versions of R, isFALSE, where the latter two to some degree takes care of fringe cases of NULLs and NAs.
For your example:
if (all(test.df[,c(27:50)] <30)) {
print("hi")
}
you can try this:
if (any(test.df[,c(27:50)] <30)){ print("hi")}
I am new to R and I have troubles understanding how displaying an index works.
# Find indices of NAs in Max.Gust.SpeedMPH
ind <- which(is.na(weather6$Max.Gust.SpeedMPH))
# Look at the full rows for records missing Max.Gust.SpeedMPH
weather6[ind, ]
My code here works, no problem but I don't understand why weather6[ind] won't display the same thing as weather6[ind, ] . I got very lucky and mistyped the first time.
I apologize in advance that the question might have been posted somewhere else, I searched and couldn't find a proper answer.
So [ is a function just like any other function in R, but we call it strangely. Another way to write it in this case would be:
'[.data.frame'(weather6,ind,)
or the other way:
'[.data.frame'(weather6,ind)
The first three arguments to the function are named x, i and j. If you look at the code, early on it branches with the line:
if (Narg < 3L)
Putting the extra comma tells R that you've called the function with 3 arguments, but that the j argument is "missing". Otherwise, without the comma, you have only 2 arguments, and the function code moves on the the next [ method for lists, in which it will extract the first column instead.
I want to check a list named "answer,if it contains FALSE element,then return a boolean (F),if there is no any FALSE element,in other words all TRUE,return a boolean (T)
here is the code(not good too many lines,but I don't know the easier one)
>answer=c(TRUE,FALSE,FALSE)
>l=length(answer)
>ind <- 1
>t=0
>f=0
>while(ind<(length(answer)+1)){
>ifelse(answer[ind]==TRUE,t<-t+1,f<-f+1)
>ind<-ind+1
>}
>ifelse(f>0,print("False"),print("True"))
This part code could give me right result.BUT it give me twice!!
like this:
[1] "True"
[1] "True"
WHY WHY give me twice...please help me I don't want to use this function so many lines
The reason you get the print twice is that ifelse(f>0,print("False"),print("True")) will first evaluate f>0 (which is TRUE), and then evaluate print("False") (which will result in "False" being printed to the console), and finally the ifelse will return the value of print("False") ("False") which will then be auto-printed to the console (the second print).
To get around the double print you could replace your last line with
> ifelse(f>0,"False","True")
Note however that neither this code or your code is returning booleans, both of them are returning character-strings. If you want a boolean you should instead use
> ifelse(f>0,FALSE,TRUE)
There are however a number of things that could be done to improve this code. You could use a for-loop to iterate directly over the answer vector (eliminating the need for the ind variable. Even better, you could use the fact that R is allowing you to add the value of two booleans (TRUE=1, and FALSE=0), so sum(answer) will give you the number of TRUE-values in the vector.
The easiest way to solve this is doing what baptiste is hinting at all(answer) will evaluate to TRUE if answer only contains TRUE-values, which seems to be what you want.
I've got a large function in R and the users have the ability to not include/specify an object. If they DO, the code checks to make sure the names in that object match the names in another. If they DON'T, there's no need to do that checking. The code line is:
if(exists("grids")) if(!all(expvarnames %in% names(grids))) {stop("Not all expvar column names found as column names in grids")}
But I'm getting the following error:
Error in match(x, table, nomatch = 0L) : argument "grids" is missing, with no default
Well in this trial run, grids is SUPPOSED to be missing. If I try
if(exists("grids")) print("yay")
Then nothing prints, i.e. the absence of grids means the expression isn't evaluated, which is as I'd expect. So can anyone think why R seems to be evaluating the subsequent IF statement in the main example? Should I slap another set of curly brackets around the second one??
Thanks!
Edit: more problems. Removing "grids," from the functions list of variables means it works if there's no object called grids and you don't specify it in the call (i.e. function(x,grids=whatever)). And keeping "grids," IN the functions list of variables means it works if there IS an object called grids and you do specify it in the call.
Please see this: http://i.imgur.com/9mr1Lwi.png
using exists(grids) is out because exists wants "quotes" and without em everything fails. WITH them ("grids"), I need to decide whether to keep "grids," in the functions list. If I don't, but I specify it in the call (function(x,grids=whatever)) then I get unused argument fail. If I DO, but don't specify it in the call because grids doesn't exist and I don't want to use it, I get match error, grids missing no default.
How do I get around this? Maybe list it in the function variables list as grids="NULL", then rather than if(exists("grids")) do if(grids!="NULL")
I still don't know why the original match problem is happening though. Match is from the expvarnames/grids names checker, which is AFTER if(exists("grids")) which evaluates to FALSE. WAaaaaaaiiiiittttt..... If I specify grids in the function variables list, i.e. simply putting function(x,grids,etc){do stuff}, does that mean the function CREATES an object called grids, within its environment?
Man this is so f'd up....
testfun <- function(x,grids)
{if(exists("grids")) globalgrids<<-grids
print(x+1)}
testfun(1) # Error in testfun(1) : argument "grids" is missing, with no default
testfun <- function(x,grids)
{if(exists("grids")) a<<-c(1,2,3)
print(x+1)}
testfun(1) #2 (and globally assigns a)
So in the first example, the function seems to have created an object called "grids" because exists("grids") evaluates to true. But THEN, ON THE SAME LINE, when asked to do something with grids, it says it doesn't exist! Schroedinger's object?!
This is proven in example 2: grids evaluates true and a is globally assigned then the function does its thing. Madness. Complete madness. Does anyone know WHY this ridiculousness is going on? And is the best solution to use my grids="NULL" default in the functions variables list?
Thanks.
Reproducible example, if you want to but I've already done it for every permutation:
testfun <- function(x,grids)
{if(exists("grids")) if(!all(expvarnames %in% names(grids))) {stop("Not all expvar column names found as column names in grids")}
print(x+1)}
testfun(1)
testfun(x=1,grids=grids)
grids<-data.frame(c(1,2,3),c(1,2,3),c(1,2,3))
expvarnames <- c("a","b","c")
colnames(grids) <- c("a","b","c")
Solution
Adapting your example use:
testfun <- function(x,grids = NULL)
{
if(!is.null(grids)){
if(!all(expvarnames %in% names(grids))){
stop("Not all expvar column names found as column names in grids")
}
print(x+1)
}
}
Using this testfun(1) will return nothing. By specifying a default argument in the function as NULL the function then checks for this (i.e. no argument specified) and then doesn't continue the function if so.
The Reason the Problem Occurs
We go through each of the examples:
testfun <- function(x,grids)
{if(exists("grids")) globalgrids<<-grids
print(x+1)}
testfun(1) # Error in testfun(1) : argument "grids" is missing, with no default
Here we call the function testfun, giving only the x argument. testfun knows it needs two arguments, and so creates local variables x and grids. We have then given an argument to x and so it assigns the value to x. There is no argument to grids, however the variable has still been created, even though no value has been assigned to it. So grids exists, but has no value.
From this exists("grids") will be TRUE, but when we try to do globalgrids<<-grids we will get an error as grids has not been assigned a value, and so we can't assign anything to globalgrids.
testfun <- function(x,grids)
{if(exists("grids")) a<<-c(1,2,3)
print(x+1)}
testfun(1) #2 (and globally assigns a)
This, however is fine. grids exists as in the previous case, and we never actually try and access the value stored in grids, which would cause an error as we have not assigned one.
In the solution, we simply set a default value for grids, which means we can always get something whenever we try and access the variable. Unlike in the previous cases, we will get NULL, not that nothing is stored there.
The main point of this is that when you declare arguments in your function, they are created each time you use the function. They exist. However, if you don't assign them values in your function call then they will exist, but have no value. Then when you try and use them, their lack of values will throw an error.
> a <- c(1,2,3,4)
> b <- c(2,4,6,8)
> if(exists("a")) if(!all(a %in% b)) {stop("Not all a in b")}
Error: Not all a in b
> rm(a)
> if(exists("a")) if(!all(a %in% b)) {stop("Not all a in b")}
>
When a does not exist, the expression does not evaluate, as expected. Before testing your first expression, make sure that grids does not exist by running rm(grids) in the console.
Richard Scriven's comment got me thinking: grids was an argument in my function but was optional, so maybe shouldn't be specified (like anything in "..." optional functions). I commented it out and it worked. Hooray, cheers everyone.
I wonder if there is a way to split a call to a function in R over several lines, other then using commas or '+' which is not always applicable.
I am basically looking like Python's '\' escape.
For example, I want to display this line:
PromoterIslands$illumina_probes[bins_with_probes]-tapply(CGIP_to_Probe$subjectHits,CGIP_to_Probe$subjectHits,function(x) length(x))
as:
PromoterIslands$illumina_probes[bins_with_probes]
<-tapply(CGIP_to_Probe$subjectHits,CGIP_to_Probe$subjectHits,
function(x) length(x))]
Is there any way to do this?
Thanks in advance
You can just split commands on various lines, no special sign needed.
The command you wrote is almost OK, you just need to put the <- operator on the first line.
So for instance, this is valid R code, and will assign 13 to a
a <-
5 +
8
But this is not
a
<- 5 +
8
Note, however, that this is valid code
a <-
5
+ 8
But would assign 5 to a and print 8.
Assuming you're talking about source (as opposed to desiring to get something to print a particular way), you can break R code in any place that doesn't produce a syntactically complete statement. There is no special character that tells R that the statement isn't complete. In your case, one option is:
PromoterIslands$illumina_probes[bins_with_probes] <-
tapply(
CGIP_to_Probe$subjectHits,
CGIP_to_Probe$subjectHits,
function(x) length(x)
)
You have to leave the <- at the end of the first line, otherwise PromoterIslands$illumina_probes[bins_with_probes] is a syntactically complete statement that would get evaluated. Similarly, on the next line, you have to leave the ( on the same line as tapply otherwise tapply is a syntactically complete statement (returns the contents of the tapply function).
While this doesn't quite answer your question, hopefully you will find there are enough places you can break a line in R that the lack of the special command you are looking for isn't a problem.