Data Preparation / Data Preprocessing 📂 Data Collection · 2 of 13 125 min read

Exploratory Data Analysis (EDA) with Pandas

A hands-on guide to reading datasets, understanding their structure, data types, and computing essential summary statistics — the foundation of every data science project.

🌐
SectionSection第 01 节

What Is Exploratory Data Analysis (EDA)? 🔍Exploratory Data Analysis (EDA) क्या है? 🔍什么是探索性数据分析(EDA)?🔍

EDA is the first thing you do with a new dataset, before any model or conclusion. Before you can trust data, you must understand it: its size, its types, its gaps, its odd values, and the patterns inside it.

EDA वह पहला काम है जो आप नए dataset के साथ करते हैं, किसी model या निष्कर्ष से पहले। Data पर भरोसा करने से पहले उसे समझना ज़रूरी है: उसका आकार, types, कमियाँ, अजीब मान, और अंदर छिपे patterns।

EDA 是拿到新数据集后的第一件事,先于任何模型或结论。要信任数据,先得理解它:规模、类型、缺口、异常值以及其中的规律。

EDA is a mindset more than a checklist: ask questions, look from several angles, and let the data surprise you. The statistician John Tukey made the idea popular with his 1977 book Exploratory Data Analysis, and compared it to detective work — you look for clues before you try to prove anything.

EDA checklist से ज़्यादा एक सोच है: सवाल पूछें, कई कोणों से देखें, और data को आपको चौंकाने दें। Statistician John Tukey ने अपनी 1977 की किताब Exploratory Data Analysis से यह विचार लोकप्रिय किया, और इसे जासूसी जैसा काम कहा — कुछ साबित करने से पहले आप सुराग ढूँढते हैं।

EDA 与其说是清单,不如说是一种思维方式:多提问,从多个角度看,让数据给你惊喜。统计学家约翰·图基在 1977 年的著作《探索性数据分析》中推广了这一思想,并把它比作侦探工作 —— 在证明任何东西之前,先寻找线索。

💡
Why EDA Comes Before ModellingEDA मॉडलिंग से पहले क्यों为什么 EDA 要先于建模

Surveys of data scientists consistently find that a large share of their time — often reported as somewhere between 40% and 80% — goes into getting and understanding data rather than modelling. A model built without EDA can learn from duplicated rows, wrong types, typos or a biased sample without anyone noticing.

Data scientists के surveys बार-बार दिखाते हैं कि उनके समय का बड़ा हिस्सा — अक्सर 40% से 80% के बीच बताया जाता है — modelling के बजाय data पाने और समझने में जाता है। EDA के बिना बना model duplicated rows, ग़लत types, typos या biased sample से सीख सकता है, और किसी को पता भी नहीं चलता।

对数据科学家的调查一再发现,他们很大一部分时间 —— 常见说法在 40% 到 80% 之间 —— 花在获取和理解数据上,而不是建模。不做 EDA 就建模,模型可能会从重复行、错误类型、拼写错误或有偏样本中学习,却没人察觉。


SectionSection第 02 节

The EDA Pipeline — Step by StepEDA Pipeline — क़दम दर क़दमEDA 流程 — 一步一步

01
Load the dataData load करें读入数据
Read CSV, Excel, JSON, SQL or Parquet into a DataFrame with pd.read_*().
CSV, Excel, JSON, SQL या Parquet को pd.read_*() से DataFrame में पढ़ें।
用 pd.read_*() 把 CSV、Excel、JSON、SQL 或 Parquet 读成 DataFrame。
02
Shape & structureआकार और ढाँचा形状与结构
Rows, columns and types: .shape, .dtypes, .info().
Rows, columns और types: .shape, .dtypes, .info()।
行、列和类型:.shape、.dtypes、.info()。
03
Look at real rowsअसली rows देखें查看真实行
.head(), .tail() and especially .sample() to spot odd formats and junk.
.head(), .tail() और ख़ासकर .sample() से अजीब formats और कचरा पकड़ें।
用 .head()、.tail(),尤其是 .sample(),发现异常格式和垃圾数据。
04
Fix types, find duplicatesTypes ठीक करें, duplicates ढूँढें修正类型、查找重复
pd.to_datetime(), astype("category"), .value_counts(), .duplicated().
pd.to_datetime(), astype("category"), .value_counts(), .duplicated()।
pd.to_datetime()、astype("category")、.value_counts()、.duplicated()。
05
Missing dataMissing data缺失数据
Count and understand gaps with .isnull().sum(); decide to drop, fill or flag.
.isnull().sum() से कमियाँ गिनें और समझें; हटाएँ, भरें या चिह्नित करें।
用 .isnull().sum() 统计并理解缺口;决定删除、填充还是标记。
06
Summary & grouped statisticsSummary और grouped statistics汇总与分组统计
.describe(), .skew(), .groupby() — centre, spread, shape, and differences between groups.
.describe(), .skew(), .groupby() — केंद्र, फैलाव, आकार, और groups के बीच अंतर।
.describe()、.skew()、.groupby() —— 中心、离散、形状以及组间差异。
07
OutliersOutliers异常值
IQR fences and z-scores to find values that need a closer look.
IQR fences और z-scores से वे मान ढूँढें जिन्हें क़रीब से देखना है।
用 IQR 围栏和 z 分数找出需要细看的值。
📐
This Tutorial Covers Numerical EDAयह Tutorial Numerical EDA के बारे में है本教程讲数值型 EDA

All steps above use numbers and tables. Charts (histograms, box plots, heatmaps) are covered in a separate tutorial on matplotlib and seaborn — but the simulators here already show you what those numbers look like.

ऊपर के सभी steps संख्याओं और tables का इस्तेमाल करते हैं। Charts (histograms, box plots, heatmaps) matplotlib और seaborn वाले अलग tutorial में हैं — पर यहाँ के simulators अभी से दिखाते हैं कि वे संख्याएँ कैसी दिखती हैं।

以上步骤都基于数字和表格。图表(直方图、箱线图、热力图)在另一篇 matplotlib 和 seaborn 教程中讲解 —— 不过这里的模拟器已经能让你看到这些数字长什么样。


SectionSection第 03 节

Reading the DatasetDataset पढ़ना读取数据集

Setting Upतैयारी准备工作

import pandas as pd
import numpy as np

# Optional display settings
pd.set_option("display.max_columns", 50)
pd.set_option("display.float_format", "{:.2f}".format)

Reading Different File Formatsअलग-अलग File Formats पढ़ना读取不同的文件格式

