2017-01-04 2 views
4

:왜 dtype = object를 갖는 numpy 배열이 dtype = int보다 훨씬 작은 파일 크기가됩니까? 여기에 예를 들어

import numpy as np 
randoms = np.random.randint(0, 20, 10000000) 

a = randoms.astype(np.int) 
b = randoms.astype(np.object) 

np.save('d:/dtype=int.npy', a)  #39 mb 
np.save('d:/dtype=object.npy', b) #19 mb! 

당신은 DTYPE = 객체 파일이 절반 정도 크기입니다 것을 볼 수 있습니다. 어째서? 나는 제대로 정의 된 numpy dtypes가 객체 dtypes보다 엄격하게 낫다는 인상을 받았다.

+1

어떤 버전의 Python과 NumPy를 사용하고 있습니까? – user2357112

+0

어떤 CPU 아키텍처가 있습니까? 그리고 정확히'a'의'dtype'은 무엇입니까? 'np.int64'? 또는'np.int32? ' –

+0

어쨌든, 개체 dtypes는 엄격하게 * 더 느릴 것입니다 * 그러나 작은 파일 크기를 얻는 이유에 대한 몇 가지 가능성이 있습니다. –

답변

6

비 개체 dtype에서 npy 파일 형식의 대부분은 배열 데이터의 원시 바이트 덤프로 구성됩니다. NumPy가 4 또는 8 바이트 정수로 기본 설정되어 있는지 여부에 따라 요소 당 4 또는 8 바이트가됩니다. 파일 크기에서 요소 당 4 바이트로 보입니다.

개체 dtype의 경우 대부분의 npy 파일 형식은 배열의 일반적인 피클로 구성됩니다. 이러한 배열에있는 것과 같은 작은 정수의 경우, 피클은 pickletools 모듈에, 긴 이름 BININT1, "문서화"는 K 피클 연산 코드를 사용

I(name='BININT1', 
    code='K', 
    arg=uint1, 
    stack_before=[], 
    stack_after=[pyint], 
    proto=1, 
    doc="""Push a one-byte unsigned integer. 

    This is a space optimization for pickling very small non-negative ints, 
    in range(256). 
    """), 

이것은 K 오피 코드에 대한 두 개의 정수 당 바이트, 하나가 필요합니다 및 부호없는 정수 데이터의 1 바이트.

dtype이 numpy.int8 또는 numpy.uint8 인 배열을 정수 당 약 1 바이트로 저장하면 파일 크기를 더욱 줄일 수 있습니다.

+0

흥미 롭습니다. 이 추가 분석을 해주셔서 감사합니다. 로버츠의 대답과 잘 어울립니다. – Muppet

2

편집 :이 분석은 잘못되었습니다. 올바른 정보는 user2357112의 답변을 참조하십시오.

dtype=object 배열은 NPY 파일 내에 파이썬 피클로 저장됩니다. 파이썬 피클은 객체 그래프 내부의 객체에 대한 신원을 보존합니다. 즉 b[i] is b[j] 인 경우 피클은 b[i]b[j]으로 표시된 객체를 단지 처음으로 직렬화하고 다음에 나타날 때이를 참조합니다. 직렬화 될 때 객체 자체가 꽤 작을 때조차도이 참조는 종종 직렬화 된 객체 자체보다 작습니다.

파이썬은 작은 정수를 최적화하여 같은 객체를 항상 -5에서 256까지의 정수로 재사용하므로 배열의 유일한 값인 range(0, 20)을 모두 포함합니다. numpy는 .astype(object)을 통해 변환 할 때 인스턴스를 다시 사용하기로 결정할 수도 있습니다.

부동 소수점 uniform(0.0, 1.0, 10000000)과 같이 대부분 또는 모든 값이 고유 한 배열을 만든 경우 원하는 상대 크기를 얻을 수 있습니다.

+0

훌륭한 답변 - 많은 의미가 있습니다. 감사! – Muppet

+0

나를 괴롭히기 - 방금 커버 아래를 보았습니다. https://github.com/numpy/numpy/blob/master/numpy/lib/format.py # L567 –

+0

나는 이것이 대답 일 것으로 기대했지만, 내 자신의 테스트에서 피클은 메모 연산자를 사용하지 않는 것 같았습니다. 그렇지 않은 경우 결과는 여전히 정수 당 8-10 바이트 정도였습니다. – user2357112

관련 문제