Почему random.shuffle не работает в списках numpy? - PullRequest
1 голос
/ 10 февраля 2020

У меня есть массив векторов строк, на котором я запускаю random.shuffle:

#!/usr/bin/env python                                                                                                                                                                                                                                                

import random
import numpy as np

zzz = np.array([[0.1, 0.2, 0.3, 0.4, 0.5],
                [0.6, 0.7, 0.8, 0.9, 1. ]])

iterations = 100000
f = 0
for _ in range(iterations):
    random.shuffle(zzz)
    if np.array_equal(zzz[0], zzz[1]):
        print(zzz)
        f += 1

print(float(f)/float(iterations))

Между 99,6 и 100% времени, использование random.shuffle на zzz возвращает список с те же элементы в нем, например, :

$ ./test.py
...
[[ 0.1  0.2  0.3  0.4  0.5]
 [ 0.1  0.2  0.3  0.4  0.5]]
0.996

Использование numpy.random.shuffle, по-видимому, проходит этот тест и правильно перемешивает векторы строк. Мне любопытно узнать, почему random.shuffle терпит неудачу.

Ответы [ 3 ]

4 голосов
/ 10 февраля 2020

Если вы посмотрите на код файла random.shuffle, он выполнит перестановки следующим образом:

x[i], x[j] = x[j], x[i]

, который для numpy .array завершится ошибкой, без повышения ошибка. Пример:

>>> zzz[1], zzz[0] = zzz[0], zzz[1]
>>> zzz
array([[0.1, 0.2, 0.3, 0.4, 0.5],
       [0.1, 0.2, 0.3, 0.4, 0.5]])

Причина в том, что Python сначала полностью вычисляет правую часть, а затем выполняет назначение (именно поэтому с Python возможен однострочный своп), но для numpy массив это не правда.

numpy

>>> arr = np.array([[1],[1]])
>>> arr[0], arr[1] = arr[0]+1, arr[0]
>>> arr
array([[2],
       [2]])

Python

>>> l = [1,1]
>>> l[0], l[1] = l[0]+1, l[0]
>>> l
[2, 1]
0 голосов
/ 10 февраля 2020
In [200]: zzz = np.array([[0.1, 0.2, 0.3, 0.4, 0.5], 
     ...:                 [0.6, 0.7, 0.8, 0.9, 1. ]]) 
     ...:                                                                                      
In [201]: zl = zzz.tolist()                                                                    
In [202]: zl                                                                                   
Out[202]: [[0.1, 0.2, 0.3, 0.4, 0.5], [0.6, 0.7, 0.8, 0.9, 1.0]]

random.random, вероятно, использует назначение на месте, например:

In [203]: zzz[0],zzz[1]=zzz[1],zzz[0]                                                          
In [204]: zzz                                                                                  
Out[204]: 
array([[0.6, 0.7, 0.8, 0.9, 1. ],
       [0.6, 0.7, 0.8, 0.9, 1. ]])

Обратите внимание на репликацию.

Но применяется к списку списков:

In [205]: zl[0],zl[1]=zl[1],zl[0]                                                              
In [206]: zl                                                                                   
Out[206]: [[0.6, 0.7, 0.8, 0.9, 1.0], [0.1, 0.2, 0.3, 0.4, 0.5]]
In [207]: zl[0],zl[1]=zl[1],zl[0]                                                              
In [208]: zl                                                                                   
Out[208]: [[0.1, 0.2, 0.3, 0.4, 0.5], [0.6, 0.7, 0.8, 0.9, 1.0]]

Я протестировал zl = list(zzz) и все еще получил поведение массива. Это zl список с представлениями zzz. tolist составляет список списков, которые s totally independent of zzz`.

Короче говоря random.random не может правильно обрабатывать изменения на месте ndarray. np.random.shuffle предназначен для работы с 1-м dim массива, поэтому он правильно понимает.

правильное назначение для ndarray:

In [211]: zzz = np.array([[0.1, 0.2, 0.3, 0.4, 0.5], 
     ...:                 [0.6, 0.7, 0.8, 0.9, 1. ]]) 
     ...:                                                                                      
In [212]: zzz[[0,1]] = zzz[[1,0]]                                                              
In [213]: zzz                                                                                  
Out[213]: 
array([[0.6, 0.7, 0.8, 0.9, 1. ],
       [0.1, 0.2, 0.3, 0.4, 0.5]])
In [214]: zzz[[0,1]] = zzz[[1,0]]                                                              
In [215]: zzz                                                                                  
Out[215]: 
array([[0.1, 0.2, 0.3, 0.4, 0.5],
       [0.6, 0.7, 0.8, 0.9, 1. ]])
0 голосов
/ 10 февраля 2020

Попробуйте так:

#!/usr/bin/env python                                                                                                                                                                                                                                                

import random
import numpy as np

zzz = np.array([[0.1, 0.2, 0.3, 0.4, 0.5],
                [0.6, 0.7, 0.8, 0.9, 1. ]])

iterations = 100000
f = 0
for _ in range(iterations):
    random.shuffle(zzz[0])
    random.shuffle(zzz[1])
    if np.array_equal(zzz[0], zzz[1]):
        print(zzz)
        f += 1

print(float(f)/float(iterations))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...