Come rappresentare una variabile senza limiti come numero compreso tra 0 e 1


28

Voglio rappresentare una variabile come un numero compreso tra 0 e 1. La variabile è un numero intero non negativo senza limite intrinseco. Mappa da 0 a 0 ma cosa posso mappare a 1 o numeri tra 0 e 1?

Potrei usare la cronologia di quella variabile per fornire i limiti. Ciò significherebbe che dovrei riformulare vecchie statistiche se il massimo aumenta. Devo farlo o ci sono altri trucchi che dovrei conoscere?


6
Poiché qualsiasi funzione non decrescente da farà il trucco, hai molta flessibilità. Ma alcuni metodi saranno migliori di altri, a seconda dell'applicazione. Qual è il tuo scopo nel cercare una re-espressione? [0,)[0,1]
whuber

1
Sto misurando il contenuto in molte dimensioni diverse e voglio essere in grado di fare confronti in termini di pertinenza di un determinato contenuto. Inoltre, voglio visualizzare valori attraverso queste dimensioni che siano spiegabili e facilmente comprensibili.
Spencer,

1
@Spencer Esattamente come stai misurando il contenuto e la "pertinenza"? Ad esempio, su scale arbitrarie, come conteggi, proporzioni, frequenze di viste, correlazioni con altri contenuti, ecc. Ecc. Diversi tipi di misurazioni beneficiano di diversi tipi di re-espressioni.
whuber

1
Li sto misurando su scale arbitrarie. Quanti anni ha il contenuto. Quanti "punti" viene ricevuto un contenuto. "Interesse" auto-segnalato nel dominio del contenuto.
Spencer,

2
Una delle trasformazioni più semplici che potresti utilizzare è quella di convertire i tuoi dati in punteggi quantili.
charles.y.zheng

Risposte:


34

Un trucco molto comune per farlo (ad es. Nella modellistica connessionista) è usare la tanh tangente iperbolica come 'funzione di schiacciamento'. Adatta automaticamente tutti i numeri nell'intervallo tra -1 e 1. Che nel tuo caso limita l'intervallo da 0 a 1. In re matlablo ottieni via tanh().

Un'altra funzione di compressione è la funzione logistica (grazie a Simon per il nome), fornita da , che limita l'intervallo da 0 a 1 (con 0 mappato a. 5). Quindi dovresti moltiplicare il risultato per 2 e sottrarre 1 per adattare i tuoi dati nell'intervallo tra 0 e 1.f(X)=1/(1+e-X)

Ecco un semplice codice R che traccia entrambe le funzioni (tanh in rosso, logistica in blu) in modo da poter vedere come entrambe le squash:

x <- seq(0,20,0.001)
plot(x,tanh(x),pch=".", col="red", ylab="y")
points(x,(1 / (1 + exp(-x)))*2-1, pch=".",col="blue")

Grazie per la tua risposta. Questo risolve il problema del limite. Per i miei dati va a 1 molto rapidamente per i miei dati, quindi immagino che la prossima cosa che devo fare sia ridimensionare queste informazioni per concentrarmi sull'interessante intervallo che potrei fare in base alla loro storia senza paura di lasciare il limite, solo colpire il limite.
Russell Gallop,

25

Come spesso, la mia prima domanda sarebbe stata " perché vuoi farlo", poi ho visto che hai già risposto a questo nei commenti alla domanda: " Sto misurando il contenuto in molte dimensioni diverse e voglio essere in grado di fare confronti in termini di pertinenza di un determinato contenuto. Inoltre, desidero visualizzare valori spiegabili e facilmente comprensibili in queste dimensioni " .

Non c'è motivo di normalizzare i dati in modo che il massimo sia 1 e il minimo sia zero per raggiungere questo obiettivo, e la mia opinione è che questa sarebbe una cattiva idea in generale . I valori massimo o minimo potrebbero facilmente essere valori anomali che non rappresentano la distribuzione della popolazione. L'osservazione di separazione di @osknows sull'uso di -scores è un'idea molto migliorez . punteggi (noti anche come punteggi standard) normalizzano ogni variabile usando la sua deviazione standard anziché il suo intervallo. La deviazione standard è meno influenzata dai valori anomali. Per usarezz-scores, è preferibile che ogni variabile abbia una distribuzione approssimativamente normale, o almeno abbia una distribuzione approssimativamente simmetrica (cioè non è fortemente inclinata) ma se necessario è possibile applicare prima una trasformazione dei dati appropriata per raggiungere questo obiettivo; quale trasformazione usare potrebbe essere determinata trovando la trasformazione Box-Cox più adatta .


