|$ curl https://forge-ai.dev/api/markdown?path=docs/python/data-science
$cat docs/python-—-data-science.md
updated Last week·28 min read·published

Python — Data Science

PythonIntermediate🎯Free Tools
Introduction

Python is the dominant language for data science thanks to three core libraries: NumPy for numerical computation, Pandas for data manipulation, and Matplotlib for visualization. Together they form the foundation of nearly every data workflow.

The typical data science workflow is: load data, clean and transform it, explore patterns with statistics and plots, build models, and communicate results. Jupyter notebooks provide an interactive environment for each step.

NumPy Arrays

NumPy provides the ndarray, a fast, fixed-type multidimensional array. Vectorized operations on NumPy arrays are 10-100x faster than equivalent Python loops because they run in compiled C code.

numpy_basics.py
Python
1import numpy as np
2
3# Creating arrays
4a = np.array([1, 2, 3, 4, 5]) # from list
5b = np.zeros((3, 4)) # 3x4 zeros
6c = np.ones((2, 3, 4)) # 3D ones
7d = np.arange(0, 10, 0.5) # like range() but float
8e = np.linspace(0, 1, 100) # 100 evenly spaced [0,1]
9f = np.random.randn(3, 4) # 3x4 normal distribution
10
11# Shape and dtype
12print(a.shape) # (5,)
13print(f.shape) # (3, 4)
14print(a.dtype) # int64
15print(b.dtype) # float64
16
17# Reshaping
18matrix = np.arange(12).reshape(3, 4)
19print(matrix)
20# [[ 0 1 2 3]
21# [ 4 5 6 7]
22# [ 8 9 10 11]]
23
24# Indexing and slicing
25print(matrix[0, :]) # first row → [0 1 2 3]
26print(matrix[:, 2]) # third column → [2 6 10]
27print(matrix[1:3, 1:3]) # submatrix → [[5 6] [9 10]]
numpy_ops.py
Python
1# Vectorized operations — no loops needed
2a = np.array([1, 2, 3, 4])
3b = np.array([10, 20, 30, 40])
4
5print(a + b) # [11 22 33 44]
6print(a * b) # [10 40 90 160]
7print(a ** 2) # [1 4 9 16]
8print(np.sqrt(a)) # [1.0 1.414 1.732 2.0]
9
10# Aggregations
11data = np.random.randn(1000)
12print(np.mean(data)) # ~0.0
13print(np.std(data)) # ~1.0
14print(np.median(data)) # ~0.0
15print(np.percentile(data, [25, 50, 75])) # quartiles
16
17# Broadcasting — operations between different shapes
18matrix = np.arange(12).reshape(3, 4)
19row = np.array([1, 0, 1, 0])
20print(matrix + row) # adds row to each row of matrix
21
22# Boolean indexing
23data = np.array([1, 5, 3, 8, 2, 9, 4])
24mask = data > 4
25print(data[mask]) # [5 8 9]
26print(np.sum(mask)) # 3 elements > 4
27
28# Linear algebra
29A = np.array([[1, 2], [3, 4]])
30B = np.array([[5, 6], [7, 8]])
31print(A @ B) # matrix multiply
32print(np.linalg.inv(A)) # inverse
33print(np.linalg.det(A)) # determinant

info

Always prefer vectorized NumPy operations over Python loops. If you find yourself writing a for-loop over array elements, there is almost certainly a NumPy function that does it faster.
Pandas DataFrames

Pandas builds on NumPy to provide labeled, heterogeneous tabular data via DataFrame and Series. It is the primary tool for data cleaning, transformation, and exploration.