FormatFormat格式FunctionFunction函数Useful parametersकाम के parameters常用参数
CSVpd.read_csv()sep, usecols, parse_dates, dtype, na_values, encoding
Excel (.xlsx)pd.read_excel()sheet_name, skiprows, usecols (needs openpyxl)sheet_name, skiprows, usecols (openpyxl चाहिए)sheet_name、skiprows、usecols(需要 openpyxl)
JSONpd.read_json()orient, lines (one record per line)orient, lines (हर line एक record)orient、lines(每行一条记录)
SQLpd.read_sql()sql, con, params
Parquetpd.read_parquet()columns (needs pyarrow)columns (pyarrow चाहिए)columns(需要 pyarrow)
HTML tablespd.read_html()match (needs lxml)match (lxml चाहिए)match(需要 lxml)
# CSV, parsing dates and loading only the columns you need
df = pd.read_csv("orders.csv", parse_dates=["order_date"], usecols=["order_date", "city", "amount"])

# Tab-separated file
df = pd.read_csv("data.tsv", sep="\t")

# A file too big for memory: summarise each chunk, keep only the small results
totals = []
for chunk in pd.read_csv("huge.csv", chunksize=100_000):
    totals.append(chunk.groupby("city")["amount"].sum())
city_totals = pd.concat(totals).groupby(level=0).sum()

# Excel sheet
df = pd.read_excel("report.xlsx", sheet_name="Q3_Sales")

# SQL with a safe parameter (never paste user input into the SQL string)
import sqlite3
with sqlite3.connect("mydb.db") as conn:
    df = pd.read_sql("SELECT * FROM customers WHERE country = ?", conn, params=("India",))

# Parquet, only two columns
df = pd.read_parquet("data.parquet", columns=["age", "income"])
⚠️
Encoding Errors with CSV FilesCSV Files में Encoding ErrorsCSV 文件的编码错误

pandas reads CSV as UTF-8 by default, which handles Hindi, Chinese and accented letters. If you get a UnicodeDecodeError, the file was saved in another encoding. Try encoding="utf-8-sig" (files from Excel), then "cp1252" (older Windows files). "latin-1" never raises an error, but it can silently turn characters into nonsense — check the text after loading.

pandas डिफ़ॉल्ट रूप से CSV को UTF-8 में पढ़ता है, जो हिंदी, चीनी और accented अक्षर संभाल लेता है। UnicodeDecodeError मिले तो file किसी और encoding में saved है। encoding="utf-8-sig" (Excel की files) आज़माएँ, फिर "cp1252" (पुरानी Windows files)। "latin-1" कभी error नहीं देता, पर चुपचाप अक्षरों को बेमतलब बना सकता है — load के बाद text जाँचें।

pandas 默认用 UTF-8 读取 CSV,能处理中文、印地语和带重音的字母。如果出现 UnicodeDecodeError,说明文件用的是别的编码。先试 encoding="utf-8-sig"(Excel 导出的文件),再试 "cp1252"(较老的 Windows 文件)。"latin-1" 永远不会报错,但可能悄悄把字符变成乱码 —— 读入后要检查文本。

🆕
pandas 2 vs pandas 3pandas 2 बनाम pandas 3pandas 2 与 pandas 3

pandas 3.0 (released in early 2026) stores text columns with a new str dtype instead of object, and dates read with to_datetime usually get microsecond resolution (datetime64[us]) instead of nanoseconds. The outputs on this page come from pandas 3. If you use pandas 2, you will see object and datetime64[ns] instead — the ideas are the same.

pandas 3.0 (2026 की शुरुआत में जारी) text columns को object की जगह नए str dtype में रखता है, और to_datetime से पढ़ी dates आम तौर पर nanoseconds की जगह microsecond resolution (datetime64[us]) पाती हैं। इस page के outputs pandas 3 के हैं। pandas 2 में आपको object और datetime64[ns] दिखेंगे — विचार वही हैं।

pandas 3.0(2026 年初发布)用新的 str 类型代替 object 存储文本列,to_datetime 读入的日期通常为微秒精度(datetime64[us])而非纳秒。本页输出来自 pandas 3。若使用 pandas 2,你会看到 object 和 datetime64[ns] —— 道理相同。


SectionSection第 04 节

Our Practice Dataset — With Real Problems Plantedहमारा Practice Dataset — असली समस्याओं के साथ我们的练习数据集 — 预埋真实问题

Every output on this page comes from one dataset: 10,000 online orders from 2024, plus 25 duplicate rows. Like real data, it has problems hidden inside: missing ages, ratings and cities; "Female" and "female" as two different labels; four impossible delivery times; and a very skewed purchase amount. Run this code once to create sales_data.csv and follow along.

इस page का हर output एक ही dataset से है: 2024 के 10,000 online orders, और 25 duplicate rows। असली data की तरह इसमें छिपी समस्याएँ हैं: ग़ायब ages, ratings और cities; "Female" और "female" दो अलग labels; चार असंभव delivery समय; और बहुत skewed purchase amount। sales_data.csv बनाने के लिए यह code एक बार चलाएँ और साथ चलें।

本页所有输出都来自同一个数据集:2024 年的 10,000 笔网购订单,外加 25 行重复。和真实数据一样,里面藏着问题:缺失的年龄、评分和城市;“Female”和“female”被当作两个标签;四个不可能的配送天数;以及严重偏态的消费金额。运行一次这段代码生成 sales_data.csv,然后跟着做。

# 0) Build the practice dataset used in this tutorial (with real-world problems planted in it)
import numpy as np, pandas as pd
rng = np.random.default_rng(7)
n = 10_000
cats = ["Electronics", "Furniture", "Clothing", "Books", "Grocery"]
base = {"Electronics": 9.2, "Furniture": 8.8, "Clothing": 8.1, "Books": 7.1, "Grocery": 6.2}
cat = rng.choice(cats, n, p=[.15, .10, .30, .20, .25])
df = pd.DataFrame({
    "customer_id": np.arange(1001, 1001 + n),
    "age": rng.normal(34, 10, n).clip(18, 70).round(),
    "gender": rng.choice(["Male", "Female", "female", "Other"], n, p=[.48, .44, .05, .03]),
    "city": rng.choice(["Delhi", "Mumbai", "Pune", "Chandigarh", "Shimla"], n),
    "product_category": cat,
    "purchase_amount": np.round(np.exp(rng.normal([base[c] for c in cat], 0.6)), 2),
    "order_date": pd.date_range("2024-01-01", periods=366).strftime("%Y-%m-%d").to_numpy()[rng.integers(0, 366, n)],
    "rating": rng.choice([1, 2, 3, 4, 5], n, p=[.05, .08, .2, .37, .3]).astype(float),
    "delivery_days": rng.integers(1, 11, n),
})
df.loc[rng.choice(n, 157, replace=False), "age"] = np.nan          # missing ages
df.loc[rng.choice(n, 280, replace=False), "rating"] = np.nan       # missing ratings
df.loc[rng.choice(n, 9, replace=False), "city"] = np.nan           # missing cities
df.loc[rng.choice(n, 4, replace=False), "delivery_days"] = 200      # impossible values
df = pd.concat([df, df.sample(25, random_state=1)], ignore_index=True)  # 25 duplicate rows
df.to_csv("sales_data.csv", index=False)
print("saved", df.shape)
OUTPUT
saved (10025, 9)
LIVELIVE互动Inspect a Messy DataFrame — Command by Commandएक बिखरा DataFrame जाँचें — Command दर Command逐条命令检查一个杂乱的 DataFrame

