Free tutorials & notes in Hindi & English · Clean code examples 🧰 Free PDF & Image Tools →
🧹 Week 3 – Data Cleaning & EDA  ·  Day 16

Day 16: Dates, Times & Text Columns

⏱ 2 hours📶 Intermediate🎯 100% self-study
Day 16 / 60

✅ Today you will learn

  • Parse dates and use .dt (year, month, day_name)
  • Time differences with Timedelta
  • resample() and rolling() on time series
  • Clean and search text with .str
  • Extract numbers and words with regex

🏢 In the real world

Two everyday questions: “Which weekday brings the most orders – should we run the sale on Friday or Sunday?” and “How bad was Delhi’s air in November compared with July?” Both need dates. A third – “What are customers complaining about?” – needs text.

Dates with .dt

Python
import pandas as pd
sales = pd.read_csv("sales_data.csv", parse_dates=["order_date"])
print(sales["order_date"].dtype, sales["order_date"].min().date(), "→", sales["order_date"].max().date())
sales["month"] = sales["order_date"].dt.month
sales["month_name"] = sales["order_date"].dt.strftime("%b")
sales["weekday"] = sales["order_date"].dt.day_name()
sales["is_weekend"] = sales["order_date"].dt.dayofweek >= 5
print(sales[["order_date", "month", "month_name", "weekday", "is_weekend"]].head(3))
datetime64[ns] 2024-01-01 → 2024-12-31 order_date month month_name weekday is_weekend 0 2024-01-01 1 Jan Monday False 1 2024-01-01 1 Jan Monday False 2 2024-01-01 1 Jan Monday False
Python
import pandas as pd
sales = pd.read_csv("sales_data.csv", parse_dates=["order_date"])
order = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]
by_day = sales["order_date"].dt.day_name().value_counts().reindex(order)
print(by_day)
print("Best day:", by_day.idxmax())
order_date Monday 250 Tuesday 267 Wednesday 262 Thursday 250 Friday 257 Saturday 368 Sunday 346 Name: count, dtype: int64 Best day: Saturday
Python
import pandas as pd
sales = pd.read_csv("sales_data.csv", parse_dates=["order_date"])
sales["festive"] = sales["order_date"].between("2024-10-01", "2024-11-15")
sales["revenue"] = sales["quantity"] * sales["unit_price"] * (1 - sales["discount"])
days = {True: 46, False: 366 - 46}
per_day = sales.groupby("festive")["revenue"].sum() / pd.Series(days)
print(per_day.round())
print("Festive days earn", round(per_day[True] / per_day[False], 1), "x a normal day")
False 16981.0 True 31434.0 dtype: float64 Festive days earn 1.9 x a normal day

Date arithmetic

Python
import pandas as pd
emp = pd.read_csv("employees.csv", parse_dates=["join_date"])
today = pd.Timestamp("2025-01-01")
emp["tenure_days"] = (today - emp["join_date"]).dt.days
emp["tenure_years"] = (emp["tenure_days"] / 365.25).round(1)
emp["review_due"] = emp["join_date"] + pd.DateOffset(years=5)
print(emp[["name", "join_date", "tenure_years", "review_due"]].head(4))
print("Average tenure:", emp["tenure_years"].mean().round(1), "years")
name join_date tenure_years review_due 0 Aarav 2020-01-05 5.0 2025-01-05 1 Diya 2019-12-31 5.0 2024-12-31 2 Kabir 2016-10-18 8.2 2021-10-18 3 Ananya 2019-03-17 5.8 2024-03-17 Average tenure: 4.6 years

resample and rolling: time-series views

