14

Say, I have a vector y, and I want to check if each element in y is integer or not, and if not, stop with an error message. I tried is.integer(y), but it does not work.

2
  • 5
    It's sort of a hard question to define what exactly an "integer" is or not -- you need to clarify integer in the sense of "whole number" vs integer the data type. You rarely deal with the data type integer directly in R (but that's what is.integer tests for) -- take a look at is.whole() provided by Martin Maechler here: stat.ethz.ch/pipermail/r-help/2003-April/032471.html Commented Apr 11, 2012 at 21:06
  • When you stop do you want to know where you stopped... i.e. which one wasn't an integer first? A vector only contains one data type. So, you can't mean integer the type, only integer as in a whole number. Even that's a bit problematic because not all whole numbers are whole numbers exactly. You also need a tolerance of deviance from exactly a whole number. Add the answers to those things to your question. Commented Apr 11, 2012 at 21:15

7 Answers 7

19

The simplest (and fastest!) thing is probably this:

stopifnot( all(y == floor(y)) )

...So trying it out:

y <- c(3,4,9)
stopifnot( all(y == floor(y)) ) # OK

y <- c(3,4.01,9)
stopifnot( all(y == floor(y)) ) # ERROR!

If you want a better error message:

y <- c(3, 9, NaN)
if (!isTRUE(all(y == floor(y)))) stop("'y' must only contain integer values")
Sign up to request clarification or add additional context in comments.

1 Comment

What about the case where the input, here y, is c('A', 2, 3, 4)?
10

you could do:

   y <- c(3,3.1,1,2.3)
   (y - floor(y)) == 0
    [1]  TRUE FALSE  TRUE FALSE

or

   (y - round(y)) == 0

and if you want a single TRUE or FALSE for the whole thing, put it in all(), e.g.:

   all((y - round(y)) == 0)
    [1] FALSE

1 Comment

Good to have a TRUE/FALSE value for each element, since R is a vectorized language.
7

Here's another way (using the same trick as Justin of comparing each number to that number coerced into the 'integer' type):

R> v1 = c(1,2,3)
R> v2 = c(1,2,3.5)
R> sapply(v1, function(i) i == as.integer(i))
[1] TRUE TRUE TRUE
R> sapply(v2, function(i) i == as.integer(i))
[1]  TRUE  TRUE FALSE

To make your test:

R> all(sapply(v2, function(i) i == as.integer(i)))
[1] FALSE

Comments

4

Not sure which is faster Tim's way or this, but:

> x <- 1:5
> y <- c(x, 2.0)
> z <- c(y, 4.5)
> all.equal(x, as.integer(x))
[1] TRUE
> all.equal(y, as.integer(y))
[1] TRUE
> all.equal(z, as.integer(z))
[1] "Mean relative difference: 0.1111111"
> 

or:

all((z - as.integer(z))==0)

4 Comments

You could use identical() instead of all.equal(), since all.equal(3.00000001,3L) is not really TRUE.
@BenBarnes identical(y, as.integer(y)) returns FALSE for me, but yeah, you are correct. The subtraction technique is probably a little more fool proof...
I think @mweylandt and @John's comments about the ambiguity of the question are right on (and that's what I was trying to get at). is.integer(2.0) is FALSE as R sees it, but for other intents and purposes, it's a fine integer.
@BenBarnes Right again, more detail from the asker would help to determine what the correct approach(es) is/are.
3

I went in a completely different direction then Tim (I like his better though my approach works on a mixed vector that's a character vector with integers etc.):

int.check <- function(vect) {
    vect <- as.character(vect)
    sapply(vect, function(x) all(unlist(strsplit(x, ""))%in% 0:9))
}

x <- c(2.0, 1111,"x", 2.4)
int.check(x)

EDIT: altered the function as it only worked on character vectors.

This works on vectors of the class character as well in case you have a character vector with various number intermixed but that have been coerced to character.

4 Comments

...it is very slow though. y<-1:1e5; system.time( int.check(y) ) takes about 1.8 seconds. My version takes 0.01 or less ;-)
Oh yeah it's definitely not the way to go if you have a numeric vector, just a different take But see how your approach works on y<-c(1:1e5, "x") ; )
PS I get 4.12 seconds not too bad though.
BTW, shouldn't "1e6" be considered integer? int.check("1e6") returns FALSE.
1

checking the following helps with a crisp if condition which we can use on scripting.

sff <- 5

if(!(is.integer(sff) == is.character(sff))){ 
  sff
} else {
  "hello"
}

gives

hello

sff <- 'a' gives 'a' as the result.

1 Comment

Can you explain what the condition is doing? I cant.
0

If you have floating-point representation error, try:

round( y, TOLERANCE.DIGITS ) %% 1 == 0

In my application, I had seriously brutal floating-point representation error, such that:

> dictionary$beta[3]
[1] 89
> floor(dictionary$beta[3])
[1] 88
> as.integer( dictionary$beta )[3]
[1] 88
> dictionary$beta[3] %% 1
[1] 1

the remainder divided by one was one. I found that I had to round before I took the integer. I think all of these tests would fail in the case where you wanted the above 89 to count as an integer. The "all.equal" function is meant to be the best way to handle floating-point representation error, but:

all.equal( 88, 89 );

as in my case, would have (and did) given a false negative for an integer value check.

EDIT: In benchmarking, I found that:

(x == as.integer(x)) 

was universally the best performer.

(x == floor(x))
((x - as.integer(x)) == 0)

usually worked well, often just as fast.

(x %% 1 <= tolerance)

works, but not as quickly as the others

!(is.character(all.equal(x, as.integer(x)))) 

when the vector wasn't integers, had terrible performance (certainly because it goes to the trouble of estimating the difference).

identical(x, as.integer(x)) 

when the vector was all integer values, returned the incorrect result (assuming the question was meant to check for integer values, not integer types).

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.