quindi non c'è nulla a che fare con il forzare i dati a , e in generale sono d'accordo con la standardizzazione se l'autore la cerca davvero :) Ho risposto prima che apparisse la discussione, quindi probabilmente cancella la mia risposta se questa è corretto :)[0,1]
Dmitrij Celov

1
Se uno è preoccupato per i valori anomali, si potrebbe prendere in considerazione l'uso della deviazione assoluta mediana (dalla mediana) invece della deviazione standard. In R, usa la mad()funzione. E se uno è preoccupato per l'asimmetria, si possono usare i ranghi dei dati invece delle osservazioni originali. In R, questo sarebbe rank(), ma se uno lo utilizzerà su nuovi dati, ecdf()sarebbe un'alternativa migliore ( ecdf(x)restituisce una nuova funzione che sostanzialmente dà il valore al -quantile di , ad es. 0 (davvero ) al valore più basso di , al valore più alto, 0,5 alla mediana ecc.)ppX1/nX1
Karl Ove Hufthammer,

10

Qualsiasi funzione sigmoid funzionerà:


erf non è una funzione molto utile, a condizione che non si desideri piuttosto usarlo per i suoi derivati.

Ho finito per usare una semplice funzione logistica con alcune piccole modifiche: (1 / (1 + java.lang.Math.exp (-1 * (fattore * i))) - 0,5) * 2. Ho scelto un fattore di 0,05 che sembra funzionare bene per i tra 0 e alcune centinaia.
Jilles van Gurp,

1.0 / (1.0 + exp (-1.69897 * (x-mean (x)) / sd (x))) è una stretta approssimazione di pnorm
Chris

3

Oltre ai buoni suggerimenti di Henrik e Simon Byrne, puoi usare f (x) = x / (x + 1). A titolo di confronto, la funzione logistica esagererà le differenze man mano che x diventa più grande. Cioè, la differenza tra f (x) ef (x + 1) sarà maggiore con la funzione logistica che con f (x) = x / (x + 1). Potresti o meno volere quell'effetto.



1

Per aggiungere alle altre risposte suggerendo pnorm ...

Per un metodo potenzialmente ottimale per la selezione dei parametri suggerisco questa approssimazione per pnorm.

1.0/(1.0+exp(-1.69897*(x-mean(x))/sd(x)))

pnormish

Questa è essenzialmente la normalizzazione di Softmax.

Riferimento Pnorm in un pizzico


1

Esistono due modi per implementare questo che uso comunemente. Lavoro sempre con dati in tempo reale, quindi questo presuppone un input continuo. Ecco alcuni pseudo-codice:

Utilizzando una minmax allenabile:

define function peak:
    // keeps the highest value it has received

define function trough:
    // keeps the lowest value it has received

define function calibrate:
    // toggles whether peak() and trough() are receiving values or not

define function scale:
    // maps input range [trough.value() to peak.value()] to [0.0 to 1.0]

Questa funzione richiede che tu esegua una fase iniziale di allenamento (usando calibrate()) o che ti alleni di nuovo a determinati intervalli o in base a determinate condizioni. Ad esempio, immagina una funzione come questa:

define function outBounds (val, thresh):
    if val > (thresh*peak.value()) || val < (trough.value() / thresh):
        calibrate()

il picco e il trogolo normalmente non ricevono valori, ma se outBounds()riceve un valore superiore di 1,5 volte il picco corrente o inferiore al trogolo corrente diviso per 1,5, calibrate()viene chiamato che consente alla funzione di ricalibrare automaticamente.

Utilizzando una minmax storica:

var arrayLength = 1000
var histArray[arrayLength]

define historyArray(f):
    histArray.pushFront(f) //adds f to the beginning of the array

define max(array):
    // finds maximum element in histArray[]
    return max

define min(array):
    // finds minimum element in histArray[]
    return min

define function scale:
    // maps input range [min(histArray) to max(histArray)] to [0.0 to 1.0]

main()
historyArray(histArray)
scale(min(histArray), max(histArray), histArray[0])
// histArray[0] is the current element

Tutto ciò può essere implementato in Max / MSP / Jitter con gli oggetti [peak] e [trough] per il primo esempio e con [jit.3m] per il secondo esempio.
terrazza

0

Un'opzione molto semplice è quella di dividere ogni numero nei tuoi dati per il numero più grande nei tuoi dati. Se hai molti numeri piccoli e alcuni numeri molto grandi, questo potrebbe non trasmettere bene le informazioni. Ma è relativamente facile; se ritieni che informazioni significative vadano perse quando grafici i dati in questo modo, potresti provare una delle tecniche più sofisticate che altri hanno suggerito.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.