2015-01-05 16 views
7

varsayalım Ben girin:Python: türleri ve dtypes arasındaki karışıklık

a = uint8(200) 
a*2 

Sonra sonuç 400 olduğunu ve tipi UInt16 olması yeniden biçimlendirilmiştir. Ancak

:

a = array([200],dtype=uint8) 
a*2 

ve sonuç çarpım sonucu bir bayt kalmasını sağlamak için, modül 256 yapılmıştır

array([144], dtype=uint8) 

olup.

"Types" ve "dtypes" hakkında kafam karıştı ve birinin diğerine göre kullanıldığı yer. Gördüğünüz gibi, tür çıktıda önemli bir fark yaratabilir.

Örneğin, bu sayıdaki işlemlerin modulo 256 gerçekleştirilebilmesi için tek bir dtype uint8 sayısı oluşturabilir miyim? Alternatif olarak, bir işlem türü (dtype değil) uint8 oluşturabilirim, böylece üzerindeki işlemler 0-255 aralığı dışında değerler üretecek mi?

cevap

2

Sayısal bir dizi, aynı türde öğeler içerir, bu nedenle np.array([200],dtype=uint8) türünde uint8 türünde bir dizidir. np.uint8(200) yaptığınızda, bir diziniz yoktur, yalnızca tek bir değer. Bu büyük bir fark yaratıyor.

Dizide bir miktar işlem gerçekleştirilirken, tek bir değer taşması değerine bakılmaksızın, tür aynı kalır. Tüm dizinin büyüklüğünün değişmesi gerektiğinden, dizilerdeki otomatik upcasting yasaklanmıştır. Bu sadece kullanıcı açıkça bunu isterse yapılır. Bir işlemi tek bir değerde gerçekleştirirken, diğer değerleri etkilemeden kolayca yükselebilir. Bir NumPy dizisinin type numarası numpy.ndarray;

8

