Programming/Python

[Python] 큰 데이터 사이즈 읽는 방법(Iterator, Generator)

쌍쌍바나나 2019. 1. 16. 10:48
반응형

파이썬에서 데이터를 읽을때, 보통은 모든 데이터를 메모리에 올리고 사용하는 경우가 많다.
하지만, 작은 사이즈의 데이터는 가능하지만 큰 사이즈의 데이터를 메모리에 올리고 사용하는게 가능하다면?
피시에 감사하자. 큰 데이터셋을 사용하는 경우인 데이터 학습 시킬 학습 데이터, 통계를 낼때 데이터 등등..
이때는 데이터를 built-in 함수인 iterator, generator를 이용을 해야만 한다. MUST!!

Iterator, Generator

자 interation을 어떻게 쓰는게 좋은가?

python for x in range(10): print x

range(10)은 리스트를 생성하는것과 동일하다. [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] list를 iteration object로 생성이 가능한데,

iteration = iter(range(10))

만약 위의 값을 for문으로 돌리면 아래와 같이 사용이 가능하다.

으로 FIFO으로 출력이 가능하다.

여기서 중요한게 있는데, 파일입출력을 예로 들어보겠다. 만약에 파일입출력을 해서 간단한 for-loop을 돌리는 프로그램을 작성한다고 가정할때, 위의 range를 통해서는 모든 파일의 내용을 메모리에 올려야하기 때문에 OOM이 날 가능성이 높다.

보통 large dataset을 사용하는 Tensorflow나 Keras와 같은 플랫폼에서도 데이터를 iteration을 통해 읽는 경우가 많다. (학습하는 데이터의 양이 매우 많은 경우)

그렇다면 range를 사용하지 않고, 어떻게 모든 파일을 처리할수 있을까? 그 답은 generator를 사용하면 된다.

위에서 사용한것처럼 g의 object를 사용하면 되는데, next(g)를 통해서 큐형식으로 데이터를 뺄수도 있다.

위에서 사용한 yield는 데이터를 주고, 받는 역할을 한다고 생각하면 된다. 하나의 통로가 있고 그 통로에 데이터를 밀어넣어주고 받아주는 역할 위에서 for문 내부에 있는 yield를 통해서 i+3의 값을 어딘가 버퍼에 넣어주고, generator를 통해서 하나씩 값을 던져준다.

위 예제에서 만약 for-loopwhile-loop으로 교체하면 어떻게 될까? 위에서 언급하듯이 yield는 값을 가져다 주기도 하지만, 넣기도 가능하다. 하지만 사용시에 주의해야할 점이 있는데 일단 아래와 같이 작성하면 결과는 잘 나온다.

위에서 만약 next(g)를 사용하지 않고 g.send(2)를 바로 사용하면 어떻게 될까? TypeError: can't send non-None value to a just-started generator 이런 에러가 난다. 그 이유는 yield에 이미 1이라는 값이 들어있고, 그 값을 내보내기 위해서 대기하고 있습니다. 근데 그 상태에서 g.send(2)를 해버리면, 이미 yield의 1이 들어있기 때문에 에러가 난다. 그렇기 때문에 next(g)를 한번 수행하고, 그 이후에 While-loop을 사용하기 때문에 g.send(2)를 무수히 수행이 가능!

파일 읽기

보통 작은 파일은 아래와 같이 데이터를 읽을 수 있다. 간단하게 읽기가 가능한데, 극단적으로 나의 메모리 사이즈가 4GB라고 할때, 1GB의 데이터를 읽을때 아마도 OOM이 날것이다.

```python f_in = file('text.txt', 'r')

for line in f_in.readlines(): print line[:-1] # 강제개행이 들어가니까... ```

위 문제를 해결하기 위해서는 generator를 이용해서 파일을 읽으면 OOM없이 파일을 쉽게 읽을 수 가 있다. large dataset을 읽을때도 거의 모든 방법이 아래와 같다. 전체의 데이터를 메모리에 올리지 않고, 한줄 씩 읽는 방법이니, 큰 데이터는 아래와 같이 사용하자.

반응형