Comment représenter une variable illimitée sous forme de nombre entre 0 et 1

28

Je veux représenter une variable sous la forme d'un nombre compris entre 0 et 1. La variable est un entier non négatif sans limite inhérente. Je mappe 0 à 0, mais que puis-je mapper à 1 ou à des nombres entre 0 et 1?

Je pourrais utiliser l'historique de cette variable pour fournir les limites. Cela signifierait que je dois retraiter les anciennes statistiques si le maximum augmente. Dois-je le faire ou y a-t-il d'autres astuces à connaître?

Russell Gallop
la source
6
Parce que toute fonction non décroissante de fera l'affaire, vous avez beaucoup de flexibilité. Mais certaines méthodes seront meilleures que d'autres, selon l'application. Quel est votre but en recherchant une telle ré-expression? [0,)[0,1]
whuber
1
Je mesure le contenu à travers de nombreuses dimensions différentes et je veux pouvoir faire des comparaisons en termes de pertinence d'un élément de contenu donné. De plus, je veux afficher des valeurs à travers ces dimensions qui sont explicables et faciles à comprendre.
Spencer
1
@Spencer Exactement comment mesurez-vous le contenu et la «pertinence»? Par exemple, à des échelles arbitraires, comme les nombres, les proportions, les fréquences de vues, les corrélations avec d'autres contenus, etc. etc. Différents types de mesures bénéficient de différents types de ré-expressions.
whuber
1
Je les mesure à des échelles arbitraires. Quel âge a le contenu. Combien de "points" un élément de contenu est reçu. «Intérêt» autodéclaré dans le domaine du contenu.
Spencer
2
L'une des transformations les plus simples que vous pourriez utiliser consiste à convertir vos données en scores quantiles.
charles.y.zheng

Réponses:

34

Une astuce très courante pour le faire (par exemple, dans la modélisation connexionniste) consiste à utiliser la tangente hyperbolique tanh comme «fonction d'écrasement». Elle ajuste automatiquement tous les nombres dans l'intervalle entre -1 et 1. Ce qui dans votre cas restreint la plage de 0 à 1. Dans ret matlabvous l'obtenez via tanh().

Une autre fonction d'écrasement est la fonction logistique (merci à Simon pour le nom), fournie par , qui restreint la plage de 0 à 1 (avec 0 mappé à. 5). Vous devrez donc multiplier le résultat par 2 et soustraire 1 pour adapter vos données dans l'intervalle entre 0 et 1.f(x)=1/(1+ex)

Voici un code R simple qui trace les deux fonctions (tanh en rouge, logistique en bleu) afin que vous puissiez voir comment les deux écrasent:

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")
Henrik
la source
Merci pour votre réponse. Cela résout le problème de délimitation. Pour mes données, il passe à 1 très rapidement pour mes données, donc je suppose que la prochaine chose que je dois faire est de mettre à l'échelle ces informations pour me concentrer sur la plage intéressante que je pourrais faire en fonction de l'historique sans craindre de quitter la limite, juste atteindre la limite.
Russell Gallop
25

Comme souvent, ma première question allait être « pourquoi voulez-vous faire cela», alors j'ai vu que vous avez déjà répondu à cela dans les commentaires à la question: « Je mesure le contenu à travers de nombreuses dimensions différentes et je veux être capable de faire des comparaisons en termes de pertinence d'un élément de contenu donné. En outre, je souhaite afficher des valeurs explicatives et faciles à comprendre dans ces dimensions. "

Il n'y a aucune raison de normaliser les données afin que le max soit 1 et le min soit zéro pour y parvenir, et mon avis est que ce serait une mauvaise idée en général . Les valeurs max ou min pourraient très facilement être des valeurs aberrantes non représentatives de la répartition de la population. La remarque de séparation @osknows sur l' utilisation des scores est une bien meilleure idéez . scores (ou scores standard) normalisent chaque variable en utilisant son écart type plutôt que sa plage. L'écart type est moins influencé par les valeurs aberrantes. Pour utiliserzzz-les scores, il est préférable que chaque variable ait une distribution à peu près normale, ou au moins une distribution à peu près symétrique (c'est-à-dire qu'elle ne soit pas gravement asymétrique) mais si nécessaire, vous pouvez d'abord appliquer une transformation de données appropriée afin d'y parvenir; quelle transformation utiliser pourrait être déterminée en trouvant la transformation de Box – Cox la mieux adaptée .

