5.4.1 · Coding › Scientific Computing (Python)
Intuition Ek-sentence wali idea
Ek NumPy ndarray basically memory mein bytes ka ek flat block hota hai, saath mein kuch chote bookkeeping numbers (dtype , shape , strides ) jo NumPy ko batate hain ki un bytes ko ek multi-dimensional grid ki tarah kaise interpret aur walk through karna hai.
YE DESIGN KYU? Kyunki ek 2-D table ko real 2-D structure (list of lists / pointers) mein store karna slow aur memory-scattered hota hai. Iske bajaye NumPy sab kuch EK cache-friendly block mein rakhta hai aur dimensions ko fake karne ke liye math (strides) use karta hai. Yahi NumPy ko fast banata hai.
dtype (data type) ek element ki binary layout fix karta hai: uski kind (int/float/bool/complex…) aur bytes mein uska size (itemsize).
Ek ndarray mein har element ka same dtype hota hai — isliye arrays homogeneous hote hain (Python lists ke unlike). Homogeneity exactly yahi allow karti hai ki NumPy har baar ek fixed number of bytes step kar sake.
Worked example dtype inspect karna
a = np.array([ 1 , 2 , 3 ])
a.dtype # dtype('int64') (platform default int)
a.itemsize # 8 bytes per element
a.nbytes # 24 = 3 * 8
Ye step kyun? itemsize × number_of_elements = nbytes. Agar tum yeh samajh gaye toh NumPy mein memory ka 80% samajh gaye.
shape ek tuple (d0, d1, …, d_{n-1}) hai. d_k axis k ke along kitni entries hain. Elements ki total sankhya ka product hai ∏ k d k .
b = np.arange( 12 ).reshape( 3 , 4 )
b.shape # (3, 4)
b.ndim # 2
b.size # 12 = 3*4
Ye step kyun? arange(12) ne flat buffer mein 12 elements banaye; reshape ne sirf metadata change kiya , bytes nahi. Data hila nahi.
Intuition strides kyun hote hain
Element A[i, j] dhundhne ke liye NumPy ko flat buffer mein byte offset chahiye. Strides index space se byte space mein conversion factors hain.
Ek 2-D array ko row by row lay out karo (C/"row-major" order). Shape (R, C) aur itemsize = s bytes ke liye, A[i, j] ki flat position (elements count karke) hai:
flat_index ( i , j ) = i ⋅ C + j
Kyun? Row i tak skip karne ke liye i poori rows cross karni padti hain, har ek length C ki; phir row ke andar j move karo.
s se multiply karke bytes mein convert karo:
byte_offset ( i , j ) = ( i ⋅ C + j ) ⋅ s = i ( C ⋅ s ) + j ( s )
Isse general stride formula se match karo:
byte_offset = k ∑ i k ⋅ stride k
Comparison se, strides hain:
stride 0 = C ⋅ s , stride 1 = s
Worked example (3,4) int64 array ke strides
b = np.arange( 12 ).reshape( 3 , 4 ) # int64, s = 8
b.strides # (32, 8)
Check: stride_1 = s = 8 ✓. stride_0 = C*s = 4*8 = 32 ✓.
Ye step kyun? Ek row neeche jaana (i→i+1) 4 elements ki poori row skip karta hai = 4×8 = 32 bytes.
Intuition Slicing aur transpose FREE hain
Kaafi operations ek view create karte hain: ek naya ndarray object jo same buffer point karta hai alag metadata ke saath. Koi bytes copy nahi → O(1).
Worked example Transpose sirf strides swap karta hai
b = np.arange( 12 ).reshape( 3 , 4 ) # shape (3,4) strides (32,8)
bt = b.T # shape (4,3) strides (8,32)
bt.base is b.base # True -> shares memory
Kyun? Transpose same bytes ko reinterpret karta hai by swapping kaunsa axis kaunsa stride rakhta hai. .T ke baad array F-contiguous (column-major) ho jaata hai lekin koi data nahi hila.
A[2,1] ka location dhundho
A = np.arange( 12 , dtype = np.int64).reshape( 3 , 4 )
# strides = (32, 8)
Step 1 — byte offset: 2 ⋅ 32 + 1 ⋅ 8 = 72 bytes.
Kyun? ∑ i k stride k apply karo.
Step 2 — element index: 72/8 = 9 , toh value hai 9. Check: A[2,1] == 9 ✓.
Kyun? Flat index = 2 ⋅ 4 + 1 = 9 , consistent hai.
Common mistake "reshape data copy karta hai"
Kyun sahi lagta hai: shape bilkul alag dikhti hai, toh memory zaroor rearrange hogi. Haqeeqat: reshape sirf metadata edit karta hai jab layout compatible ho — yeh ek view return karta hai. Fix: yaad rakho data buffer sacred hai; metadata sasta hai . (Copy tabhi hoti hai jab requested layout impossible ho, jaise ek non-contiguous transposed array ko reshape karna.)
Common mistake "Ek 2-D slice ek alag array hai jise main safely mutate kar sakta hoon"
Kyun sahi lagta hai: Python mein, list slices copy karte hain. Haqeeqat: sub = A[1:3, :] ek view hai; sub[0,0]=99 likhne se A change ho jaata hai. Fix: jab independence chahiye toh A[1:3,:].copy() use karo. np.shares_memory(sub, A) se check karo.
Common mistake "Bada dtype hamesha slow hota hai / kabhi matter nahi karta"
Kyun sahi lagta hai: correctness aur speed mein confusion. Haqeeqat: dtype overflow aur precision bhi control karta hai. np.int8 127 par wrap karta hai; np.float32 precision khota hai. Fix: dtype range + memory ke liye choose karo, phir speed socho.
Common mistake "strides elements mein hain"
Kyun sahi lagta hai: shape elements mein hai, toh strides bhi waisa lagta hai. Haqeeqat: strides bytes mein hain. Element step paane ke liye hamesha itemsize se divide karo. Fix: yaad rakho formula s se multiply karta hai.
Recall Feynman: 12-saal ke bachche ko samjhao
Socho ek lambi single shelf par numbered books hain — yahi memory hai. Tum pretend karte ho ki yeh rows aur columns wala bookcase hai. "Row 2, column 1" dhundhne ke liye tum actually bookcase mein nahi chalte; tum quick maths karte ho: "2 rows ki books skip karo, phir 1 aur." Har direction ke liye "skip-amount" stride hai. Shape batata hai ki tum kitni rows/columns hone ka pretend kar rahe ho, aur dtype batata hai ki har book kitni moti hai. Bookcase ko sideways palatna (transpose) ek bhi book move nahi karta — tum sirf swap karte ho ki kaun sa skip-number "row" matlab rakhta hai aur kaun sa "column."
D ata S ize, S hape, S tep"
dtype = har cell kitna bada, Shape = har axis par kitne cells, Strides = step karne ke liye kitne bytes. Memory par chalo: offset = Σ index × step .
Ek ndarray ke flat buffer ko interpret karne wale teen metadata pieces kaunse hain? dtype (element type/size), shape (har axis par size), strides (har axis par step karne ke bytes).
strides ki units kya hain?Bytes (elements nahi).
i_k indices wale element ka byte offset formula kya hai? offset = Σ_k i_k · stride_k.
Ek C-contiguous (3,4) int64 array ke strides kya hain? (32, 8): last axis 8 = itemsize, first axis 4×8 = 32.
Kya reshape zyaadatar data copy karta hai? Nahi — yeh ek view return karta hai, sirf metadata change karta hai (jab tak layout incompatible na ho).
.T (transpose) memory ke saath kya karta hai?Buffer ke saath kuch nahi; yeh strides (aur shape) swap karta hai. Ek C-array F-contiguous ban jaata hai.
NumPy arrays homogeneous (sabka ek dtype) kyun hote hain? Taaki har element ek fixed byte size ka ho, strides ko constant amount step karne deta hai → fast indexing.
Slice se real independent array kaise milti hai? .copy() use karo; sharing .np.shares_memory se check karo.
Axis k ke liye C-contiguous stride formula kya hai? stride_k = itemsize · k ke baad wale axes ke shape sizes ka product.
.size aur .nbytes mein kya difference hai?size = elements ki sankhya (shape ka product); nbytes = size × itemsize.
NumPy — broadcasting (axes ko "stretch" karne ke liye 0-stride tricks use karta hai)
NumPy — views vs copies & np.shares_memory
NumPy — vectorization & performance
CPU cache & memory locality
Row-major vs column-major (C vs Fortran order)
Python lists vs arrays
fixes itemsize + enforces
sizes axes, product = size
reshape changes metadata only