[python] 두 개의 numpy 배열을 동시에 섞는 더 좋은 방법

모양이 다른 두 개의 numpy 배열이 있지만 길이는 동일합니다 (선행 치수). 해당 요소가 계속 일치하도록 각 요소를 섞고 싶습니다. 즉, 선행 지수와 관련하여 일치하게 섞습니다.

이 코드는 작동하며 내 목표를 보여줍니다.

def shuffle_in_unison(a, b):
    assert len(a) == len(b)
    shuffled_a = numpy.empty(a.shape, dtype=a.dtype)
    shuffled_b = numpy.empty(b.shape, dtype=b.dtype)
    permutation = numpy.random.permutation(len(a))
    for old_index, new_index in enumerate(permutation):
        shuffled_a[new_index] = a[old_index]
        shuffled_b[new_index] = b[old_index]
    return shuffled_a, shuffled_b

예를 들면 다음과 같습니다.

>>> a = numpy.asarray([[1, 1], [2, 2], [3, 3]])
>>> b = numpy.asarray([1, 2, 3])
>>> shuffle_in_unison(a, b)
(array([[2, 2],
       [1, 1],
       [3, 3]]), array([2, 1, 3]))

그러나 이것은 어색하고 비효율적이며 느리게 느껴지며 배열의 사본을 만들어야합니다.

이것에 대해 더 좋은 방법이 있습니까? 빠른 실행과 낮은 메모리 사용이 저의 주요 목표이지만, 우아한 코드도 좋습니다.

내가 가진 또 다른 생각은 이것입니다.

def shuffle_in_unison_scary(a, b):
    rng_state = numpy.random.get_state()
    numpy.random.shuffle(a)
    numpy.random.set_state(rng_state)
    numpy.random.shuffle(b)

이것은 효과가 있지만 … 계속 작동한다는 보장이 거의 없기 때문에 조금 무섭습니다.



답변

당신의 “무서운”해결책은 나에게 무서운 것처럼 보이지 않습니다. 호출 shuffle()난수 생성기에 대한 호출 같은 수의 같은 길이 결과의 두 시퀀스, 이들은 셔플 알고리즘에서 유일하게 “임의의”요소입니다. 상태를 재설정하면 난수 생성기에 대한 호출이에 대한 두 번째 호출에서 동일한 결과를 제공 shuffle()하므로 전체 알고리즘이 동일한 순열을 생성합니다.

이 방법이 마음에 들지 않으면 처음부터 두 개가 아닌 하나의 배열에 데이터를 저장하고이 단일 배열에 두 개의 뷰를 만들어 현재 두 배열을 시뮬레이션하는 다른 솔루션이 있습니다. 셔플 링에는 단일 배열을 사용하고 다른 모든 용도로는보기를 사용할 수 있습니다.

예 :하자가 배열 가정 ab같은 모양을 :

a = numpy.array([[[  0.,   1.,   2.],
                  [  3.,   4.,   5.]],

                 [[  6.,   7.,   8.],
                  [  9.,  10.,  11.]],

                 [[ 12.,  13.,  14.],
                  [ 15.,  16.,  17.]]])

b = numpy.array([[ 0.,  1.],
                 [ 2.,  3.],
                 [ 4.,  5.]])

이제 모든 데이터를 포함하는 단일 배열을 구성 할 수 있습니다.

c = numpy.c_[a.reshape(len(a), -1), b.reshape(len(b), -1)]
# array([[  0.,   1.,   2.,   3.,   4.,   5.,   0.,   1.],
#        [  6.,   7.,   8.,   9.,  10.,  11.,   2.,   3.],
#        [ 12.,  13.,  14.,  15.,  16.,  17.,   4.,   5.]])

이제 우리는 원래의 시뮬레이션 뷰 생성 ab:

a2 = c[:, :a.size//len(a)].reshape(a.shape)
b2 = c[:, a.size//len(a):].reshape(b.shape)

의 데이터 a2와는 b2함께 공유됩니다 c. 두 어레이를 동시에 섞으려면을 사용하십시오 numpy.random.shuffle(c).

프로덕션 코드에서는 물론 원본을 만드는 피하려고 것입니다 ab만들 즉시 전혀와 c, a2b2.

이 솔루션은 경우에 적용 할 수 ab다른 dtypes 있습니다.


답변

NumPy의 배열 인덱싱을 사용할 수 있습니다 .

def unison_shuffled_copies(a, b):
    assert len(a) == len(b)
    p = numpy.random.permutation(len(a))
    return a[p], b[p]

이로 인해 개별 셔플 배열이 생성됩니다.


답변

X = np.array([[1., 0.], [2., 1.], [0., 0.]])
y = np.array([0, 1, 2])
from sklearn.utils import shuffle
X, y = shuffle(X, y, random_state=0)

자세한 내용은 http://scikit-learn.org/stable/modules/generated/sklearn.utils.shuffle.html을 참조 하십시오.


답변

매우 간단한 해결책 :

randomize = np.arange(len(x))
np.random.shuffle(randomize)
x = x[randomize]
y = y[randomize]

두 배열 x, y는 이제 같은 방식으로 무작위로 섞입니다.


답변

James는 2015 년에 도움이되는 sklearn 솔루션 을 썼습니다 . 그러나 그는 불필요하게 임의의 상태 변수를 추가했습니다. 아래 코드에서는 numpy의 임의 상태가 자동으로 가정됩니다.

X = np.array([[1., 0.], [2., 1.], [0., 0.]])
y = np.array([0, 1, 2])
from sklearn.utils import shuffle
X, y = shuffle(X, y)


답변

from np.random import permutation
from sklearn.datasets import load_iris
iris = load_iris()
X = iris.data #numpy array
y = iris.target #numpy array

# Data is currently unshuffled; we should shuffle 
# each X[i] with its corresponding y[i]
perm = permutation(len(X))
X = X[perm]
y = y[perm]


답변

NumPy 만 사용하여 원하는 수의 배열을 제자리에 섞습니다.

import numpy as np


def shuffle_arrays(arrays, set_seed=-1):
    """Shuffles arrays in-place, in the same order, along axis=0

    Parameters:
    -----------
    arrays : List of NumPy arrays.
    set_seed : Seed value if int >= 0, else seed is random.
    """
    assert all(len(arr) == len(arrays[0]) for arr in arrays)
    seed = np.random.randint(0, 2**(32 - 1) - 1) if set_seed < 0 else set_seed

    for arr in arrays:
        rstate = np.random.RandomState(seed)
        rstate.shuffle(arr)

그리고 이렇게 사용할 수 있습니다

a = np.array([1, 2, 3, 4, 5])
b = np.array([10,20,30,40,50])
c = np.array([[1,10,11], [2,20,22], [3,30,33], [4,40,44], [5,50,55]])

shuffle_arrays([a, b, c])

몇 가지 참고할 사항 :

  • 어설 션은 모든 입력 배열이 첫 번째 차원을 따라 동일한 길이를 갖도록합니다.
  • 배열은 첫 번째 차원으로 제자리에서 뒤섞였으며 아무것도 반환되지 않았습니다.
  • 양의 int32 범위 내의 임의의 시드
  • 반복 가능한 셔플이 필요한 경우 시드 값을 설정할 수 있습니다.

셔플 후 np.split응용 프로그램에 따라 슬라이스를 사용하여 데이터를 분할 하거나 참조 할 수 있습니다 .