2015-08-16 3 views
1

Я пытаюсь получить вектор, который содержит сумму элементов, которые соответствуют условию.R: сумма вектор по вектору условий

values = runif(5000) 
    bin = seq(0, 0.9, by = 0.1) 
    sum(values < bin) 

Я ожидал, что сумма будет возвращать мне 10 значений - сумма элементов «ценности», которые соответствуют «<» состояние на каждый элемент «бен». Однако он возвращает только одно значение. Как я могу достичь результата без использования цикла while?

ответ

4

Я понимаю, это означает, что вы хотите, для каждого значения в bin, количество элементов в values, которые меньше bin. Так что я думаю, что вы хотите vapply() здесь

vapply(bin, function(x) sum(values < x), 1L) 
# [1] 0 497 1025 1501 1981 2461 2955 3446 3981 4526 

Если вы хотите немного таблицу для справки, можно добавить имена

v <- vapply(bin, function(x) sum(values < x), 1L) 
setNames(v, bin) 
# 0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 
# 0 497 1025 1501 1981 2461 2955 3446 3981 4526 
+0

В моем ответе, должны ли я получать те же результаты, что и вы в колонке cumsum, или вы выполняете другой расчет? Спасибо. – mpalanco

+0

Нет, из-за использования 'runif()' ни один из нас не будет иметь одинаковых результатов. –

+0

Извините, я не говорю, что я установил одно и то же семя, используя ваш код. Теперь я вижу, вы вычисляете совокупный счет, и я делал кумулятивную сумму. Я включил оба в мой ответ. – mpalanco

2

Использование tapply с -constructed вектором INDEX cut() кажется доставить:

tapply( values, cut(values, bin), sum) 
    (0,0.1] (0.1,0.2] (0.2,0.3] (0.3,0.4] (0.4,0.5] (0.5,0.6] 
25.43052 71.06897 129.99698 167.56887 222.74620 277.16395 
(0.6,0.7] (0.7,0.8] (0.8,0.9] 
332.18292 368.49341 435.01104 

Хотя я предполагаю, что вы хотите, чтобы вектор разреза простирался до 1,0:

bin = seq(0, 1, by = 0.1) 
tapply( values, cut(values, bin), sum) 

    (0,0.1] (0.1,0.2] (0.2,0.3] (0.3,0.4] (0.4,0.5] (0.5,0.6] 
25.48087 69.87902 129.37348 169.46013 224.81064 282.22455 
(0.6,0.7] (0.7,0.8] (0.8,0.9] (0.9,1] 
335.43991 371.60885 425.66550 463.37312 

Понятно, что я понял вопрос иначе, чем Ричард. Если вы хотите получить его результат, вы можете использовать cumsum по моему результату.

0

Использование dplyr:

set.seed(1) 
library(dplyr) 
df %>% group_by(groups) %>% 
    summarise(count = n(), sum = sum(values)) %>% 
    mutate(cumcount= cumsum(count), cumsum = cumsum(sum)) 

Выход:

 groups count  sum cumcount  cumsum 
1 (0,0.1] 537 26.43445  537 26.43445 
2 (0.1,0.2] 504 75.12241  1041 101.55686 
3 (0.2,0.3] 496 124.56939  1537 226.12625 
4 (0.3,0.4] 522 184.28862  2059 410.41487 
5 (0.4,0.5] 505 226.77295  2564 637.18782 
6 (0.5,0.6] 486 267.47094  3050 904.65876 
7 (0.6,0.7] 423 275.87466  3473 1180.53342 
8 (0.7,0.8] 478 359.65217  3951 1540.18559 
9 (0.8,0.9] 513 436.04508  4464 1976.23067 
10  NA 536 509.21853  5000 2485.44920 
3

Я лично предпочитаю data.table над tapply или vapply и findInterval над cut.

set.seed(1) 
library(data.table) 
dt <- data.table(values, groups=findInterval(values, bin)) 
setkey(dt, groups) 
dt[,.(n=.N, v=sum(values)), groups][,list(cumsum(n), cumsum(v)),] 
#  V1   V2 
# 1: 537 26.43445 
# 2: 1041 101.55686 
# 3: 1537 226.12625 
# 4: 2059 410.41487 
# 5: 2564 637.18782 
# 6: 3050 904.65876 
# 7: 3473 1180.53342 
# 8: 3951 1540.18559 
# 9: 4464 1976.23067 
#10: 5000 2485.44920 

cbind(vapply(bin, function(x) sum(values < x), 1L)[-1], 
cumsum(tapply( values, cut(values, bin), sum)))  
#   [,1]  [,2] 
#(0,0.1] 537 26.43445 
#(0.1,0.2] 1041 101.55686 
#(0.2,0.3] 1537 226.12625 
#(0.3,0.4] 2059 410.41487 
#(0.4,0.5] 2564 637.18782 
#(0.5,0.6] 3050 904.65876 
#(0.6,0.7] 3473 1180.53342 
#(0.7,0.8] 3951 1540.18559 
#(0.8,0.9] 4464 1976.23067 
Смежные вопросы