Python
import pandas as pd
w = pd.read_csv("delhi_weather.csv", parse_dates=["date"]).set_index("date")
monthly = w["aqi"].resample("ME").mean().round()
print(monthly["2024"].to_string())
print("Worst month:", monthly.idxmax().strftime("%b %Y"), "AQI", int(monthly.max()))
date 2024-01-31 295.0 2024-02-29 282.0 2024-03-31 248.0 2024-04-30 185.0 2024-05-31 138.0 2024-06-30 96.0 2024-07-31 78.0 2024-08-31 101.0 2024-09-30 144.0 2024-10-31 191.0 2024-11-30 251.0 2024-12-31 280.0 Freq: ME Worst month: Jan 2023 AQI 302
Python
import pandas as pd
import matplotlib.pyplot as plt
w = pd.read_csv("delhi_weather.csv", parse_dates=["date"]).set_index("date")
fig, ax = plt.subplots(figsize=(10, 4.2))
ax.plot(w.index, w["aqi"], color="#cbd5e1", lw=0.8, label="Daily AQI")
ax.plot(w.index, w["aqi"].rolling(30).mean(), color="#dc2626", lw=2.2, label="30-day average")
ax.axhline(200, color="#f59e0b", ls="--", lw=1, label="Poor (200)")
ax.set_title("Delhi air quality 2022–2024: every winter is a crisis")
ax.set_ylabel("AQI"); ax.legend()
plt.show()
Line chart of Delhi daily AQI with 30-day rolling average peaking every winter
rolling(30).mean() removes day-to-day noise and reveals the seasonal pattern.
CodeMeaning
"D" / "W"day / week
"ME" / "MS"month end / month start
"QE"quarter end
"YE"year end

Text with .str

Python
import pandas as pd
rv = pd.read_csv("product_reviews.csv")
print(rv.head(3))
rv["clean"] = rv["review"].str.lower().str.replace(r"[^a-z ]", "", regex=True).str.strip()
rv["words"] = rv["clean"].str.split().str.len()
print(rv[["clean", "words"]].head(3))
print("Average words per review:", rv["words"].mean().round(1))
review stars sentiment 0 Colour faded after first wash One star. 1 negative 1 Fabric is soft and colour is same as photo 4 positive 2 Product is fake, not original Never again. 2 negative clean words 0 colour faded after first wash one star 7 1 fabric is soft and colour is same as photo 9 2 product is fake not original never again 7 Average words per review: 7.2
Python
import pandas as pd
rv = pd.read_csv("product_reviews.csv")
text = rv["review"].str.lower()
topics = {"delivery": "deliver|late|courier", "quality": "quality|broke|stopped|faded|cheap",
          "size": "size|fit|small|tight", "refund": "refund|return|replace"}
for name, pat in topics.items():
    hits = text.str.contains(pat)
    print(f"{name:9s} mentioned in {hits.sum():3d} reviews | avg stars {rv.loc[hits, 'stars'].mean():.2f}")
delivery mentioned in 60 reviews | avg stars 3.12 quality mentioned in 113 reviews | avg stars 3.32 size mentioned in 24 reviews | avg stars 1.62 refund mentioned in 27 reviews | avg stars 1.48
Python
import pandas as pd
s = pd.Series(["Order #4521 delivered in 3 days", "Refund of Rs 1,299 for order #4610", "Call 98765-43210 for help"])
print(s.str.extract(r"#(\d+)"))
print(s.str.findall(r"\d+").tolist())
print(s.str.startswith("Order").tolist())
0 0 4521 1 4610 2 NaN [['4521', '3'], ['1', '299', '4610'], ['98765', '43210']] [True, False, False]
💼 Business action

Reviews about size and refunds average under 2 stars – far worse than delivery (about 3.1). So the first fix is a better size chart and a faster refund process, not a new courier. Text analysis turns 600 reviews into a priority list in seconds.

🏅 Job skills unlocked today

✔ Extract calendar features with .dt✔ Calculate durations and deadlines✔ Resample and smooth time series✔ Clean and search text with .str and regex

Practice tasks

🏋️ Practice – do it yourself

