1
votes

Ajuster la moyenne et l'écart type d'une liste de nombres aléatoires?

Je dois créer une liste de nombres aléatoires (avec décimales) compris entre -3 et 3. Le problème est que la liste doit avoir une moyenne de 0 et un écart-type de 1. Comment puis-je ajuster la moyenne et les paramètres d'écart type? Y a-t-il une fonction que je peux utiliser?

J'ai déjà pu créer une liste de nombres aléatoires entre -3 et 3.

import random


def lista_aleatorios(n):
    lista = [0] * n
    for i in range(n):
        lista[i] = random.uniform(-3, 3)
    return lista

print("\nHow many numbers do you want?: ")
n = int(input())

print (lista_aleatorios(n))


1 commentaires

Que voulez-vous dire exactement une moyenne de 0 ? La valeur moyenne de la distribution est différente de la valeur moyenne de l'échantillon - si je commence l'échantillonnage à partir de la gaussienne simple, N (0,1), sans limite, alors même si la moyenne de la distribution est 0, la moyenne d'échantillonnage serait différente et se fermerait à 0 lorsque le nombre de samples va à l'infini. Voulez-vous que la moyenne de distribution soit nulle? Ou vous voulez que la moyenne de l'échantillon (en fait, la somme) de toute séquence échantillonnée soit exactement zéro tout le temps? Ces deux conditions sont assez différentes


3 Réponses :


0
votes

La fonction random.normalvariate (mu, sigma) vous permet de spécifier la moyenne et le stdev pour des variables aléatoires normalement distribuées.


2 commentaires

Merci! Mais comment pourrais-je contrôler la plage de -3 à 3 en utilisant cette fonction? Salutations!


Je remarque également qu'avec cette fonction ou avec random.gauss (mu, sigma), le sd et la moyenne se rapprochent des valeurs que j'indique. Néanmoins, ce ne sont pas exactement ceux que j'ai établis. Y a-t-il un moyen d'ajuster cela?



0
votes

Utilisez random.gauss , puis mettez à l'échelle:

import numpy as np

from random import gauss

def bounded_normal(n, mean, std, lower_bound, upper_bound):

    # generate numbers between lower_bound and upper_bound

    result = []
    for i in range(n):
        while True:
            value = gauss(mean, std)
            if lower_bound < value < upper_bound:
                break

        result.append(value)

    # modify the mean and standard deviation

    actual_mean = np.mean(result)
    actual_std = np.std(result)
    mean_difference = mean - actual_mean
    std_difference = std / actual_std
    new_result = [(element + mean_difference) * std_difference for element in result]

    return new_result


7 commentaires

Agréable! Merci mon pote!


1. Il est généralement appelé gaussien tronqué / normal tronqué. 2. Vous venez de créer deux conditions difficiles sur les RV générés - la somme est égale à 0 et la somme des carrés égale à une autre valeur fixe. Ce n'est généralement pas ce que les gens veulent dire quand ils disent que la moyenne est zéro. 3. Après le décalage et la remise à l'échelle avant le retour, vous obtiendrez parfois des numéros hors limites.


@SeverinPappadeux que proposez-vous alors?


Si vous souhaitez rester avec en.wikipedia.org/wiki/Truncated_normal_distribution , alors jetez un œil aux formules là-bas. Fondamentalement, vous avez des valeurs de distribution (\ mu, \ sigma) que vous ne connaissez pas, et que vous voulez atteindre. Vous attribuez une expression moyenne de TN à la moyenne souhaitée, une expression de variance à stddev souhaitée ^ 2, deux équations pour deux inconnues, il y aurait une solution. Heureusement, \ mu va être 0 parce que min / max est symétrique et que la moyenne souhaitée est 0. Pour \ sigma, il va y avoir une équation non linéaire, qui pourrait être résolue puis (mu, sigma) échantillonnée à partir de


en utilisant ceci - stackoverflow.com/questions/18441779/... . Je m'attendrais à ce que \ sigma soit un peu plus grand que 1, mais pas de beaucoup. Fondamentalement, vous coupez des queues de gaussien, ce qui signifie que les échantillons sigma élevés ont disparu maintenant - vous devez compenser en élargissant légèrement la distribution.


s'il vous plaît également jeter un oeil à la question que j'ai posée à @Help, il devrait clarifier ce qu'il / elle veut dire / stddev


@gmds Veuillez jeter un œil à la réponse que j'ai fournie - elle suit de très près les commentaires



0
votes

Ok, voici une solution rapide (si vous voulez utiliser le gaussien tronqué). Définissez les limites et le stddev souhaité. Je suppose que la moyenne est égale à 0. Ensuite, un code rapide et grossier pour effectuer une recherche binaire pour la distribution sigma , en résolvant la racine non linéaire ( brentq () doit être utilisé en production code). Toutes les formules sont tirées de la page Wiki sur Truncated Normal . Il (sigma) doit être plus grand que le stddev souhaité du fait que la troncature supprime les valeurs aléatoires qui contribuent à un grand stddev. Ensuite, nous faisons un test d'échantillonnage rapide - et mean et stddev sont proches des valeurs souhaitées mais jamais exactement égales à elles. Code (Python-3.7, Anaconda, Win10 x64)

1.0153870105743408
-0.00015923177289006116
0.9999974266369461

Pour moi, il a imprimé

sigma = 1.0153870105743408
mean = -0.000400729471992301
stddev = 1.0024267696681475

avec une longueur de graine ou de séquence différente que vous pourriez obtenir sortie comme

import numpy as np
from scipy.special import erf
from scipy.stats import truncnorm

def alpha(a, sigma):
    return a/sigma

def beta(b, sigma):
    return b/sigma

def xi(x, sigma):
    return x/sigma

def fi(xi):
    return 1.0/np.sqrt(2.0*np.pi) * np.exp(-0.5*xi*xi)

def Fi(x):
    return 0.5*(1.0 + erf(x/np.sqrt(2.0)))

def Z(al, be):
    return Fi(be) - Fi(al)

def Variance(sigma, a, b):
    al = alpha(a, sigma)
    be = beta(b, sigma)
    ZZ = Z(al, be)

    return sigma*sigma*(1.0 + (al*fi(al) - be*fi(be))/ZZ - ((fi(al)-fi(be))/ZZ)**2)

def stddev(sigma, a, b):
    return np.sqrt(Variance(sigma, a, b))

m = 0.0 # mean
s =  1.0 # this is what we want
a = -3.0 # left boundary
b =  3.0 # right boundary

#print(stddev(s , a, b))
#print(stddev(s + 0.1, a, b))

slo = 1.0
shi = 1.1

stdlo = stddev(slo, a, b)
stdhi = stddev(shi, a, b)

sigma = -1.0
while True: # binary search for sigma
    sme = (slo + shi) / 2.0
    stdme = stddev(sme, a, b)
    if stdme - s == 0.0:
        sigma = stdme
        break
    elif stdme - s < 0.0:
        slo = sme
    else:
        shi = sme

    if shi - slo < 0.0000001:
        sigma = (shi + slo) / 2.0
        break

print(sigma) # we got it, shall be slightly bigger than s, desired stddev

np.random.seed(73123457)

rvs = truncnorm.rvs(a, b, loc=m, scale=sigma, size=1000000) # quick sampling test

print(np.mean(rvs))
print(np.std(rvs))


0 commentaires