; Bu sadece Python nesnesinin türüdür (örneğin, type("hello")'un str olduğu gibi).

dtype bellekteki bayt bir sayısal (yani tek bir numara) veya bir dizi ve bayt tedavi edilecek bir yolla (örneğin, int/float) tarafından yorumlanır tanımlar. Bu nedenle, bir dizinin veya skalerin type'unu değiştirmezsiniz, sadece dtype.

gözlemlemek gibi, iki skalarlar çarpmak ederseniz elde edilen veri türü iki değer dökülebilir için en küçük "güvenli" bir türüdür. Bununla birlikte, bir dizi ve bir skaler ile çarpmak basit bir şekilde aynı veri tipinin bir dizisini döndürür. fonksiyonu için documentation belirli sayıl veya dizi nesne en dtype değiştirildiğinde açıkça gösterir: numpy içinde

Tip promosyon bazı küçük farklarla, C++ gibi dillerde kurallara benzer şekilde çalışır. Skaler ve diziler her ikisi de kullanıldığında dizinin türü önceliklidir ve skaler gerçek değeri dikkate alınır.

belgeleri devam eder:

sadece skalerler veya skalerler maksimum kategorisi dönüş değerinin üretilmesi için, veri tipleri promote_types ile birleştirilir dizilerin en kategori daha yüksektir varsa . dizinin veri türü sayısal alan int önceliklidir ve bir np.uint8 veri türü döndürülür

>>> np.promote_types(np.uint8, int) 
dtype('int32') 

np.array([200], dtype=np.uint8) * 2 için:

Yani np.uint8(200) * 2, iki skalerler için, ortaya çıkan veri türü np.promote_types tarafından döndürülen tip olacaktır. ,

>>> np.array([200], dtype=np.uint8) * np.uint8(2) 
144 

alternatif:

Eğer numpy otomatik dtype tanıtımını engellemek için kullanan diğer skalerler ait veri türlerini kısıtlamak gerekir, operasyonlar sırasında bir skaler dtype istinat ilgili son soruya cevap için Tabii ki, tek bir değeri bir NumPy dizisinde basitçe sarmak (ve sonra NumPy onu farklı dtype skalerleriyle işlemlere dönüştürmez).

bir operasyon sırasında bir dizinin türünü desteklemek için, öncelikle Herhangi bir dizide skalarlar sarabilirdiniz:

>>> np.array([200], dtype=np.uint8) * np.array([2]) 
array([400]) 
+0

"' dtype' yalnızca bellekte baytların bir skaler tarafından nasıl yorumlanacağını tanımlar »→ ayrıca yorumlandıkları yolu tanımlar (örn." Int32' vs float32 "). – Veedrac

+0

Teşekkürler, Veedrac, bu cümleyi biraz daha hassaslaştırdım. –

2

basit, üst düzey yanıt olduğunu NumPy katmanları Python'un tip tepesinde bir ikinci tip sistemi sistemi. Bir NumPy nesnesinin type için sorduğunuzda

, sen numpy.ndarray gibi --something konteynerin türünü olsun. Ancak, dtype için sorulduğunda, öğelerinin öğelerinin (numpy tarafından yönetilen) türünü alırsınız. Bazen

>>> from numpy import * 
>>> arr = array([1.0, 4.0, 3.14]) 
>>> type(arr) 
<type 'numpy.ndarray'> 
>>> arr.dtype 
dtype('float64') 

, varsayılan float türü kullanırken olduğu gibi, öğe veri tipi ( dtype) bir Python tipine denktir. Ama bu aynı değil, eşdeğer:

>>> arr.dtype == float 
True 
>>> arr.dtype is float 
False 

Diğer durumlarda, eşdeğer Python türü yoktur. Örneğin, uint8'u belirttiğinizde. Bu veri değerleri/türleri Python tarafından yönetilebilir, ancak C, Rust ve diğer "sistem dilleri" nden farklı olarak, doğrudan makine veri tiplerine (uint8 "işaretsiz baytlarla hesaplamalar" gibi) hizalanan değerleri yönetmek yaygın değildir. Python için kullanım çantası.

Büyük öykü, NumPy'nin kendi tür sistemi altında çalışan diziler ve matrisler gibi kaplar sağlamasıdır. Ve bu kaplarda (ve onların elemanlarında) çalışmak için oldukça faydalı, iyi optimize edilmiş rutinler bir demet sağlar. Bakım kullanıyorsanız, NumPy ve normal Python hesaplamalarını karıştırabilir ve eşleştirebilirsiniz.

Python türü yok uint8.döndürür bir NumPy tipi denilen uint8 adında bir yapıcı işlevi vardır: "Ben (d_type değil) türü bir dizi oluşturabilir uint8 ..."

>>> u = uint8(44) 
>>> u 
44 
>>> u.dtype 
dtype('uint8') 
>>> type(u) 
<type 'numpy.uint8'> 

Yani Hayır. Yapamazsın. Böyle bir hayvan yok. Hesaplamaları uint8 kurallarıyla kısıtlı hesaplamalar yapmadan NumPy arrays (a.k.a. NumPy skaler değerleri) kullanamazsınız. Ör:

>>> uint8(44 + 1000) 
20 
>>> uint8(44) + uint8(1000) 
20 

değerleri mod 256 hesaplamak istiyorsanız Ancak, Python'un mod operatörü kullanmak muhtemelen daha kolay:

>> (44 + 1000) % 256 
20 

verileri Sürüş içine daha büyük 255 değerleri uint8 veri türleri ve daha sonra aritmetik yapmak, mod-256 aritmetik elde etmek için oldukça arka kapıdır. Dikkatli değilseniz, Python'un değerlerinizi tam tamsayıya (mod-256 düzenini öldürerek) "yükseltmesine" veya taşma istisnalarını tetiklemesine neden olacaksınız (çünkü C ve makine dilinde harika çalışan püf noktaları genellikle daha yüksek seviyeli diller).