pandas_basics.py
Python
1import pandas as pd
2
3# Creating DataFrames
4df = pd.DataFrame({
5 "name": ["Alice", "Bob", "Charlie", "Diana"],
6 "age": [28, 35, 42, 31],
7 "city": ["NYC", "SF", "NYC", "LA"],
8 "salary": [85000, 120000, 95000, 110000],
9})
10
11# From CSV
12# df = pd.read_csv("data.csv")
13# From JSON
14# df = pd.read_json("data.json")
15# From Excel
16# df = pd.read_excel("data.xlsx")
17
18# Basic inspection
19print(df.shape) # (4, 4)
20print(df.head(2)) # first 2 rows
21print(df.dtypes) # column types
22print(df.describe()) # summary statistics
23print(df.info()) # non-null counts and types
pandas_select.py
Python
1# Selection and filtering
2print(df["name"]) # Series
3print(df[["name", "age"]]) # DataFrame subset
4
5# loc — label-based
6print(df.loc[0:2, "name":"city"]) # rows 0-2, name through city
7
8# iloc — integer position
9print(df.iloc[0:2, 0:3]) # first 2 rows, first 3 columns
10
11# Boolean filtering
12seniors = df[df["age"] > 35]
13nyc = df[df["city"] == "NYC"]
14complex_filter = df[(df["age"] > 30) & (df["salary"] > 100000)]
15
16# Query syntax
17result = df.query("age > 30 and city == 'NYC'")
18
19# Adding columns
20df["bonus"] = df["salary"] * 0.1
21df["senior"] = df["age"] > 35
22
23# apply — row or column-wise operations
24df["name_upper"] = df["name"].str.upper()
25df["age_group"] = df["age"].apply(lambda x: "senior" if x > 35 else "junior")
pandas_group.py
Python
1# Grouping and aggregation
2city_stats = df.groupby("city").agg(
3 avg_age=("age", "mean"),
4 avg_salary=("salary", "mean"),
5 count=("name", "count"),
6).reset_index()
7print(city_stats)
8# city avg_age avg_salary count
9# 0 LA 31.0 110000.0 1
10# 1 NYC 35.0 90000.0 2
11# 2 SF 35.0 120000.0 1
12
13# Multiple groupby columns
14# df.groupby(["city", "senior"]).agg(...)
15
16# Sorting
17print(df.sort_values("salary", ascending=False))
18print(df.sort_values(["city", "salary"], ascending=[True, False]))
19
20# Merging
21employees = pd.DataFrame({
22 "name": ["Alice", "Bob"],
23 "dept": ["Engineering", "Marketing"],
24})
25merged = pd.merge(df, employees, on="name", how="left")
26
27# Pivot tables
28pivot = df.pivot_table(
29 values="salary",
30 index="city",
31 aggfunc=["mean", "count"],
32)
Data Cleaning
cleaning.py
Python
1import pandas as pd
2import numpy as np
3
4# Load messy data
5df = pd.read_csv("sales.csv")
6
7# Check for missing values
8print(df.isnull().sum())
9
10# Drop rows with missing values
11df_clean = df.dropna(subset=["revenue", "date"])
12
13# Fill missing values
14df["category"] = df["category"].fillna("Unknown")
15df["price"] = df["price"].fillna(df["price"].median())
16
17# Remove duplicates
18df = df.drop_duplicates(subset=["order_id"])
19
20# Fix data types
21df["date"] = pd.to_datetime(df["date"])
22df["price"] = pd.to_numeric(df["price"], errors="coerce")
23
24# String cleanup
25df["product"] = df["product"].str.strip().str.lower()
26
27# Outlier detection with IQR
28Q1 = df["price"].quantile(0.25)
29Q3 = df["price"].quantile(0.75)
30IQR = Q3 - Q1
31lower = Q1 - 1.5 * IQR
32upper = Q3 + 1.5 * IQR
33df = df[(df["price"] >= lower) & (df["price"] <= upper)]
34
35# Rename columns
36df = df.rename(columns={"price": "unit_price", "qty": "quantity"})
37
38# Replace values
39df["status"] = df["status"].replace({
40 "cancelled": "canceled",
41 "shipped": "completed",
42})

best practice

