생성기에서 numpy 배열을 어떻게 작성합니까?


166

생성기 객체에서 numpy 배열을 어떻게 만들 수 있습니까?

문제를 설명해 드리겠습니다.

>>> import numpy
>>> def gimme():
...   for x in xrange(10):
...     yield x
...
>>> gimme()
<generator object at 0x28a1758>
>>> list(gimme())
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> numpy.array(xrange(10))
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
>>> numpy.array(gimme())
array(<generator object at 0x28a1758>, dtype=object)
>>> numpy.array(list(gimme()))
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

이 경우 gimme()출력을 배열로 바꾸고 싶은 발전기입니다. 그러나 배열 생성자는 생성기를 반복하지 않고 단순히 생성기 자체를 저장합니다. 내가 원하는 동작은 from numpy.array(list(gimme()))이지만, 중간 목록과 최종 배열을 메모리에 동시에 갖는 메모리 오버 헤드를 지불하고 싶지 않습니다. 더 공간 효율적인 방법이 있습니까?


6
이것은 흥미로운 문제입니다. 나는 이것을 붙 잡았 from numpy import *; print any(False for i in range(1))습니다. 내장을 어둡게 any()하고 반대 결과를 얻습니다 (지금 알고있는 것처럼).
moooeeeep 2016 년

4
@moooeeeep 끔찍합니다. 경우 numpy없는 (또는 원치 않는)은 인수로 발전기를 받으면 파이썬 적어도 예외를 제기해야 않는 치료 용 발전기.
최대

1
@max 나는 정확히 같은 광산을 밟았습니다. 분명히 이것은 NumPy 목록 (및 이전 )에서 제기되어 예외가 발생하도록 변경되지 않으며 항상 네임 스페이스를 사용해야한다고 결론 내 렸습니다.
alexei

답변:


128

Numpy 배열은 파이썬 목록과 달리 작성 시간에 명시 적으로 길이를 설정해야합니다. 각 항목의 공간을 메모리에 연속적으로 할당 할 수 있도록하기 위해 필요합니다. 연속 할당은 numpy 배열의 주요 기능입니다. 네이티브 코드 구현과 결합하면 일반 목록보다 훨씬 빠르게 작업을 실행할 수 있습니다.

이를 염두에두고 다음 중 하나가 아니면 발전기 객체를 가져 와서 배열로 만드는 것은 기술적으로 불가능합니다.

  1. 실행할 때 얼마나 많은 요소가 생성되는지 예측할 수 있습니다.

    my_array = numpy.empty(predict_length())
    for i, el in enumerate(gimme()): my_array[i] = el
  2. 중간 목록에 요소를 기꺼이 저장합니다.

    my_array = numpy.array(list(gimme()))
  3. 두 개의 동일한 생성기를 만들고 첫 번째 생성기를 통해 전체 길이를 찾은 다음 배열을 초기화 한 다음 생성기를 다시 실행하여 각 요소를 찾을 수 있습니다.

    length = sum(1 for el in gimme())
    my_array = numpy.empty(length)
    for i, el in enumerate(gimme()): my_array[i] = el

1 은 아마도 당신이 찾고있는 것입니다. 2 는 공간이 비효율적이며 3 은 시간이 비효율적입니다 (발전기를 두 번 통과해야 함).


11
내장 array.array은 연결되지 않은 연속 된 목록이며 간단하게 할 수 있습니다 array.array('f', generator). 불가능하다고 말하면 오해의 소지가 있습니다. 그것은 단지 동적 할당입니다.
Cuadue 2019

1
Cuadue가 말한 것처럼 numpy.array가 내장 array.array와 동일한 방식으로 메모리 할당을 수행하지 않는 이유는 무엇입니까? 거래는 무엇입니까? 두 예제 모두에 연속 할당 된 메모리가 있기 때문에 묻습니다. 아님?
jgomo3