A 10-row slice of the same kind of data. Click a command: it is typed, run, and the rows or cells it is about are highlighted. Can you find all four problems?

उसी तरह के data का 10-row हिस्सा। किसी command पर click करें: वह type होकर चलता है, और जिन rows या cells के बारे में है वे highlight होते हैं। क्या आप चारों समस्याएँ ढूँढ सकते हैं?

同类数据的 10 行切片。点击一条命令:它会被输入并运行,相关的行或单元格会高亮。你能找出全部四个问题吗?


SectionSection第 05 节

Understanding the Structureढाँचे को समझना理解结构

Once the data is loaded, get oriented: how big is it, what are the columns, and are the types what you expect? .info() answers most of this in one call.

Data load होने के बाद दिशा पकड़ें: यह कितना बड़ा है, columns क्या हैं, और क्या types वैसे हैं जैसी उम्मीद थी? .info() एक call में इसका ज़्यादातर जवाब देता है।

数据读入后先摸清情况:有多大?有哪些列?类型是否符合预期?.info() 一次调用就能回答大部分问题。

# 1) Load and get oriented
import pandas as pd
df = pd.read_csv("sales_data.csv")
print(df.shape)
print(df.sample(3, random_state=42))
df.info()
OUTPUT
(10025, 9) customer_id age gender ... order_date rating delivery_days 3312 4313 20.0 Male ... 2024-05-24 5.0 4 9078 10079 52.0 Male ... 2024-01-07 4.0 10 5617 6618 27.0 Male ... 2024-07-10 2.0 5 [3 rows x 9 columns] <class 'pandas.DataFrame'> RangeIndex: 10025 entries, 0 to 10024 Data columns (total 9 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 customer_id 10025 non-null int64 1 age 9867 non-null float64 2 gender 10025 non-null str 3 city 10016 non-null str 4 product_category 10025 non-null str 5 purchase_amount 10025 non-null float64 6 order_date 10025 non-null str 7 rating 9744 non-null float64 8 delivery_days 10025 non-null int64 dtypes: float64(3), int64(2), str(4) memory usage: 989.5 KB
🧮 How to Read the .info() Output.info() Output कैसे पढ़ें如何解读 .info() 输出
Check 1जाँच 1检查 1
Non-null count vs rows. 10,025 rows, but age has 9,867 non-null (158 missing), rating 9,744 (281 missing) and city 10,016 (9 missing).
Non-null गिनती बनाम rows। 10,025 rows, पर age में 9,867 non-null (158 ग़ायब), rating में 9,744 (281 ग़ायब) और city में 10,016 (9 ग़ायब)।
非空数 vs 行数。共 10,025 行,但 age 只有 9,867 个非空(缺 158),rating 9,744(缺 281),city 10,016(缺 9)。
Check 2जाँच 2检查 2
Types. order_date is text, not a date — fix with pd.to_datetime(). age is float only because NaN is a float.
Types। order_date text है, date नहीं — pd.to_datetime() से ठीक करें। age float सिर्फ़ इसलिए है क्योंकि NaN float होता है।
类型。order_date 是文本而不是日期 —— 用 pd.to_datetime() 修正。age 之所以是浮点数,只因为 NaN 是浮点数。
Check 3जाँच 3检查 3
Memory. About 1 MB here. Text columns with few distinct values can be stored much smaller as category.
Memory। यहाँ लगभग 1 MB। कम अलग मानों वाले text columns category बनाकर बहुत छोटे रखे जा सकते हैं।
内存。这里约 1 MB。取值种类少的文本列改成 category 能小很多。
💡
Why .sample() Beats .head().sample(), .head() से बेहतर क्यों为什么 .sample() 胜过 .head()

.head() always shows the first rows, which are often sorted or unusually clean. .sample() shows a random slice, so problems hidden in the middle — mixed formats, stray characters, odd values — show up much more often. Pass random_state if you want the same sample again.

.head() हमेशा पहली rows दिखाता है, जो अक्सर sorted या असामान्य रूप से साफ़ होती हैं। .sample() एक random हिस्सा दिखाता है, इसलिए बीच में छिपी समस्याएँ — मिले-जुले formats, फ़ालतू अक्षर, अजीब मान — कहीं ज़्यादा बार दिखती हैं। वही sample फिर से चाहिए तो random_state दें।

.head() 总是显示最前面几行,它们往往已排序或格外干净。.sample() 随机抽取,所以藏在中间的问题 —— 格式混杂、多余字符、异常值 —— 更容易暴露。想得到同一份样本,就传入 random_state。


SectionSection第 06 节

Data Types in PandasPandas में Data TypesPandas 中的数据类型

Every column has a dtype. It decides how values are stored, how much memory they use, and which operations work. Fixing dtypes is one of the most useful steps in EDA.

हर column का एक dtype होता है। यह तय करता है कि मान कैसे रखे जाएँ, कितनी memory लगे, और कौन-से operations चलें। dtypes ठीक करना EDA के सबसे काम के steps में से एक है।

每列都有一个 dtype。它决定值如何存储、占多少内存、能做哪些运算。修正 dtype 是 EDA 中最有用的步骤之一。

dtypedtypedtypeHoldsक्या रखता है存放Notesनोट्स说明
int64 / int32Whole numbers: counts, IDsपूर्ण संख्याएँ: गिनती, IDs整数:计数、编号Cannot hold NaN. Use the nullable Int64 if values can be missing.NaN नहीं रख सकता। मान ग़ायब हो सकते हों तो nullable Int64 लें।不能存 NaN。可能缺失时用可空的 Int64。
float64Decimals: prices, measurementsदशमलव: कीमतें, माप小数:价格、测量值A whole-number column with NaN becomes float, because NaN is a float.NaN वाला पूर्ण-संख्या column float बन जाता है, क्योंकि NaN float है।含 NaN 的整数列会变成浮点,因为 NaN 是浮点数。
str (pandas 3) / object (pandas 2)TextText文本object can also mean mixed types — a warning sign in a numeric column.object का मतलब मिले-जुले types भी हो सकता है — numeric column में ख़तरे का संकेत।object 也可能表示混合类型 —— 出现在数值列中是警告信号。
boolTrue / False flagsTrue / False flagsTrue / False 标志is_returned, has_discount. A bool column with NaN becomes object unless you use boolean.is_returned, has_discount। NaN वाला bool column object बन जाता है, जब तक boolean न लें।is_returned、has_discount。含 NaN 的布尔列会变成 object,除非用 boolean。
datetime64Dates and timesतारीख़ और समय日期时间Enables .dt.year, .dt.month, resampling and date ranges..dt.year, .dt.month, resampling और date ranges चलते हैं।可用 .dt.year、.dt.month、重采样和日期区间。
categoryA few repeated labelsकुछ दोहराए labels少量重复标签Stores each label once plus small integer codes. Less memory, faster groupby.हर label एक बार और छोटे integer codes रखता है। कम memory, तेज़ groupby।每个标签只存一次,外加小整数编码。更省内存,groupby 更快。
# 2) Fix data types and measure the memory saving
import pandas as pd
df = pd.read_csv("sales_data.csv")
before = df.memory_usage(deep=True).sum()

df["order_date"] = pd.to_datetime(df["order_date"])
for col in ["gender", "city", "product_category"]:
    df[col] = df[col].astype("category")
df["delivery_days"] = df["delivery_days"].astype("int32")

after = df.memory_usage(deep=True).sum()
print(df.dtypes)
print(f"memory: {before/1e6:.2f} MB -> {after/1e6:.2f} MB ({(1 - after/before)*100:.0f}% smaller)")
print(df["gender"].value_counts())          # spot the problem!
OUTPUT
customer_id int64 age float64 gender category city category product_category category purchase_amount float64 order_date datetime64[us] rating float64 delivery_days int32 dtype: object memory: 1.01 MB -> 0.47 MB (53% smaller) gender Male 4775 Female 4394 female 546 Other 310 Name: count, dtype: int64
💾 PICTURE 1 — MEMORY BEFORE AND AFTER FIXING TYPESतस्वीर 1 — TYPES ठीक करने से पहले और बाद MEMORY图 1 — 修正类型前后的内存
Memory per column before and after fixing types gender 130 KB 10 KB city 144 KB 10 KB product_category 157 KB 10 KB order_date 180 KB 80 KB delivery_days 80 KB 40 KB purchase_amount 80 KB 80 KB as loaded (str / int64)जैसा load हुआ (str / int64)读入时(str / int64) after: category / datetime / int32बाद में: category / datetime / int32之后:category / datetime / int32

Measured on our dataset: 1.01 MB → 0.47 MB in total. With pandas 2 (object text) the saving on text columns is usually even bigger.

हमारे dataset पर मापा: कुल 1.01 MB → 0.47 MB। pandas 2 (object text) में text columns पर बचत आम तौर पर और ज़्यादा होती है।

在我们的数据集上实测:总计 1.01 MB → 0.47 MB。在 pandas 2(object 文本)中,文本列的节省通常更大。

🎯
Look Before You ConvertConvert करने से पहले देखें转换前先看一眼

Before you turn a text column into category, run .value_counts(). Our gender column has "Female" (4,394) and "female" (546) — one group split in two. Fix it first with df["gender"] = df["gender"].str.strip().str.title(). A good rule of thumb for category: few distinct values compared with the number of rows.

Text column को category बनाने से पहले .value_counts() चलाएँ। हमारे gender column में "Female" (4,394) और "female" (546) हैं — एक group दो में बँटा। पहले df["gender"] = df["gender"].str.strip().str.title() से ठीक करें। category के लिए अच्छा नियम: rows की तुलना में कम अलग मान।

把文本列转成 category 之前,先运行 .value_counts()。我们的 gender 列里有 “Female”(4,394)和“female”(546) —— 同一组被拆成两组。先用 df["gender"] = df["gender"].str.strip().str.title() 修正。category 的经验法则:与行数相比,取值种类很少。


SectionSection第 07 节

Identifying Missing DataMissing Data पहचानना识别缺失数据

pandas marks missing values as NaN (numbers), NaT (dates) or NA (nullable types). Before computing statistics, find out how much is missing and, just as important, why.

pandas ग़ायब मानों को NaN (संख्याएँ), NaT (dates) या NA (nullable types) से दिखाता है। Statistics निकालने से पहले पता करें कि कितना ग़ायब है और, उतना ही ज़रूरी, क्यों।

pandas 用 NaN(数值)、NaT(日期)或 NA(可空类型)标记缺失值。计算统计量之前,要弄清缺了多少,同样重要的是为什么缺。

# 3) Missing values: count, percent, and how pandas treats NaN
import numpy as np, pandas as pd
df = pd.read_csv("sales_data.csv")
miss = df.isnull().sum()
pct = (df.isnull().mean() * 100).round(2)
print(pd.DataFrame({"missing": miss, "%": pct})[miss > 0])

print("pandas mean (skips NaN):", round(df["rating"].mean(), 3))
print("numpy mean (NaN spreads):", np.mean(df["rating"].to_numpy()))
print("rows actually used:", df["rating"].count(), "of", len(df))
OUTPUT
missing % age 158 1.58 city 9 0.09 rating 281 2.80 pandas mean (skips NaN): 3.779 numpy mean (NaN spreads): nan rows actually used: 9744 of 10025
⚠️
pandas Skips NaN Quietlypandas चुपचाप NaN छोड़ देता हैpandas 会悄悄跳过 NaN

pandas methods like .mean() and .sum() skip NaN by default, so they give an answer — but based on fewer rows (9,744 of 10,025 ratings above). NumPy functions return nan instead. Neither warns you, which is why you count missing values first.

.mean() और .sum() जैसे pandas methods डिफ़ॉल्ट रूप से NaN छोड़ देते हैं, इसलिए जवाब देते हैं — पर कम rows पर आधारित (ऊपर 10,025 में से 9,744 ratings)। NumPy functions इसके बजाय nan लौटाते हैं। कोई भी चेतावनी नहीं देता, इसीलिए पहले missing values गिनें।

.mean()、.sum() 等 pandas 方法默认跳过 NaN,所以会给出结果 —— 但基于更少的行(上面 10,025 条评分中只用了 9,744 条)。NumPy 函数则直接返回 nan。两者都不会提醒你,所以要先统计缺失值。

Situationस्थिति情况Common approachआम तरीका常见做法CodeCode代码
Very few missing, at randomबहुत कम ग़ायब, random极少且随机缺失Drop those rows, or fill with the medianवे rows हटाएँ, या median से भरें删除这些行,或用中位数填充df.dropna(subset=["age"])
More missing, other columns help predict itज़्यादा ग़ायब, दूसरे columns अनुमान में मदद करें缺失较多,其他列能帮助预测Model-based filling (KNN, iterative)Model-based भरना (KNN, iterative)基于模型的填充(KNN、迭代)sklearn.impute.KNNImputer
The fact that it is missing may matterग़ायब होना ख़ुद मायने रख सकता है“缺失”本身可能有意义Add a 0/1 "was missing" column, then fill0/1 "ग़ायब था" column जोड़ें, फिर भरें先加一列 0/1“是否缺失”,再填充df["age_missing"] = df["age"].isna().astype(int)
Mostly empty columnज़्यादातर ख़ाली column基本为空的列Consider dropping it — unless it is importantहटाने पर विचार करें — जब तक ज़रूरी न हो考虑删除 —— 除非它很重要df.drop(columns=["col"])
🧠
The Percentage Is Not the Whole Storyप्रतिशत पूरी कहानी नहीं है比例并不能说明一切

What matters most is why values are missing. Missing completely at random (a form was lost) is the easy case. If the chance of missing depends on the value itself — older customers skip the age question — every simple fill gives a biased answer. Also: compute fill values (mean, median) on the training data only, then apply them to test data, to avoid leaking information.

सबसे ज़रूरी है कि मान क्यों ग़ायब हैं। पूरी तरह random ग़ायब (कोई form खो गया) आसान मामला है। अगर ग़ायब होने का chance ख़ुद मान पर निर्भर है — बड़ी उम्र के ग्राहक age वाला सवाल छोड़ देते हैं — तो हर सरल भराई biased जवाब देती है। साथ ही: भरने वाले मान (mean, median) सिर्फ़ training data पर निकालें, फिर test data पर लगाएँ, ताकि जानकारी leak न हो।

最重要的是值为什么缺失。完全随机缺失(某张表丢了)是简单情形。如果缺失的概率取决于值本身 —— 年长顾客不填年龄 —— 任何简单填充都会带来偏差。另外:填充值(均值、中位数)要只在训练数据上计算,再应用到测试数据,以免信息泄漏。

LIVELIVE互动Missing Data — Mechanism and FillingMissing Data — कारण और भराई缺失数据 — 机制与填充

200 true ages. Choose why some go missing and how many, then choose a fix. Compare the histogram after handling (bars) with the truth (dashed outline), and watch the mean and std.

200 असली ages। चुनें कि कुछ क्यों और कितने ग़ायब होते हैं, फिर एक उपाय चुनें। संभालने के बाद के histogram (bars) की तुलना सच (dashed outline) से करें, और mean व std देखें।

200 个真实年龄。选择缺失的原因和数量,再选一种处理方法。把处理后的直方图(柱)与真实情况(虚线轮廓)比较,并观察均值和标准差。


SectionSection第 08 节

Summary StatisticsSummary Statistics汇总统计

Summary statistics squeeze a whole column into a few numbers about its centre, spread and shape. They tell you what to expect before you draw any chart.

Summary statistics पूरे column को कुछ संख्याओं में समेट देते हैं: उसका केंद्र, फैलाव और आकार। कोई chart बनाने से पहले ये बताते हैं कि क्या उम्मीद करें।

汇总统计把一整列压缩成几个数字,描述它的中心、离散程度和形状。在画图之前,它们就告诉你该期待什么。

Mean ⚖️Mean ⚖️均值 ⚖️
x̄ = Σxᵢ / n
The balance point. One extreme value can pull it a long way.
संतुलन बिंदु। एक अति मान इसे बहुत दूर खींच सकता है।
平衡点。一个极端值就能把它拉得很远。
Median 🎯Median 🎯中位数 🎯
middle value when sortedsorted होने पर बीच का मान排序后的中间值
Robust to outliers. Usually the better "typical value" for skewed data like income or prices.
Outliers से अप्रभावित। income या कीमतों जैसे skewed data के लिए आम तौर पर बेहतर "आम मान"।
不受异常值影响。对收入、价格这类偏态数据,通常是更好的“典型值”。
Mode 📌Mode 📌众数 📌
most frequent valueसबसे ज़्यादा बार आने वाला मान出现次数最多的值
The only "average" for labels like city or colour.
City या रंग जैसे labels के लिए इकलौता "औसत"।
对城市、颜色等标签,它是唯一的“平均”。
Variance 📐Variance 📐方差 📐
s² = Σ(xᵢ − x̄)² / (n − 1)
Average squared distance from the mean. Its units are squared, so it is hard to read directly.
Mean से औसत वर्ग दूरी। इसकी इकाई वर्ग में होती है, इसलिए सीधे पढ़ना कठिन है।
到均值的平均平方距离。单位是平方,所以不便直接解读。
Std dev 📊Std dev 📊标准差 📊
s = √s²
Back in the original units: a typical distance from the mean.
मूल इकाई में वापस: mean से आम दूरी।
回到原单位:到均值的典型距离。
IQR 📏IQR 📏IQR 📏
IQR = Q3 − Q1
The spread of the middle 50%. Robust to outliers; the basis of box plots.
बीच के 50% का फैलाव। Outliers से अप्रभावित; box plots का आधार।
中间 50% 的范围。不受异常值影响,是箱线图的基础。
📌
Sample vs Population — the n − 1 RuleSample बनाम Population — n − 1 नियम样本 vs 总体 — n − 1 规则

pandas .var() and .std() divide by n − 1 by default (ddof=1), the usual choice when your data are a sample. NumPy's np.std() divides by n (ddof=0) — so the two can disagree slightly. Pass ddof explicitly when it matters.

pandas के .var() और .std() डिफ़ॉल्ट रूप से n − 1 से भाग देते हैं (ddof=1), जो data sample होने पर आम चुनाव है। NumPy का np.std() n से भाग देता है (ddof=0) — इसलिए दोनों थोड़ा अलग हो सकते हैं। ज़रूरी हो तो ddof साफ़ दें।

pandas 的 .var() 和 .std() 默认除以 n − 1(ddof=1),这是数据为样本时的常规选择。NumPy 的 np.std() 除以 n(ddof=0)—— 所以两者可能略有差异。需要时请明确指定 ddof。

describe(), skew and groupby on Our Dataहमारे Data पर describe(), skew और groupby在我们的数据上运行 describe()、skew 和 groupby

# 4) Summary statistics, skew, and grouped statistics
import pandas as pd
df = pd.read_csv("sales_data.csv").drop_duplicates()
print(df[["purchase_amount", "age", "rating", "delivery_days"]].describe().round(2))
print("\nskew of purchase_amount:", round(df["purchase_amount"].skew(), 2))
print("\nmean purchase by category:")
print(df.groupby("product_category")["purchase_amount"].agg(["mean", "median", "count"])
        .sort_values("mean", ascending=False).round(0))
OUTPUT
purchase_amount age rating delivery_days count 10000.00 9843.00 9720.00 10000.00 mean 4174.45 34.23 3.78 5.57 std 5314.11 9.48 1.10 4.83 min 66.56 18.00 1.00 1.00 25% 766.99 27.00 3.00 3.00 50% 2180.28 34.00 4.00 5.00 75% 5523.58 41.00 5.00 8.00 max 59869.05 70.00 5.00 200.00 skew of purchase_amount: 2.81 mean purchase by category: mean median count product_category Electronics 11821.0 9916.0 1500 Furniture 8007.0 6783.0 1000 Clothing 3963.0 3320.0 2963 Books 1406.0 1181.0 2000 Grocery 572.0 489.0 2537
🧮 How to Read This describe() Outputइस describe() Output को कैसे पढ़ें如何解读这份 describe() 输出
count
Non-null values after removing duplicates: age 9,843 of 10,000 → 157 missing.
Duplicates हटाने के बाद non-null मान: age 10,000 में 9,843 → 157 ग़ायब।
去重后的非空数:age 10,000 中有 9,843 → 缺 157。
mean vs 50%
purchase_amount mean ₹4,174 vs median ₹2,180: the mean is almost twice the median → strongly right-skewed (skew = 2.81). Report the median as the typical order.
purchase_amount का mean ₹4,174 बनाम median ₹2,180: mean लगभग median का दोगुना → बहुत right-skewed (skew = 2.81)। आम order के रूप में median बताएँ।
purchase_amount 均值 ₹4,174 vs 中位数 ₹2,180:均值几乎是中位数的两倍 → 强烈右偏(偏度 = 2.81)。用中位数代表典型订单。
std
₹5,314 on a mean of ₹4,174 — a coefficient of variation of about 127%. Big spread, driven by the long tail.
₹4,174 के mean पर ₹5,314 — लगभग 127% का coefficient of variation। बड़ा फैलाव, लंबी tail की वजह से।
均值 ₹4,174 时标准差为 ₹5,314 —— 变异系数约 127%。离散度很大,来自长尾。
min / max
delivery_days max = 200 while the 75% value is 8. That is not an insight — it is an error to investigate.
delivery_days का max = 200 जबकि 75% मान 8 है। यह कोई खोज नहीं — यह जाँचने लायक़ ग़लती है।
delivery_days 最大值 200,而 75% 分位只有 8。这不是洞见 —— 是需要排查的错误。
25% / 75%
IQR of purchase_amount = 5,523.58 − 766.99 = ₹4,757. Half of all orders fall in this range.
purchase_amount का IQR = 5,523.58 − 766.99 = ₹4,757। आधे orders इसी range में हैं।
purchase_amount 的 IQR = 5,523.58 − 766.99 = ₹4,757。一半订单落在这个范围内。
📊 PICTURE 2 — describe() ON A SKEWED COLUMNतस्वीर 2 — SKEWED COLUMN पर describe()图 2 — 偏态列上的 describe()
What describe() means on a right-skewed column ≥19.5k ₹0k ₹5k ₹10k ₹15k ₹20k 25%: ₹767 50% (median): ₹2,180 mean: ₹4,174 75%: ₹5,524 max ₹59,869 IQR = ₹4,757 purchase_amount (10,000 orders): mean ₹4,174 is far above median ₹2,180 → long right tail (skew = 2.81)purchase_amount (10,000 orders): mean ₹4,174, median ₹2,180 से बहुत ऊपर → लंबी right tail (skew = 2.81)purchase_amount(10,000 笔订单):均值 ₹4,174 远高于中位数 ₹2,180 → 右侧长尾(偏度 = 2.81)
LIVELIVE互动Mean vs Median — Add One Huge PurchaseMean बनाम Median — एक बहुत बड़ी ख़रीद जोड़ें均值 vs 中位数 — 加入一笔巨额消费

40 purchases. Switch between symmetric and right-skewed data, then add one huge order. Watch which statistics move and which stay put.

40 ख़रीदें। Symmetric और right-skewed data के बीच बदलें, फिर एक बहुत बड़ा order जोड़ें। देखें कौन-से statistics हिलते हैं और कौन-से स्थिर रहते हैं।

40 笔消费。在对称和右偏数据之间切换,再加入一笔巨额订单。看看哪些统计量会动,哪些保持不变。


SectionSection第 09 节

Grouped StatisticsGrouped Statistics分组统计

Overall numbers rarely tell the full story. The category table above shows Electronics orders average ₹11,821 while Grocery orders average ₹572 — a 20× difference hidden inside the single overall mean. .groupby() works in three steps: split the rows into groups, apply a function to each group, and combine the results.

कुल संख्याएँ शायद ही पूरी कहानी बताती हैं। ऊपर की category table में Electronics orders का औसत ₹11,821 है जबकि Grocery का ₹572 — एक कुल mean में छिपा 20 गुना अंतर। .groupby() तीन steps में काम करता है: rows को groups में बाँटें, हर group पर function लगाएँ, और नतीजे जोड़ें।

总体数字很少能说明全部。上面的类别表显示:电子产品订单平均 ₹11,821,而杂货订单平均 ₹572 —— 一个总体均值里藏着 20 倍的差距。.groupby() 分三步:把行拆分成组,对每组应用函数,再把结果合并。

# Several statistics per group
df.groupby("gender")["purchase_amount"].agg(["mean", "median", "count"])

# Two grouping columns -> a table
df.groupby(["city", "product_category"])["purchase_amount"].median().unstack()

# Correlation between numeric columns
df.corr(numeric_only=True).round(2)
LIVELIVE互动groupby: Split → Apply → Combinegroupby: बाँटें → लागू करें → जोड़ेंgroupby:拆分 → 应用 → 合并

Twelve orders. Pick an aggregation and run: rows fly into their groups, the function is applied to each group, and the results form a new, smaller table.

बारह orders। एक aggregation चुनें और चलाएँ: rows अपने groups में जाती हैं, हर group पर function लगता है, और नतीजे एक नई, छोटी table बनाते हैं।

十二笔订单。选一种聚合并运行:各行飞入所属组,函数作用于每组,结果组成一张更小的新表。

💡
When Mean ≠ Median — The Skew Signalजब Mean ≠ Median — Skew का संकेत当均值 ≠ 中位数 — 偏态信号

When the mean is well above the median, the data are right-skewed — common for income, prices and website traffic — and the median is the more honest "typical" value. .skew() puts a number on it: beyond about ±0.5 is moderately skewed, beyond ±1 strongly skewed. Notice in the category table that even within each group the mean is above the median.

जब mean, median से काफ़ी ऊपर हो, तो data right-skewed है — income, कीमतों और website traffic में आम — और median ज़्यादा ईमानदार "आम" मान है। .skew() इसे संख्या देता है: लगभग ±0.5 से आगे मध्यम skewed, ±1 से आगे बहुत skewed। Category table में देखें कि हर group के अंदर भी mean, median से ऊपर है।

当均值明显高于中位数时,数据右偏 —— 收入、价格、网站流量都很常见 —— 此时中位数是更诚实的“典型值”。.skew() 给出量化:超过约 ±0.5 为中度偏态,超过 ±1 为强偏态。注意类别表中,即使在每组内部,均值也高于中位数。


SectionSection第 10 节

Detecting OutliersOutliers पहचानना检测异常值

An outlier is a value far from the bulk of the data. It may be a real extreme (a huge order), a data-entry error (200 delivery days), or a measurement fault. EDA should find them; deciding what to do needs domain knowledge.

Outlier ऐसा मान है जो ज़्यादातर data से दूर हो। यह असली अति हो सकता है (बहुत बड़ा order), data-entry की ग़लती (200 delivery दिन), या माप की गड़बड़ी। EDA को इन्हें ढूँढना चाहिए; क्या करना है, यह तय करने के लिए domain की समझ चाहिए।

异常值是远离大部分数据的值。它可能是真实的极端值(巨额订单)、录入错误(配送 200 天)或测量故障。EDA 负责发现它们;如何处理需要领域知识。

# 5) Outliers: IQR fences, z-score and modified z-score
import numpy as np, pandas as pd
df = pd.read_csv("sales_data.csv").drop_duplicates()

def iqr_outliers(s, k=1.5):
    q1, q3 = s.quantile([.25, .75])
    lo, hi = q1 - k * (q3 - q1), q3 + k * (q3 - q1)
    return s[(s < lo) | (s > hi)], lo, hi

for col in ["delivery_days", "purchase_amount"]:
    s = df[col].dropna()
    out, lo, hi = iqr_outliers(s)
    z = (s - s.mean()) / s.std()
    mad = (s - s.median()).abs().median()
    mz = 0.6745 * (s - s.median()) / mad
    print(f"{col}: fences [{lo:.1f}, {hi:.1f}] -> IQR flags {len(out)}, "
          f"|z|>3 flags {(z.abs() > 3).sum()}, modified-z>3.5 flags {(mz.abs() > 3.5).sum()}")
print("largest delivery_days:", sorted(df['delivery_days'].unique())[-3:])
OUTPUT
delivery_days: fences [-4.5, 15.5] -> IQR flags 4, |z|>3 flags 4, modified-z>3.5 flags 4 purchase_amount: fences [-6367.9, 12658.5] -> IQR flags 696, |z|>3 flags 228, modified-z>3.5 flags 929 largest delivery_days: [np.int64(9), np.int64(10), np.int64(200)]
🔎
Read These Results Carefullyइन नतीजों को ध्यान से पढ़ें仔细解读这些结果

For delivery_days all three methods find exactly the 4 planted errors (the value 200). For purchase_amount they disagree wildly — 696, 228 and 929 flags — because the column is naturally skewed: most "outliers" are just big, real orders in the long tail. On skewed data, look at the log of the values or at the business context before you delete anything.

delivery_days में तीनों तरीके ठीक 4 डाली गई ग़लतियाँ (मान 200) पकड़ते हैं। purchase_amount में वे बहुत असहमत हैं — 696, 228 और 929 — क्योंकि column स्वाभाविक रूप से skewed है: ज़्यादातर "outliers" लंबी tail के बड़े, असली orders हैं। Skewed data में कुछ भी हटाने से पहले मानों का log या business का संदर्भ देखें।

对 delivery_days,三种方法都恰好找到了 4 个预埋错误(值为 200)。对 purchase_amount,结果差异极大 —— 分别标记 696、228 和 929 个 —— 因为这一列天然偏态:大多数“异常值”只是长尾中真实的大额订单。对偏态数据,删除任何东西之前,先看取对数后的值或业务背景。

Methodतरीका方法Ruleनियम规则Assumes normal data?Normal data मानता है?假设正态?Best forसबसे अच्छा适用
IQR fencesIQR fencesIQR 围栏x < Q1 − 1.5·IQR or x > Q3 + 1.5·IQRNoनहीं否General first check; robustआम पहली जाँच; robust通用的初步检查;稳健
Z-score|x − mean| / std > 3Yesहाँ是Roughly normal data; can be fooled by the outliers themselvesलगभग normal data; outliers ख़ुद इसे धोखा दे सकते हैं近似正态数据;可能被异常值本身蒙蔽
Modified z-scoreModified z-score修正 z 分数0.6745 · |x − median| / MAD > 3.5Noनहीं否Robust; small samplesRobust; छोटे samples稳健;小样本
Isolation Forestanomaly scoreanomaly score异常分数Noनहीं否Several columns at onceएक साथ कई columns同时考虑多列
LIVELIVE互动IQR vs Z-Score — Who Gets Flagged?IQR बनाम Z-Score — किसे चिह्नित किया जाता है?IQR vs z 分数 — 谁会被标记?

120 values. Orange rings are flagged by the IQR rule; red dots by the z-score rule. Switch data types and move both thresholds.

120 मान। नारंगी घेरे IQR नियम से चिह्नित हैं; लाल बिंदु z-score नियम से। Data प्रकार बदलें और दोनों सीमाएँ खिसकाएँ।

120 个值。橙色圆圈是 IQR 规则标记的,红点是 z 分数规则标记的。切换数据类型并移动两个阈值。


SectionSection第 11 节

A Reusable EDA Reportदोबारा इस्तेमाल लायक़ EDA Report可复用的 EDA 报告

Paste this function into your notebook and pass any DataFrame. It works on pandas 2 and 3. Here is its real output on our dataset — every planted problem shows up.

यह function अपनी notebook में डालें और कोई भी DataFrame दें। यह pandas 2 और 3 दोनों पर चलता है। हमारे dataset पर इसका असली output यह है — हर डाली गई समस्या दिखती है।

把这个函数粘贴到你的笔记本中,传入任意 DataFrame 即可。它在 pandas 2 和 3 上都能运行。下面是它在我们数据集上的真实输出 —— 每个预埋问题都暴露了。

# 6) A compact, reusable EDA report
import pandas as pd

def run_eda(df, name="Dataset"):
    print(f"== EDA REPORT: {name} ==")
    print(f"[1] shape: {df.shape[0]:,} rows x {df.shape[1]} columns")
    miss = df.isnull().mean().mul(100).round(2)
    print("[2] missing %:", miss[miss > 0].to_dict())
    print(f"[3] duplicate rows: {df.duplicated().sum()}")
    num = df.select_dtypes("number")
    print("[4] min / max:")
    print(num.agg(["min", "max"]).T.to_string())
    skew = num.skew().round(2)
    print("[5] |skew| > 1:", skew[skew.abs() > 1].to_dict())
    for col in df.select_dtypes(exclude=["number", "datetime"]).columns:   # text + category (pandas 2 and 3)
        print(f"[6] {col}: {df[col].nunique()} unique, top = {df[col].value_counts().head(3).to_dict()}")

run_eda(pd.read_csv("sales_data.csv"), "Sales 2024")
OUTPUT
== EDA REPORT: Sales 2024 == [1] shape: 10,025 rows x 9 columns [2] missing %: {'age': 1.58, 'city': 0.09, 'rating': 2.8} [3] duplicate rows: 25 [4] min / max: min max customer_id 1001.00 11000.00 age 18.00 70.00 purchase_amount 66.56 59869.05 rating 1.00 5.00 delivery_days 1.00 200.00 [5] |skew| > 1: {'purchase_amount': 2.81, 'delivery_days': 26.05} [6] gender: 4 unique, top = {'Male': 4775, 'Female': 4394, 'female': 546} [6] city: 5 unique, top = {'Chandigarh': 2058, 'Delhi': 2024, 'Shimla': 1987} [6] product_category: 5 unique, top = {'Clothing': 2967, 'Grocery': 2545, 'Books': 2007} [6] order_date: 366 unique, top = {'2024-04-04': 44, '2024-06-01': 39, '2024-09-28': 39}
✅
What to Do After Numerical EDANumerical EDA के बाद क्या करें数值型 EDA 之后做什么

(1) Clean: drop duplicates, fix "female" → "Female", investigate the 200-day deliveries, and handle missing values with a reason. (2) Visualise: histograms, box plots and correlation heatmaps. (3) Engineer features: date parts, log of skewed amounts, encoded categories.

(1) साफ़ करें: duplicates हटाएँ, "female" → "Female" ठीक करें, 200-दिन वाली deliveries की जाँच करें, और missing values को कारण के साथ संभालें। (2) Visualise करें: histograms, box plots और correlation heatmaps। (3) Features बनाएँ: date के हिस्से, skewed राशियों का log, encoded categories।

(1) 清洗:删除重复,把“female”改成“Female”,排查 200 天的配送,并有理由地处理缺失值。(2) 可视化:直方图、箱线图和相关热力图。(3) 特征工程:日期拆分、对偏态金额取对数、类别编码。


SectionSection第 12 节

Golden Rules of EDAEDA के सुनहरे नियमEDA 黄金法则

🎯 9 Rules Every Data Scientist Should Follow9 नियम जो हर Data Scientist को मानने चाहिए每位数据科学家都应遵守的 9 条法则
1
Run .info(), .describe() and .sample() right after loading — before writing any transformation code.
Load करते ही .info(), .describe() और .sample() चलाएँ — कोई transformation code लिखने से पहले।
读入后立刻运行 .info()、.describe() 和 .sample() —— 在写任何转换代码之前。
2
Never trust a dtype. A "price" column stored as text, or a date stored as a string, is one of the most common bugs. Check .dtypes and fix types early.
किसी dtype पर भरोसा न करें। Text के रूप में रखा "price" column, या string के रूप में रखी date, सबसे आम bugs में से है। .dtypes जाँचें और types जल्दी ठीक करें।
不要轻信 dtype。以文本存储的“价格”列、以字符串存储的日期,是最常见的错误之一。检查 .dtypes,尽早修正类型。
3
Run .value_counts() on every text column. Different spellings of the same label ("Female" / "female") split your groups.
हर text column पर .value_counts() चलाएँ। एक ही label की अलग वर्तनी ("Female" / "female") आपके groups बाँट देती है।
对每个文本列运行 .value_counts()。同一标签的不同写法(“Female”/“female”)会把组拆开。
4
Report both mean and median for every continuous column. If they differ a lot, the data are skewed and the median is usually the better typical value.
हर continuous column के लिए mean और median दोनों बताएँ। बहुत अलग हों तो data skewed है और median आम तौर पर बेहतर आम मान है।
每个连续列都同时报告均值和中位数。若相差很大,说明数据偏态,中位数通常是更好的典型值。
5
Count missing values before any aggregate. pandas skips NaN silently, so a mean may rest on fewer rows than you think — and ask why values are missing.
किसी भी aggregate से पहले missing values गिनें। pandas चुपचाप NaN छोड़ता है, इसलिए mean सोच से कम rows पर टिका हो सकता है — और पूछें कि मान क्यों ग़ायब हैं।
做任何聚合前先统计缺失值。pandas 会悄悄跳过 NaN,所以均值可能基于比你想象更少的行 —— 还要问值为什么缺失。
6
Check for duplicate rows with .duplicated().sum(). Duplicates inflate counts and can leak between training and test data.
.duplicated().sum() से duplicate rows जाँचें। Duplicates गिनती बढ़ाते हैं और training व test data के बीच leak कर सकते हैं।
用 .duplicated().sum() 检查重复行。重复会抬高计数,还可能在训练集和测试集之间造成泄漏。
7
Validate min and max against common sense. An age of 0, a negative price or a 200-day delivery is a data problem, not an insight.
Min और max को सामान्य समझ से जाँचें। 0 उम्र, negative कीमत या 200-दिन की delivery data की समस्या है, कोई खोज नहीं।
用常识检验最小值和最大值。年龄为 0、价格为负、配送 200 天,都是数据问题而不是洞见。
8
Do not delete outliers automatically. On skewed data many flagged values are real; find the cause first.
Outliers को अपने आप न हटाएँ। Skewed data में कई चिह्नित मान असली होते हैं; पहले कारण ढूँढें।
不要自动删除异常值。偏态数据中很多被标记的值是真实的;先找原因。
9
Write down every finding in a markdown cell. EDA that lives only in your head helps nobody — including you, six months later.
हर खोज markdown cell में लिखें। जो EDA सिर्फ़ आपके दिमाग़ में है वह किसी के काम का नहीं — छह महीने बाद आपके भी नहीं।
把每个发现写进 markdown 单元格。只存在于你脑子里的 EDA 对谁都没用 —— 包括半年后的你自己。