2012-04-11 3 views
8

Скажем, у меня есть вектор y, и я хочу проверить, является ли каждый элемент из y целым или нет, а если нет, остановитесь с сообщением об ошибке. Я пробовал is.integer (y), но это не работает.Как проверить, является ли каждый элемент вектора целым или нет в R?

+5

Это сложный вопрос, чтобы определить, что такое «целое число» или нет - вам нужно прояснить целое число в смысле «целое число» и целое число данных. Вы редко имеете дело с целым числом типа данных непосредственно в R (но это то, что есть.). Посмотрите на is.whole(), предоставленный Мартином Маэчлером здесь: https://stat.ethz.ch/pipermail/ r-help/2003-April/032471.html – mweylandt

+0

Когда вы останавливаетесь, вы хотите знать, где вы остановились ... т.е. какой из них не был целым? Вектор содержит только один тип данных. Таким образом, вы не можете означать целочисленный тип, только целое число как целое число. Даже это немного проблематично, потому что не все целые числа являются целыми числами точно. Вам также необходимо отклонение от целого числа. Добавьте ответы на эти вопросы на свой вопрос. – John

ответ

15

Самая простая (и самая быстрая!) Вещь, вероятно, такова:

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

... Так что попробуйте :

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

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

Если вы хотите лучше сообщение об ошибке:

y <- c(3, 9, NaN) 
if (!isTRUE(all(y == floor(y)))) stop("'y' must only contain integer values") 
+0

Обновлена ​​настраиваемая версия сообщения об ошибке для обработки NA/NaN ... – Tommy

9

вы могли бы сделать:

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

или

(y - round(y)) == 0 

и если вы хотите один TRUE или FALSE для всего этого, поместите его в all(), например:

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

Хорошо иметь значение TRUE/FALSE для каждого элемента, так как R является векторизованным языком. – Rodrigo

4

Не уверен, что быстрее Тим или это, но:

> 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" 
> 

или:

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

Вы можете использовать 'identity()' вместо 'all.equal()', так как 'all.equal (3.00000001,3L)' не действительно 'TRUE'. – BenBarnes

+0

@BenBarnes 'same (y, as.integer (y))' возвращает 'FALSE' для меня, но да, вы правы. Метод вычитания, вероятно, немного более глупый доказательство ... – Justin

+0

Я думаю, что @mweylandt и @ комментарии Джона о двусмысленности вопроса верны (и это то, к чему я пытался добраться). 'is.integer (2.0)' является 'FALSE', поскольку R видит это, но для других целей и целей это прекрасное целое число. – BenBarnes

2

Я пошел в совершенно ином направлении, то Тим (мне нравится его лучше, хотя мой подход работает на смешанном векторе, что это символ вектор с целыми числами и т.д.):

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: изменена функция, поскольку она работает только с символьными векторами.

Это работает и в векторах символа класса, если у вас есть вектор-символ с различным числом, смешанным, но с принуждением к символу.

+0

... но очень медленно. 'У <-1: 1e5; system.time (int.check (y)) 'занимает около 1,8 секунды. Моя версия занимает 0.01 или менее ;-) – Tommy

+0

О, да, это определенно не путь, если у вас есть числовой вектор, просто другой подход. Но посмотрите, как ваш подход работает на 'y <-c (1: 1e5," x ")';) –

+0

PS Я получаю 4.12 секунды не так уж плохо. –

6

Вот еще один способ (используя тот же трюк, как Джастин сравнения каждого числа к этому числу принуждается в тип «целое число»):

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 

Чтобы сделать тест:

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

Если вы с плавающей точкой ошибки представления, попробуйте:

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

В моем приложении, я был серьезно жестокую FLOATING точечная погрешность, такая как:

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

остаток, деленный на один, был одним. Я обнаружил, что мне пришлось округлить, прежде чем я взял целое число. Я думаю, что все тесты потерпели бы неудачу в случае, если вы хотели, чтобы вышеуказанное 89 считалось целым числом. Все.функция, равная»предназначаются, чтобы быть лучшим способом для обработки ошибки представления с плавающей запятой, но:

all.equal(88, 89); 

как в моем случае, был бы (и сделал) дал ложную отрицательный результат в течение проверки целого значения

.

EDIT: В бенчмаркинга, я обнаружил, что:

(x == as.integer(x)) 

был универсально лучший исполнитель

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

обычно работал хорошо, часто так же быстро.

(x %% 1 <= tolerance) 

работает, но не так быстро, как другие

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

, когда вектор не было числа, имели ужасный производительность (конечно, потому что он идет в проблему оценки разности).

identical(x, as.integer(x)) 

когда вектор был все целые значения, возвращаемые в неправильный результат (предполагается, что этот вопрос должен был проверить для целочисленных значений, а не целых типов).

1

Проверка следующих действий помогает с четким условием, которое мы можем использовать при написании сценариев.

sff <- 5 

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

дает

hello 

sff <- 'a' дает 'a' как результат.

+0

Можете ли вы объяснить, что делает условие? Я не могу. – eckes