2016-01-26 14 views
6

Ho un vettore come di seguito:Come trovare la differenza tra un valore e il suo valore di armadio in un vettore in R?

x= c(1,23,4,15,8,17,21) 

dopo che i valori di ordinamento nel vettore abbiamo:

c(1,4,8,15,17,21,23) 

la mia uscita richiesto è:

c(3, 3, 4, 2, 2, 2, 2) 

che contiene la differenza tra il valore e il suo valore più vicino.

Ma se voglio avere output senza sort, c'è qualche soluzione? Ho bisogno di un out put come c (3,2,3,2,4,2,2) per sapere quale campione ha il maggior valore nella tabella di output (qui il 5 ° valore è il risultato)

+1

@PierreLafortune Ecco come ho capito il problema: prendere la differenza tra ogni elemento del vettore e qualsiasi altro elemento, restituire il minimo senza segno. – RHertel

+0

Quindi, in pratica, vuoi una funzione che sottrae tutto da tutto e stampa la differenza minima di ogni valore ...? – Sotos

+0

Il vettore non ordinato dovrebbe funzionare anche con la soluzione 'outer' che ho mostrato in precedenza. – akrun

risposta

13
d <- diff(sort(x)) 
pmin(c(d, NA), c(NA, d), na.rm = TRUE) 
# [1] 3 3 4 2 2 2 2 
+2

Molto bello, mi dimentico sempre di 'pmin'. Se utilizzato su un vettore di elementi 10e5 (quindi nemmeno così grandi), la tua soluzione è 38 volte più veloce della mia. – Heroka

+1

Grazie per tutte le soluzioni, ... Ma se voglio scoprire di mettere senza ordinare c'è qualche soluzione? come ... (3,2,3,2,4,2,2). – star

+3

@star, quindi potresti usare 'pmin (c (d, NA), c (NA, d), na.rm = TRUE) [match (x, sort (x))]'. – Julius

1

Si può farlo solo con forza bruta:

x <- c(1, 4, 8, 15, 17, 21, 23) 

n <- length(x) 
ds <- c(
    x[2] - x[1], 
    sapply(
    2:(n - 1), 
    function(i) min(x[i] - x[i - 1], x[i + 1] - x[i]) 
), 
    x[n] - x[n - 1] 
) 
7

Se ho capito bene, si vuole calcolare il valore più piccolo tra un membro di un vettore e suoi vicini.

In primo luogo, ordiniamo i dati.

x= sort(c(1,23,4,15,8,17,21)) 

Poi, si calcola la differenza con il vicino di sinistra (che manca per il punto 1) e la differenza con il vicino di casa a destra (che manca per la voce 2)

diffs <- cbind(c(NA,diff(x)),c(diff(x),NA)) 

Così, ora abbiamo la differenza a sinistra e destra per ciascuna voce, ora tutto quello che resta è quello di trovare il più piccolo:

res <- apply(diffs,MARGIN=1, min, na.rm=T) 

notare che, mentre questa soluzione contiene una spiegazione, altra condizione soluti ons (in particolare l'approccio pmin di @Julius) sono probabilmente più veloci quando le prestazioni sono un problema.

5

Si potrebbe provare:

library(dplyr) 
x <- sort(x) 
pmin(abs(x-lag(x)),abs(x-lead(x)),na.rm=T) 
#[1] 3 3 4 2 2 2 2 

x-lag(x) calcola la differenza con il numero più vicino più piccolo, x-lead(x) la differenza con il numero più grande più vicino.

7

Soluzioni carine. Julius 'sembra essere il più veloce:

library(microbenchmark) 
set.seed(1262016) 
x <- sample(1e5) 

all.equal(heroka, NicE, julius, Ambler) 
[1] TRUE 

microbenchmark(

    julius = {d <- diff(sort(x)) 
    pmin(c(d, NA), c(NA, d), na.rm = TRUE)}, 

    NicE = {x <- sort(x) 
    pmin(abs(x-lag(x)),abs(x-lead(x)),na.rm=T)}, 

    Heroka = {x= sort(x) 
    diffs <- cbind(c(NA,diff(x)),c(diff(x),NA)) 
    apply(diffs,MARGIN=1, min, na.rm=T)}, 

    Ambler = {n <- length(x) 
    ds <- c(
    x[2] - x[1], 
    sapply(
     2:(n - 1), 
     function(i) min(x[i] - x[i - 1], x[i + 1] - x[i]) 
    ), 
    x[n] - x[n - 1] 
)} 
) 
# Unit: milliseconds 
# expr  min   lq  mean  median  uq  max neval 
# julius 4.167302 5.066164 13.94478 7.967066 10.11920 89.06298 100 
# NicE  4.678274 6.804918 13.85149 9.297575 12.45606 83.41032 100 
# Heroka 142.107887 176.768431 199.96590 196.269671 221.05851 299.30336 100 
# Ambler 268.724129 309.238792 334.66432 329.252146 359.88103 409.38698 100 
+2

NicE si avvicina alla velocità, ma sono un fan delle soluzioni che non richiedono librerie aggiuntive. –

+0

Sono essenzialmente legati. Ma siccome la scala supera il milione, la soluzione di Julius risalta di più. –

Problemi correlati