Partage
  • Partager sur Facebook
  • Partager sur Twitter

"Aléatoire" dans deux intervalles

    2 février 2014 à 15:31:39

    Bonjour à tous !

    J'aimerais savoir s'il existe un moyen simple (du compliqué, je peux aussi en faire ^^) de tirer un nombre aléatoire appartenant non pas à un intervalle, mais à un parmi deux intervalles.

    Par exemple, je voudrais tirer un nombre appartenant à [-1;-0.5[U]0.5;1] : est-ce possible ?

    Merci d'avance :)

    -
    Edité par Turambar 2 février 2014 à 15:32:08

    • Partager sur Facebook
    • Partager sur Twitter
      2 février 2014 à 16:05:52

      ça ne me dit rien mais en attendant on peut tricher ;-)

      from random import uniform
      
      intervalle = [(-1, -0.5), (0.5, 1)]
      
      def tirage(intervalle):
          while 1:
              a = uniform(intervalle[0][0], intervalle[1][1])
              if a > intervalle[0][1] and a < intervalle[1][0]:
                  tirage(intervalle)
              else: return a
          
      print(tirage(intervalle))
      • Partager sur Facebook
      • Partager sur Twitter
        2 février 2014 à 16:11:29

        Tu peux définir deux intervalles tout simplement en les nommant de deux façons différentes ;)
        • Partager sur Facebook
        • Partager sur Twitter
          2 février 2014 à 16:13:56

          Oui, ça je sais faire, mais je voudrais une façon de le faire en une seule ligne, s'il existe une fonction permettant de le faire... mais merci quand même pour votre aide :p
          • Partager sur Facebook
          • Partager sur Twitter
          Anonyme
            2 février 2014 à 16:38:37

            def tirage(*args):
                return uniform(*choice(args))
            
            tirage((-1, -0.5), (0.5, 1))
            
            

            Non testé

            Ne pas oublier d'importer uniform et choice du module random...

            -
            Edité par Anonyme 2 février 2014 à 16:55:55

            • Partager sur Facebook
            • Partager sur Twitter
              2 février 2014 à 16:56:04

              Ça marche parfaitement, merci énormément :)
              • Partager sur Facebook
              • Partager sur Twitter
              Anonyme
                2 février 2014 à 16:57:01

                J'ai remodifié je pense qu'on peut faire plus léger
                • Partager sur Facebook
                • Partager sur Twitter
                  2 février 2014 à 17:00:38

                  PS : par contre, pourrais-tu, stp, m'expliquer le fonctionnement du *choice(args) ?
                  • Partager sur Facebook
                  • Partager sur Twitter
                  Anonyme
                    2 février 2014 à 17:05:09

                    choice est une fonction qui dans ce cas, va retourner un intervalle de type tuple

                    Le problème c'est que la fonction uniform prend deux arguments de type float, int et pas un tuple

                    En mettant l'étoile devant c'est comme si je faisais

                    x, y = choice(args)
                    n = uniform(x, y)
                    • Partager sur Facebook
                    • Partager sur Twitter
                      2 février 2014 à 17:11:10

                      Merci, je ne connaissais pas ça ;)
                      • Partager sur Facebook
                      • Partager sur Twitter
                        2 février 2014 à 17:14:16

                        Bonjour.

                        Choisir un intervalle puis tirer aléatoirement un nombre dedans n'aura pas la même distribution que de tirer aléatoirement un nombre dans l'union des 2 intervalles !!!

                        Par exemple pour des listes d'entiers (problème similaire), pour {1} U [[0;100]], tu auras 1 chance sur 2 de tirer 1 (dans l'ensemble {1}) alors que tu auras 1 chance sur 200 (=2*100) de tirer 99 (dans l'ensemble [[0;100]]).

                        La solution est de joindre les 2 intervalles :

                        import random
                        
                        I1 = (-1, -0.5)
                        I2 = (0.5, 1)
                        
                        I3 = (I1[0], I1[1]+I2[1]-I2[0])
                        res = random.uniform(I3[0], I3[1])
                        if I1[1] < res:
                        	res += I2[0]
                        print(res)

                        Il n'y a ici aucun contrôle sur les intervalles. Si tu veux faire quelque chose de propre il faudra vérifier qu'ils se superposent et qu'ils sont corrects.

                        • Partager sur Facebook
                        • Partager sur Twitter
                        Angular 2 est l'avenir, jQuery c'est de la merde !!! - Java 8 c'est l'an 2016+ (programmez en 1 ligne)
                          2 février 2014 à 17:43:07

                          Effectivement ; toutefois, dans le cas présent, mes deux intervalles sont de même taille, on devrait donc bien avoir une (pseudo-)équiprobabilité, non ?
                          • Partager sur Facebook
                          • Partager sur Twitter
                          Anonyme
                            2 février 2014 à 17:50:21

                            Salut, à la limite, je comprends pas pourquoi tu te prends la tête comme ça. Un petit

                            nb=random.uniform(-1;0)
                            nb+=(nb>=-0.5)
                            suffit, non ?

                            -
                            Edité par Anonyme 2 février 2014 à 17:52:44

                            • Partager sur Facebook
                            • Partager sur Twitter
                              2 février 2014 à 19:14:43

                              Salut,

                              Pour aller plus loin, on peut généraliser à plusieurs intervalles de largeur différente:

                              import random
                              import matplotlib.pyplot as plt
                              
                              def tirage(n, *intervalles):
                                  largeurs = [ max(i) - min(i) for i in intervalles ]
                                  s = sum(largeurs)
                                  def eggs(x):
                                      for idx, interv in enumerate(intervalles):
                                          if x < sum(largeurs[:idx+1]):
                                              return min(interv) + x - sum(largeurs[:idx])
                                  return [ eggs(random.uniform(0, s)) for _ in range(n) ]
                              
                              def main():
                                  intervalles = ( (-1., -0.6), (-0.4, -0.1), (0.4, 1.), (1.1, 2.) )
                                  res = tirage( int(1e6), *intervalles)
                              
                                  plt.hist(res, bins=60)
                                  plt.show()
                              
                              if __name__ == '__main__':
                                  main()
                              



                              -
                              Edité par azertymen 2 février 2014 à 19:24:11

                              • Partager sur Facebook
                              • Partager sur Twitter
                                2 février 2014 à 19:23:24

                                Turambar a écrit:

                                Effectivement ; toutefois, dans le cas présent, mes deux intervalles sont de même taille, on devrait donc bien avoir une (pseudo-)équiprobabilité, non ?

                                @dri1 a écrit:

                                Salut,
                                à la limite, je comprends pas pourquoi tu te prends la tête comme ça. Un petit

                                nb=random.uniform(-1;0)
                                nb+=(nb>=-0.5)

                                suffit, non ?


                                Comme tu l'as dit l'union d'intervalles que tu as cité n'était qu'un exemple, donc la solution que l'on te propose doit correspondre au problème et non à l'exemple ;)

                                • Partager sur Facebook
                                • Partager sur Twitter
                                Angular 2 est l'avenir, jQuery c'est de la merde !!! - Java 8 c'est l'an 2016+ (programmez en 1 ligne)

                                "Aléatoire" dans deux intervalles

                                × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                                × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                                • Editeur
                                • Markdown