2
votes

comment générer au hasard une séquence de liste qui n'est pas observée auparavant dans python 3

Supposons que j'ai le code en Python 3

newdata = [[1,6,6],[8,17,25],[2,6,11], [4,6,12]] 

Alors comment puis-je générer de manière aléatoire des éléments de données n (pas très volumineux) qui ne sont pas dans le données .

Condition: l'élément [a, b, c] ne doit pas être dans les données et 0 , 0 , 0

[1,3,5] est bon puisque il n'est pas dans data et son élément satisfait la condition

[11,3,6] est mauvais car il ne satisfait pas la condition, 11> 10

Par exemple, lorsque n = 4 , je veux une liste d'éléments qui ne sont pas dupliqués

X, Y, Z = 10, 20, 30
data = [[1,3,6],[8,15,29],[8,9,19]] # observe data


3 commentaires

Cela semble être un problème intéressant, pouvez-vous également inclure une tentative de codage raisonnable pour commencer?


@davedwards, je pense toujours. Ma méthode consiste à utiliser la technique de la force brute. comme générer tous les éléments possibles, puis sélectionner au hasard les n éléments qui ne sont pas dans les données . Mais ce n'est pas efficace.


Cela pourrait fonctionner, mais oui, la force brute n'est pas toujours efficace. Peut-être quelque chose comme générer random.randint (0, X) et vérifier que le résultat n'est pas dans la liste data , sinon, puis l'ajouter à la liste des nouvelles données?


4 Réponses :


0
votes

Cela a demandé un petit effort, mais cela semble fonctionner:

from random import *
from pprint import pprint

X, Y, Z = 10, 20, 30
data = [[1,3,6],[8,15,29],[8,9,19]]

while 1:
    newData = []
    try: n = int(input("How many lists do you want: "))
    except:
        print("Please enter an integer.\n")
        continue
    for i in range(n):
        newList = [randrange(1, X), randrange(1, Y), randrange(1, Z)]
        while (newList in data) or (newList in newData):
            newList = [randrange(1, X), randrange(1, Y), randrange(1, Z)]
        newData.append(newList)
    pprint(newData)

Cela fonctionne en créant une liste vide, en obtenant une valeur pour n, puis en entrant une boucle d'exactement n itérations. Il crée ensuite une nouvelle liste qui répond aux exigences. Si la nouvelle liste est dans la liste des données observées, elle le fait encore et encore jusqu'à ce qu'elle ne soit pas dans les données. Ensuite, il ajoute ces données à la liste de sortie et répète le processus jusqu'à ce que la boucle for soit interrompue (après n itérations).

Il peut y avoir une meilleure façon de le faire, mais cela fait l'affaire. >


0 commentaires

1
votes

Cela devrait le faire:

newdata = [(9, 9, 11), (10, 10, 4), (7, 6, 23), (2, 10, 4)]

Exemple de résultat:

from random import randint

X, Y, Z = 10, 20, 30
data = [[1,3,6],[8,15,29],[8,9,19]]
n = 4

newdata = set()

for i in range(n):
    while True:
    l = [randint(1, X), randint(1, Y), randint(1, Z)]
    if l not in data:
        newdata.add(tuple(l))
        break

print(newdata)


4 commentaires

Cela générera trop peu d'échantillons si l dans les données car cela rompt néanmoins la boucle. Le break doit être placé à l'intérieur du bloc if .


De plus, elle ne traite pas de l'unicité des échantillons générés, c'est-à-dire que cette approche permet les doublons. Cela nécessite une autre vérification je ne suis pas dans les nouvelles données , donc je vous recommande fortement d'utiliser un ensemble pour les données et newdata pour accélérer les tests d'adhésion.


@a_guest, c'est un bon point. Il semble que cette approche autorise les doublons.


@davedwards Vous devez toujours vérifier l not in newdata également (ou au lieu de la boucle for do while len (newdata) ) . À l'heure actuelle, il n'y a pas de doublons autorisés, mais cela générera trop peu d'échantillons au cas où des doublons seraient générés. Je recommande également de convertir les données en un ensemble avant d'exécuter l'algorithme pour améliorer les tests d'adhésion. Et vous pouvez créer l comme un tuple dès le début, ce qui économise une conversion supplémentaire.



0
votes

Dans le cas où X, Y, Z ne sont pas trop grands, vous pouvez simplement créer toutes les combinaisons possibles, puis échantillonner à partir de ce pool:

import itertools as it
import random

x, y, z = 10, 20, 30
pool = it.product(range(x), range(y), range(z))
data = [(1, 3, 6), (8, 15, 29), (8, 9, 19)]
pool = set(pool) - set(data)
n = 4
newdata = random.sample(pool, n)


0 commentaires

0
votes

Pour de meilleures performances, vous pouvez utiliser Numpy et le fait que les tuples peuvent être convertis en entier et inversement en les énumérant simplement (comme z, y, x est énuméré):

import numpy as np

x, y, z = 100, 200, 300
n = 1000

data = [[1,3,6],[8,15,29],[8,9,19]]
forbidden = [i[0]*y*z + i[1]*z + i[2] for i in data]
pool = np.arange(x*y*z)
mask = np.ones(pool.size, dtype=bool)
mask[forbidden] = False
pool = pool[mask]
newdata = np.random.choice(pool, n, replace=False)
newdata = [(i // (y*z), i // z, i % z) for i in newdata]


0 commentaires