Task 1: Find the average temperature of each month (Jan–Dec) across all three years in Delhi weather data.
Show solution
Python
import pandas as pd
w = pd.read_csv("delhi_weather.csv", parse_dates=["date"])
print(w.groupby(w["date"].dt.month)["avg_temp_c"].mean().round(1).to_string())
date 1 16.8 2 17.8 3 21.1 4 26.5 5 31.1 6 34.6 7 35.8 8 34.0 9 31.0 10 25.9 11 21.6 12 18.2
Task 2: Count orders per hour? Our data has no time – instead count weekend vs weekday orders per category.
Show solution
Python
import pandas as pd
s = pd.read_csv("sales_data.csv", parse_dates=["order_date"])
s["day_type"] = s["order_date"].dt.dayofweek.map(lambda d: "Weekend" if d >= 5 else "Weekday")
print(pd.crosstab(s["category"], s["day_type"]))
day_type Weekday Weekend category Books & Stationery 149 73 Electronics 285 154 Fashion 312 174 Grocery 329 199 Home & Kitchen 211 114
Task 3: List the 10 most common words in negative reviews (ignore words shorter than 4 letters).
Show solution
Python
import pandas as pd
rv = pd.read_csv("product_reviews.csv")
words = rv.loc[rv["sentiment"] == "negative", "review"].str.lower().str.findall(r"[a-z]{4,}").explode()
print(words.value_counts().head(10))
review very 92 never 74 happy 55 again 53 star 44 disappointed 41 money 31 waste 31 sound 29 cracks 29 Name: count, dtype: int64

Quick quiz

🧠 Quick Quiz – test yourself

1. Which gives the weekday name?
.dt.day is the day of the month (1–31).
2. df.resample("ME") requires…
resample groups by time periods.
3. rolling(7).mean() computes…
A moving average – the first 6 values are NaN.
4. s.str.contains("late|deliver") matches rows containing…
| means OR in a regular expression.
5. (date2 - date1).dt.days returns…
Subtracting dates gives a Timedelta.

Interview corner

💼 Interview Corner

How would you find seasonality in daily sales?

Convert the date column, set it as index, resample to weekly/monthly totals, plot with a rolling mean, and compare the same month across years or group by month/weekday. Later, decomposition (Day 49) separates trend and seasonality formally.

Why use vectorised .str methods instead of a Python loop?

They are shorter, handle NaN safely and are usually faster. A loop over rows with if-statements is harder to read and easy to break.

Summary

  • parse_dates / to_datetime → use .dt.month, .dt.day_name(), .dt.quarter.
  • Date minus date = Timedelta; DateOffset adds months/years.
  • resample("ME") for periods, rolling(n) for moving averages.
  • .str.lower/strip/replace/contains/extract for text, with regex.
➡️ Next

Day 17: create new features with apply, map, np.where, cut and qcut – turning raw columns into business signals.

Frequently Asked Questions

My dates read as text. Why?
read_csv does not guess dates. Use parse_dates=["col"] or pd.to_datetime(df.col, format=...).
What about Indian dates like 05/03/2024?
Pass format="%d/%m/%Y" (or dayfirst=True) – otherwise it may be read as May 3.
← Data Science (60 Days)
🔗

Share this topic with a friend

यह topic किसी दोस्त को भेजें

Found it useful? Send it to a classmate learning the same thing.

अच्छा लगा? जो दोस्त यही सीख रहा है, उसे भेज दीजिए।

Next topicDay 17: apply, map, Binning & New Features Your progress: 16 / 60 (27%) · Lesson 17 / 60 Continue →

How was this lesson?

Your feedback helps us make the content better.

Write a review or suggestion (optional)

After approval, your name and city may appear publicly with your review. Please do not write your email or phone number.

▶ CodingEasily on YouTube

Learn with video lessons in easy Hindi

Featured video: RDBMS Part 3 – Class XI Commerce IT

▶ Subscribe – it’s free