un arrêt
la source
donc il n'y a rien à voir avec le forçage des données vers le , et en général je suis d'accord avec la standardisation si l'auteur la recherche vraiment :) J'ai répondu avant que la discussion n'apparaisse, donc supprimez probablement ma réponse si celle-ci est correct :)[0,1]
Dmitrij Celov
1
Si l'on s'inquiète des valeurs aberrantes, on pourrait envisager d'utiliser l'écart médian absolu (par rapport à la médiane) au lieu de l'écart type. Dans R, utilisez la mad()fonction. Et si l'on s'inquiète de l'asymétrie, on peut utiliser les rangs des données au lieu des observations originales. Dans R, ce serait le cas rank(), mais si l'on veut l' utiliser sur de nouvelles données, ce ecdf()serait une meilleure alternative ( ecdf(x)renvoie une nouvelle fonction qui donne fondamentalement la valeur au -quantile de , par exemple, 0 (vraiment ) à la valeur la plus basse de , à la valeur la plus élevée, 0,5 à la médiane, etc.)p x 1 / n x 1ppx1/nx1
Karl Ove Hufthammer
10

Toute fonction sigmoïde fonctionnera:

Simon Byrne
la source
erf n'est pas une fonction très pratique, à condition de ne pas l'utiliser plutôt pour son dérivé.
J'ai fini par utiliser une fonction logistique simple avec quelques petits ajustements: (1 / (1 + java.lang.Math.exp (-1 * (factor * i))) - 0,5) * 2. J'ai choisi un facteur de 0,05 qui semble bien fonctionner pour i entre 0 et quelques centaines.
Jilles van Gurp
1.0 / (1.0 + exp (-1.69897 * (x-mean (x)) / sd (x))) est une approximation proche de pnorm
Chris
3

En plus des bonnes suggestions de Henrik et Simon Byrne, vous pouvez utiliser f (x) = x / (x + 1). À titre de comparaison, la fonction logistique va exagérer les différences à mesure que x augmente. Autrement dit, la différence entre f (x) et f (x + 1) sera plus grande avec la fonction logistique qu'avec f (x) = x / (x + 1). Vous pouvez ou non vouloir cet effet.


la source
1

Mon article précédent a une méthode pour classer entre 0 et 1. Conseils sur la corrélation d'entrée du classificateur

Cependant, le classement que j'ai utilisé, Tmin / Tmax utilise l'échantillon min / max mais vous pouvez trouver la population min / max plus appropriée. Recherchez également les scores z

osknows
la source
1

Pour ajouter aux autres réponses suggérant pnorm ...

Pour une méthode potentiellement optimale de sélection des paramètres, je suggère cette approximation pour pnorm.

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

pnormish

Il s'agit essentiellement de la normalisation Softmax.

Pnorm de référence dans un pincement

Chris
la source
1

Il existe deux façons d'implémenter cela que j'utilise couramment. Je travaille toujours avec des données en temps réel, donc cela suppose une entrée continue. Voici un pseudo-code:

Utilisation d'un minmax entraînable:

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]

Cette fonction nécessite soit que vous effectuiez une phase de formation initiale (en utilisant calibrate()) soit que vous vous entraîniez à certains intervalles ou selon certaines conditions. Par exemple, imaginez une fonction comme celle-ci:

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

le pic et le creux ne reçoivent normalement pas de valeurs, mais s'ils outBounds()reçoivent une valeur qui est plus de 1,5 fois le pic actuel ou moins que le creux actuel divisé par 1,5, alors calibrate()est appelé, ce qui permet à la fonction de se recalibrer automatiquement.

Utilisation d'un minmax historique:

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
terrasse
la source
Tout cela peut être implémenté dans Max / MSP / Jitter avec les objets [peak] et [trough] pour le premier exemple et avec [jit.3m] pour le deuxième exemple.
terrasse du
0

Une option très simple consiste à diviser chaque nombre de vos données par le plus grand nombre de vos données. Si vous avez beaucoup de petits nombres et quelques très grands, cela pourrait ne pas bien transmettre l'information. Mais c'est relativement facile; si vous pensez que des informations significatives sont perdues lorsque vous représentez graphiquement les données comme ceci, vous pouvez essayer l'une des techniques les plus sophistiquées que d'autres ont suggérées.

DanB
la source