Always inspect your data before cleaning. Use df.info(), df.describe(), and df.isnull().sum() to understand what you are working with before making changes.
Matplotlib Plotting
plotting.py
Python
1import matplotlib.pyplot as plt
2import numpy as np
3
4# Line plot
5x = np.linspace(0, 10, 100)
6plt.figure(figsize=(10, 6))
7plt.plot(x, np.sin(x), label="sin(x)", color="#3776AB")
8plt.plot(x, np.cos(x), label="cos(x)", color="#FF6B35")
9plt.title("Trigonometric Functions")
10plt.xlabel("x")
11plt.ylabel("y")
12plt.legend()
13plt.grid(True, alpha=0.3)
14plt.savefig("trig_plot.png", dpi=150, bbox_inches="tight")
15plt.close()
16
17# Bar chart
18categories = ["A", "B", "C", "D"]
19values = [23, 45, 56, 78]
20plt.figure(figsize=(8, 5))
21plt.bar(categories, values, color="#3776AB")
22plt.title("Category Values")
23plt.savefig("bar_chart.png")
24plt.close()
25
26# Histogram
27data = np.random.randn(1000)
28plt.figure(figsize=(8, 5))
29plt.hist(data, bins=30, edgecolor="white", alpha=0.7, color="#3776AB")
30plt.title("Normal Distribution")
31plt.savefig("histogram.png")
32plt.close()
33
34# Scatter plot
35x = np.random.randn(200)
36y = 2 * x + np.random.randn(200) * 0.5
37plt.figure(figsize=(8, 6))
38plt.scatter(x, y, alpha=0.5, c="#3776AB", s=20)
39plt.title("Scatter Plot with Correlation")
40plt.savefig("scatter.png")
41plt.close()
subplots.py
Python
1# Subplots — multiple charts in one figure
2fig, axes = plt.subplots(2, 2, figsize=(12, 10))
3
4# Top-left: line plot
5axes[0, 0].plot(x, np.sin(x), color="#3776AB")
6axes[0, 0].set_title("Sine Wave")
7
8# Top-right: bar chart
9axes[0, 1].bar(["A", "B", "C"], [3, 7, 5], color="#FF6B35")
10axes[0, 1].set_title("Bar Chart")
11
12# Bottom-left: histogram
13axes[1, 0].hist(np.random.randn(500), bins=25, color="#3776AB")
14axes[1, 0].set_title("Distribution")
15
16# Bottom-right: scatter
17axes[1, 1].scatter(np.random.randn(100), np.random.randn(100), alpha=0.6)
18axes[1, 1].set_title("Scatter")
19
20plt.tight_layout()
21plt.savefig("subplots.png", dpi=150)
22plt.close()
23
24# Pandas integration — plot directly from DataFrame
25df.groupby("city")["salary"].mean().plot(
26 kind="bar", title="Average Salary by City", figsize=(8, 5)
27)
28plt.tight_layout()
29plt.savefig("pandas_plot.png")
30plt.close()
Complete Workflow
workflow.py
Python
1# End-to-end data analysis workflow
2import pandas as pd
3import numpy as np
4import matplotlib.pyplot as plt
5
6# 1. Load data
7df = pd.read_csv("sales_2024.csv", parse_dates=["date"])
8
9# 2. Initial exploration
10print(f"Shape: {df.shape}")
11print(f"Columns: {df.columns.tolist()}")
12print(f"Missing:\n{df.isnull().sum()}")
13print(f"Date range: {df['date'].min()} to {df['date'].max()}")
14
15# 3. Clean data
16df = df.dropna(subset=["revenue"])
17df = df[df["revenue"] > 0]
18df["month"] = df["date"].dt.to_period("M")
19
20# 4. Transform and analyze
21monthly = df.groupby("month").agg(
22 total_revenue=("revenue", "sum"),
23 avg_order=("revenue", "mean"),
24 num_orders=("revenue", "count"),
25).reset_index()
26monthly["month_str"] = monthly["month"].astype(str)
27
28# 5. Visualize
29fig, ax1 = plt.subplots(figsize=(12, 6))
30ax1.bar(monthly["month_str"], monthly["total_revenue"], color="#3776AB", alpha=0.7)
31ax1.set_xlabel("Month")
32ax1.set_ylabel("Total Revenue", color="#3776AB")
33ax1.tick_params(axis="y", labelcolor="#3776AB")
34ax1.set_xticklabels(monthly["month_str"], rotation=45)
35
36ax2 = ax1.twinx()
37ax2.plot(monthly["month_str"], monthly["num_orders"], color="#FF6B35", marker="o")
38ax2.set_ylabel("Number of Orders", color="#FF6B35")
39ax2.tick_params(axis="y", labelcolor="#FF6B35")
40
41plt.title("Monthly Revenue and Orders")
42plt.tight_layout()
43plt.savefig("monthly_report.png", dpi=150)
44plt.close()
45
46# 6. Export results
47monthly.to_csv("monthly_summary.csv", index=False)
48print("Report generated: monthly_report.png")

info

In Jupyter notebooks, add %matplotlib inline at the top to display plots directly in the notebook. Use %timeit to benchmark code and %load_ext autoreload to auto-reload changed modules.
$Blueprint — Engineering Documentation·Section ID: PYTHON-DS·Revision: 1.0