1.4.6 · AI-ML › Python & Scientific Computing
Intuition Pandas Actually Kya Kar Raha Hai?
DataFrame ko ek aisa Excel spreadsheet samjho jise tum code se control kar sako. Har column ek Series hai (bilkul Excel ke single column jaisi). Lekin Excel ke unlike, Pandas tumhe programmatic superpowers deta hai: ek millisecond mein million rows filter karo, data ko bina copy-paste ke reshape karo, aur operations ko chain karo. Series ek 1D labeled array hai (sochho: ek column with a name). DataFrame ek 2D table hai jahan har column ek Series hai. Jadu kya hai? Labels tumhare data ke saath chipke rehte hain – sort ya filter karne par ab koi "off-by-one" error nahi.
Ek Series fundamentally ek ordered, labeled, homogeneous array hai. Chalte hain concept build karte hain:
Ek simple array se shuru karo : [10, 20, 30, 40]
Labels (index) add karo : Ab har value ka ek naam hai: {'a': 10, 'b': 20, 'c': 30, 'd': 40}
Order maintain karo : Ek dict ke unlike, Series insertion order maintain karta hai aur integer positional access support karta hai
Type consistency add karo : Saare elements same dtype share karte hain (int64, float64, object, etc.)
import pandas as pd
import numpy as np
# From list - automatic integer index
s1 = pd.Series([ 10 , 20 , 30 , 40 ])
# Index: 0, 1, 2, 3
# From list with custom index
s2 = pd.Series([ 10 , 20 , 30 , 40 ], index = [ 'a' , 'b' , 'c' , 'd' ], name = 'scores' )
# Index: 'a', 'b', 'c', 'd'
# From dictionary - keys become index
s3 = pd.Series({ 'Alice' : 85 , 'Bob' : 92 , 'Charlie' : 78 })
Ek DataFrame aligned indices ke saath Series ka ek dictionary hai. Chalte hain ise derive karte hain:
Multiple Series se shuru karo :
name_series = Series(['Alice', 'Bob', 'Charlie'])
score_series = Series([85, 92, 78])
Unhe ek common index pe align karo : Row 0, Row 1, Row 2
Har Series ek column ban jaata hai : Column 'name', Column 'score'
Result : Ek 2D table jahan har column same row index share karta hai
Ek two-dimensional labeled data structure jisme potentially different types ke columns hote hain. Inse milkar banta hai:
index : row labels (saare columns mein shared)
columns : column labels (Series ke naam)
values : 2D numpy array (actual data)
Har column ek Series hai jiska same index hai
Yeh structure kyun : SQL-jaisi operations (filtering, grouping, joining) allow karta hai, saath hi labeled access pattern maintain karta hai. Shared index ka matlab hai ki operations automatically data ko sahi se align karti hain.
Worked example Example 1: Scratch Se Series Banana
Problem : Tumhare paas monthly sales data hai aur tum use month name se track karna chahte ho.
# Bad approach: just list
sales = [ 15000 , 18000 , 22000 , 19000 ]
# Problem: sales[1] kaun sa month hai? Tumhe yaad rakhna padta hai!
# Good approach: Series with labels
sales = pd.Series(
[ 15000 , 18000 , 22000 , 19000 ],
index = [ 'Jan' , 'Feb' , 'Mar' , 'Apr' ],
name = 'monthly_sales'
)
# Yeh step kyun? Labels code ko self-documenting banate hain
print (sales[ 'Feb' ]) # 18000 - clear intent!
print (sales.name) # 'monthly_sales'
Yeh step by step kyun :
List → Series : Labels aur dtype tracking add karta hai
Custom index : Access ko semantic banata hai (sales['Feb'] vs sales[1])
Name parameter : Document karta hai ki yeh Series kya represent karta hai (DataFrame columns ke liye crucial)
Worked example Example 2: Dictionary Se DataFrame
Problem : Tumhare paas student records hain aur tum unhe saath analyze karna chahte ho.
# Dictionary of lists (most common pattern)
data = {
'name' : [ 'Alice' , 'Bob' , 'Charlie' , 'Diana' ],
'score' : [ 85 , 92 , 78 , 95 ],
'grade' : [ 'B' , 'A' , 'C' , 'A' ]
}
df = pd.DataFrame(data)
# Yeh kyun kaam karta hai - internal process:
# 1. Har list ek Series ban jaati hai: name → Series([Alice, Bob, Charlie, Diana])
# 2. Automatic integer index: 0, 1, 2, 3 (kyunki koi index specify nahi kiya)
# 3. Keys column names ban jaati hain
# 4. Saari Series shared index se align hoti hain
print (df.shape) # (4, 3) - 4 rows, 3 columns
print (df.index) # RangeIndex(start=0, stop=4, step=1)
print (df.columns) # Index(['name', 'score', 'grade'])
Dict-of-lists kyun? "Column-oriented" thinking se sabse natural mapping. Har key ek feature/variable hai.
Worked example Example 3: List of Dicts Se DataFrame
Problem : Data JSON/API se list of records ke roop mein aata hai.
# List of dictionaries (row-oriented)
records = [
{ 'name' : 'Alice' , 'score' : 85 , 'grade' : 'B' },
{ 'name' : 'Bob' , 'score' : 92 , 'grade' : 'A' },
{ 'name' : 'Charlie' , 'score' : 78 , 'grade' : 'C' }
]
df = pd.DataFrame(records)
# Yeh kyun kaam karta hai:
# 1. Har dict ek row hai
# 2. Saare dicts ke keys columns ban jaate hain (saari keys ka union)
# 3. Missing keys ko NaN milta hai
# 4. Automatic integer index
# Agar keys match nahi karein to?
mixed = [
{ 'name' : 'Alice' , 'score' : 85 },
{ 'name' : 'Bob' , 'grade' : 'A' } # missing 'score'
]
df_mixed = pd.DataFrame(mixed)
# Result: df_mixed.loc[1, 'score'] = NaN (missing data gracefully handle hoti hai)
List-of-dicts kyun? APIs/JSON ke liye natural. Har record complete hota hai.
Worked example Example 4: Access Patterns Compare Karna
df = pd.DataFrame({
'name' : [ 'Alice' , 'Bob' , 'Charlie' ],
'score' : [ 85 , 92 , 78 ],
'grade' : [ 'B' , 'A' , 'C' ]
}, index = [ 's1' , 's2' , 's3' ]) # Custom index
# Pattern 1: Column access
scores = df[ 'score' ] # Series with index ['s1', 's2', 's3']
# Kyun: Sabse common - analysis ke liye poora column lo
# Pattern 2: Label-based
bob_score = df.loc[ 's2' , 'score' ] # 92
# Yeh step kyun? Hum jaante hain Bob ka label 's2' hai
# Slices use kar sakte hain: df.loc['s1':'s2', ['name', 'score']]
# Pattern 3: Position-based
second_studentscore = df.iloc[ 1 , 1 ] # 92 (2nd row, 2nd col)
# Yeh step kyun? Position-based iteration ya slicing
# Slices use kar sakte hain: df.iloc[0:2, 0:2]
# df['s2'] kyun nahi? Woh 's2' naam ka column dhundega!
# df[1] kyun nahi? Woh 1 naam ka column dhundega!
Worked example Example 5: Students Filter Karna
df = pd.DataFrame({
'name' : [ 'Alice' , 'Bob' , 'Charlie' , 'Diana' ],
'score' : [ 85 , 92 , 78 , 95 ],
'grade' : [ 'B' , 'A' , 'C' , 'A' ]
})
# Step 1: Boolean mask banao
high_scorers = df[ 'score' ] > 85
# Result: Series([False, True, False, True])
# Kyun? Element-wise comparison
# Step 2: Mask apply karo
df_high = df[high_scorers]
# Result: Sirf Bob aur Diana ke saath DataFrame
# Yeh step kyun? Jahan mask True hai woh rows rakhta hai
# Compact form (sabse common)
df_high = df[df[ 'score' ] > 85 ]
# Multiple conditions (& aur | use karo, 'and'/'or' nahi)
df_filtered = df[(df[ 'score' ] > 80 ) & (df[ 'grade' ] == 'A' )]
# Parentheses kyun? Operator precedence - & tighter bind karta hai > se
Worked example Example 6: Column Operations
df = pd.DataFrame({
'name' : [ 'Alice' , 'Bob' , 'Charlie' ],
'score' : [ 85 , 92 , 78 ]
})
# Naya column add karo (broadcasting)
df[ 'passed' ] = df[ 'score' ] >= 80
# Yeh kyun kaam karta hai: Boolean Series banata hai, index se aligned
# Result: Series([True, True, False]) naya column ban jaata hai
# Computed column add karo
df[ 'score_normalized' ] = df[ 'score' ] / 100
# Yeh step kyun? Element-wise division, index maintain karta hai
# Existing column modify karo
df[ 'score' ] = df[ 'score' ] + 5 # Curve grades
# Kyun allowed hai? Same-index assignment, Series replace karta hai
# Function se column add karo
df[ 'grade' ] = df[ 'score' ].apply( lambda x: 'A' if x >= 90 else 'B' if x >= 80 else 'C' )
# Apply kyun? Har element pe function apply karta hai, naya Series return karta hai
Common mistake Mistake 1:
.loc aur .iloc Ko Confuse Karna
Galat intuition : "Mere paas index [0, 1, 2] hai, to df.loc[1] aur df.iloc[1] same hain."
Sahi kyun lagta hai : Integer indices positions jaisi dikhti hain!
Sach yeh hai :
df = pd.DataFrame({ 'A' : [ 10 , 20 , 30 ]}, index = [ 2 , 4 , 6 ])
df.loc[ 2 ] # Label 2 wali row → Series([10])
df.iloc[ 2 ] # Position 2 wali row → Series([30])
# Dono alag hain!
Fix : .loc hamesha label-based hai. .iloc hamesha position-based hai. Agar tumhara index integer hai, to confusion se bachne ke liye positions ke liye .iloc use karo.
Steel-man : Confusion isliye exist karta hai kyunki default integer indices .loc aur .iloc ko coincidentally equal banate hain. Jaise hi custom index aata hai, woh alag ho jaate hain.
Common mistake Mistake 2: Boolean Indexing Mein
and/or Use Karna
Galat code : df[(df['score'] > 80) and (df['grade'] == 'A')]
Sahi kyun lagta hai : Natural language mein "and" use hota hai!
Kyun fail hota hai : and single boolean values expect karta hai. df['score'] > 80 booleans ki ek Series hai, ek boolean nahi. Python bool(Series) try karta hai, jo ValueError: The truth value of a Series is ambiguous raise karta hai.
Fix : Series pe bitwise operators use karo:
& element-wise AND ke liye
| element-wise OR ke liye
~ element-wise NOT ke liye
# Sahi
df[(df[ 'score' ] > 80 ) & (df[ 'grade' ] == 'A' )]
# Operator precedence ki wajah se parentheses bhi chahiye
# Bina parentheses ke: df['score'] > (80 & df['grade']) - galat!
Steel-man : Python ka and/or scalar logic ke liye design kiya gaya hai. Pandas &/| ko arrays pe element-wise operations ke liye overload karta hai, numpy conventions follow karte hue.
Common mistake Mistake 3: Chained Assignment (SettingWithCopyWarning)
Galat code : df['score'] > 80]['grade'] = 'A'
Sahi kyun lagta hai : "Pehle filter karo, phir modify karo."
Kyun fail ho sakta hai : df['score'] > 80] ek copy ya view return kar sakta hai (Pandas decide karta hai). Agar copy hai, to tum copy modify karte ho, original df nahi.
Fix : Chained access ke liye .loc use karo:
# Sahi
df.loc[df[ 'score' ] > 80 , 'grade' ] = 'A'
# Kyun: Single .loc call original df ka modification guarantee karta hai
Steel-man : Pandas iske baare mein isliye warn karta hai kyunki behavior ambiguous hai. Assignment ke liye hamesha .loc[row_indexer, col_indexer] = value use karo.
Recall DataFrames ko 12-Saal ke Bachche Ko Explain Karo
Socho tumhare paas ek notebook hai jisme tum apne saare doston ke video game high scores track karte ho. Har page mein columns hain: "Dost ka Naam", "Game", "Score", "Date". Basically yahi ek DataFrame hai!
Series sirf us notebook ka EK column hai. Jaise agar tumne sirf "Score" column nikal liya – yeh numbers ki ek list hai, lekin har number ko abhi bhi pata hai woh kis dost ka hai (yahi index/label hai).
DataFrame poora notebook page hai with ALL columns saath mein. Cool part kya hai? Labels (dost ke naam) har row ke saath chipke rehte hain, isliye agar tum score se sort bhi karo, to tumhe kabhi nahi bhoolega ki kiska score kaun sa hai. Jaise magic sticky notes jo kabhi girti nahi!
Sirf notebook mein likhne ki jagah Pandas kyun use karein? Kyunki tum use pooch sakte ho "Mujhe woh saare dikhao jinhoone 1000 se zyada score kiya" ya "Average score kya hai?" aur woh ek millisecond mein jawab deta hai. Ek kaagaz ki notebook mein 10,000 doston ke saath try karke dekho!
L OC = L abels (semantic names)
I LOC = I ntegers (positions, jaisa array indices)
Sochho: "L abels for L ogic, I ntegers for I teration"
1.4.01-NumPy-arrays-and-vectorization - DataFrames NumPy arrays pe built hain; vectorization samajhna Pandas operations explain karne mein help karta hai
1.4.02-Python-data-structures - Series ek enhanced dict jaisi hai; DataFrame list aur dict concepts ko combine karta hai
1.4.07-Pandas-data-cleaningand-manipulation - Agla step: real analysis ke liye in structures ka use karna
1.5.01-Data-visualizationmatplotlib-basics - DataFrames plotting ke liye matplotlib ke saath seamlessly integrate hote hain
2.1.03-Feature-engineering-basics - DataFrames ML feature preparation ke liye primary structure hain
#flashcards/ai-ml
Pandas Series ke do core components kya hain? :: Values (numpy array) aur Index (labels). Index har value ko operations ke baad bhi identifiable rakhta hai.
DataFrame mein saari Series ko same index share karne ki zaroorat kyun hai? Taaki operations columns ke across automatically data align kar sakein. Jab tum filter, sort, ya merge karte ho, index ensure karta hai ki har row ki values saath rehti hain.
df['col'] aur df[['col']] mein kya difference hai?df['col'] ek Series return karta hai (single column). df[['col']] ek DataFrame return karta hai (single-column table). Operations ke liye Series use karo, jab table structure maintain rakhna ho tab DataFrame use karo.
DataFrame boolean indexing mein and ki jagah & kyun use karna padta hai? and single booleans expect karta hai; df['score'] > 80 booleans ki Series return karta hai. & Series pe element-wise AND perform karta hai. Yahi | vs or ke liye bhi hai.
.loc[row_label, col_label] kya return karta hai?Labeled row aur column ke intersection par value. Semantic labels (names/strings) use karta hai, positions nahi.
.iloc[row_int, col_int] kya return karta hai?Positional intersection par value (jaise 2D array indexing). Integer positions (0-based) use karta hai, labels nahi.
df.loc[1] aur df.iloc[1] kab differ karte hain?Jab DataFrame ka custom (non-integer) index ho, YA jab integer index sequential na ho. .loc[1] label 1 dhundta hai, .iloc[1] position 1 dhundta hai.
Filtered DataFrame ko safely modify kaise karein? .loc with boolean indexer use karo: df.loc[df['score'] > 80, 'grade'] = 'A'. Chained assignment jaise df[df['score'] > 80]['grade'] = 'A' fail ho sakta hai (SettingWithCopyWarning).
100 rows aur 5 columns wale DataFrame ki shape kya hogi? (100, 5) - shape hoti hai (n_rows, n_columns). df.shape se access karo.
Series create karte waqt index parameter kyun use karein? Default integer index ki jagah semantic labels provide karne ke liye. Code self-documenting ban jaata hai: sales['Feb'] sales[1] se zyada clear hai.
DataFrame 2D labeled table
Label to position mapping