3
numpy는 배열 크기가 변경되지 않는 것으로 가정합니다. 동일한 메모리 청크의 다른 뷰에 크게 의존하므로 배열을 확장하고 재 할당하려면 뷰를 활성화하기 위해 추가 간접 계층이 필요합니다.
joeln

2
공란을 사용하는 것이 조금 더 빠릅니다. 어떤 식 으로든 값을 초기화 할 예정이므로이 작업을 두 번 수행 할 필요가 없습니다.
Kaushik Ghose

또한 @dhill의 답변은 1보다 빠릅니다.
Bill

206

이 stackoverflow 결과 뒤에 하나의 Google이 있습니다 numpy.fromiter(data, dtype, count). 디폴트 count=-1는 iterable에서 모든 요소를 ​​가져옵니다. a dtype를 명시 적으로 설정 해야합니다 . 제 경우에는 다음과 같이 작동했습니다.

numpy.fromiter(something.generate(from_this_input), float)


이것을 질문에 어떻게 적용 하시겠습니까? numpy.fromiter(gimme(), float, count=-1)작동하지 않습니다. 무엇 something을 의미합니까?
Matthias 009

1
@ Matthias009 numpy.fromiter(gimme(), float, count=-1)가 나를 위해 일합니다.
moooeeeep 2016 년

14
설명 스레드는 이유는 fromiter단지 1 차원 배열에서 작동 : mail.scipy.org/pipermail/numpy-discussion/2007-August/... .
최대

2
fwiw count=-1는 기본값이므로 지정할 필요가 없습니다.
askewchan

5
iterable의 길이를 미리 알고 있으면 count성능을 향상 시키도록 지정하십시오 . 이렇게하면 필요에 따라 크기를 조정하는 대신 값으로 메모리를 채우기 전에 메모리를 할당합니다 (설명서 참조 numpy.fromiter)
Eddy

15

을 사용하여 생성기에서 1D 배열을 생성 할 수 있지만 다음을 사용하여 생성기 numpy.fromiter()에서 ND 배열을 생성 할 수 있습니다 numpy.stack.

>>> mygen = (np.ones((5, 3)) for _ in range(10))
>>> x = numpy.stack(mygen)
>>> x.shape
(10, 5, 3)

1D 배열에서도 작동합니다.

>>> numpy.stack(2*i for i in range(10))
array([ 0,  2,  4,  6,  8, 10, 12, 14, 16, 18])

참고 numpy.stack내부적으로 발전기를 소비하고와 중간 목록을 작성한다 arrays = [asanyarray(arr) for arr in arrays]. 구현은 여기 에서 찾을 수 있습니다 .


1
지적 해 주셔서 감사합니다. 그러나 (내 응용 프로그램에서)를 사용하는 것보다 약간 느린 것 같습니다 np.array(tuple(mygen)). 다음은 테스트 결과는 다음과 같습니다 %timeit np.stack(permutations(range(10), 7)) 1 loop, best of 3: 1.9 s per loop에 비해%timeit np.array(tuple(permutations(range(10), 7))) 1 loop, best of 3: 427 ms per loop

13
이것은 훌륭해 보이고 나를 위해 작동합니다. 그러나 Numpy 1.16.1에서는 다음과 같은 경고 메시지가 나타납니다.FutureWarning: arrays to stack must be passed as a "sequence" type such as list or tuple. Support for non-sequence iterables such as generators is deprecated as of NumPy 1.16 and will raise an error in the future.
Joseph Sheedy

6

다소 접선이지만 생성기가 목록 이해력 인 경우 numpy.where결과를보다 효과적으로 얻는 데 사용할 수 있습니다 (이 게시물을 본 후 내 코드에서 이것을 발견했습니다)


0

vstack , hstackdstack의 기능은 다차원 어레이를 생성 입력 발전기로서 취할 수있다.


3
링크가 변경되거나 다른 경우를 예로 들어 줄 수 있습니까? :)
Ari Cooper-Davis

이러한 함수는 값 생성기가 아닌 배열 생성기를 사용할 수 있습니다.
retnikt
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.