Pandas: DataFrame Core

Last updated: 2026-08-26

A DataFrame is the core data structure in Pandas — a labeled 2D table where each column is a Series with its own dtype and name. Think of a DataFrame as an Excel sheet or SQL table in code, but more powerful: programmable, extensible, and version-controllable. This section takes you deep into the essential structure of a DataFrame.

⚠️ Note: The code below requires a local Python environment.

1. What You'll Learn



2. Charlie's E-Commerce Product Table

(1) Pain Point: Managing Multiple Columns Together

Charlie runs an e-commerce website and needs to manage product data: name, category, price, stock, and rating — 5 columns of different types. With Series alone, he would need to maintain 5 separate Series objects and ensure their indexes stay aligned.

PYTHON
import pandas as pd

# 5 separate Series — must keep index aligned manually
names = pd.Series(['Laptop', 'Phone', 'Tablet', 'Monitor', 'Keyboard'])
categories = pd.Series(['Electronics', 'Electronics', 'Electronics', 'Electronics', 'Accessories'])
prices = pd.Series([999.99, 699.99, 349.99, 449.99, 79.99])
stocks = pd.Series([50, 120, 80, 35, 200])
ratings = pd.Series([4.7, 4.5, 4.3, 4.6, 4.2])
# Which price goes with which product? Hope the index stays aligned!
TEXT 📖 Display only
> **Output:** Run this in a local Python environment (pandas 2.x). The Piston server does not have pandas pre-installed — install it locally (`pip install pandas`) to follow along. Actual values may vary slightly depending on your pandas version.

(2) Solution: DataFrame Binds Columns Together

▶ Example: Managing Product Data with a DataFrame (Difficulty ⭐)

TEXT 📖 Display only
> **Output:** Run this in a local Python environment (pandas 2.x). The Piston server does not have pandas pre-installed — install it locally (`pip install pandas`) to follow along. Actual values may vary slightly depending on your pandas version.
PYTHON
import pandas as pd

df = pd.DataFrame({
    'name': ['Laptop', 'Phone', 'Tablet', 'Monitor', 'Keyboard'],
    'category': ['Electronics', 'Electronics', 'Electronics', 'Electronics', 'Accessories'],
    'price': [999.99, 699.99, 349.99, 449.99, 79.99],
    'stock': [50, 120, 80, 35, 200],
    'rating': [4.7, 4.5, 4.3, 4.6, 4.2]
})

print(df)
#        name     category    price  stock  rating
# 0    Laptop  Electronics   999.99     50     4.7
# 1     Phone  Electronics   699.99    120     4.5
# 2    Tablet  Electronics   349.99     80     4.3
# 3   Monitor  Electronics   449.99     35     4.6
# 4  Keyboard  Accessories    79.99    200     4.2

print(df['name'])     # a Series
print(df.loc[0])      # first row as a Series
TEXT 📖 Display only
> **Output:** Run this in a local Python environment (pandas 2.x). The Piston server does not have pandas pre-installed — install it locally (`pip install pandas`) to follow along. Actual values may vary slightly depending on your pandas version.

All 5 columns are bound together in a single DataFrame, with self-descriptive column names and automatic row alignment.

(3) Benefit: A DataFrame Is a "Collection of Columns"

A DataFrame is not a "2D ndarray" — it is an ordered dictionary of Series. Each column is an independent Series with its own dtype, but all columns share the same row Index.



3. The Essential Structure of a DataFrame

(1) Internal Structure Diagram

100%
graph TB
    subgraph DataFrame
        direction TB
        COL["Columns Index<br/>(name, category, price, stock, rating)"]
        ROW["Row Index<br/>(0, 1, 2, 3, 4)"]
        S1["Series: name<br/>dtype: object"]
        S2["Series: category<br/>dtype: object"]
        S3["Series: price<br/>dtype: float64"]
        S4["Series: stock<br/>dtype: int64"]
        S5["Series: rating<br/>dtype: float64"]
    end
    ROW --> S1
    ROW --> S2
    ROW --> S3
    ROW --> S4
    ROW --> S5
    COL --> S1
    COL --> S2
    COL --> S3
    COL --> S4
    COL --> S5
TEXT 📖 Display only
> **Output:** Run this in a local Python environment (pandas 2.x). The Piston server does not have pandas pre-installed — install it locally (`pip install pandas`) to follow along. Actual values may vary slightly depending on your pandas version.
Concept Description Analogy
Row Index Row labels shared by all columns Excel row numbers
Columns Name label for each column Excel column headers
Column Series Each column as an independent Series A single Excel column
values The underlying 2D ndarray Raw data matrix

(2) DataFrame vs 2D ndarray

Feature NumPy 2D ndarray Pandas DataFrame
Type constraint Single global dtype Independent dtype per column
Row labels None (integer positions) Index (customizable)
Column labels None (integer positions) Columns (column names)
Column selection arr[:, 2] df['price']
Row selection arr[0, :] df.loc[0]
Mixed types Not supported Natively supported
Missing values np.nan (float only) NaN / NaT / pd.NA
📌 Key Point: The values property of a DataFrame returns a 2D ndarray, but when you have mixed types it becomes object dtype — performance drops significantly. For pure numeric operations, select numeric columns first, then call .values.



4. Multiple Ways to Create a DataFrame

(1) From a Dictionary (Most Common)

▶ Example: Creating a DataFrame from a Dictionary (Difficulty ⭐)

TEXT 📖 Display only
> **Output:** Run this in a local Python environment (pandas 2.x). The Piston server does not have pandas pre-installed — install it locally (`pip install pandas`) to follow along. Actual values may vary slightly depending on your pandas version.
PYTHON
import pandas as pd

# Dict of lists: keys = column names, values = column data
df = pd.DataFrame({
    'product': ['Coffee', 'Tea', 'Juice', 'Water'],
    'price': [4.50, 3.80, 5.20, 1.50],
    'calories': [5, 2, 120, 0]
})
print(df)
#   product  price  calories
# 0  Coffee   4.50         5
# 1     Tea   3.80         2
# 2    Juice   5.20       120
# 3    Water   1.50         0

# Custom row index
df2 = pd.DataFrame({
    'product': ['Coffee', 'Tea', 'Juice'],
    'price': [4.50, 3.80, 5.20]
}, index=['A001', 'A002', 'A003'])
print(df2.index)  # Index(['A001', 'A002', 'A003'])
TEXT 📖 Display only
> **Output:** Run this in a local Python environment (pandas 2.x). The Piston server does not have pandas pre-installed — install it locally (`pip install pandas`) to follow along. Actual values may vary slightly depending on your pandas version.

(2) From a List of Lists

▶ Example: Creating a DataFrame from a List of Lists (Difficulty ⭐)

TEXT 📖 Display only
> **Output:** Run this in a local Python environment (pandas 2.x). The Piston server does not have pandas pre-installed — install it locally (`pip install pandas`) to follow along. Actual values may vary slightly depending on your pandas version.
PYTHON
import pandas as pd

# List of lists: each inner list = one row
data = [
    ['Coffee', 4.50, 5],
    ['Tea', 3.80, 2],
    ['Juice', 5.20, 120],
    ['Water', 1.50, 0]
]
df = pd.DataFrame(data, columns=['product', 'price', 'calories'])
print(df)
TEXT 📖 Display only
> **Output:** Run this in a local Python environment (pandas 2.x). The Piston server does not have pandas pre-installed — install it locally (`pip install pandas`) to follow along. Actual values may vary slightly depending on your pandas version.

(3) From a List of Dictionaries

▶ Example: Creating a DataFrame from a List of Dictionaries (Difficulty ⭐)

TEXT 📖 Display only
> **Output:** Run this in a local Python environment (pandas 2.x). The Piston server does not have pandas pre-installed — install it locally (`pip install pandas`) to follow along. Actual values may vary slightly depending on your pandas version.
PYTHON
import pandas as pd

# List of dicts: each dict = one row
data = [
    {'product': 'Coffee', 'price': 4.50, 'calories': 5},
    {'product': 'Tea', 'price': 3.80, 'calories': 2},
    {'product': 'Juice', 'price': 5.20, 'calories': 120}
]
df = pd.DataFrame(data)
print(df)
# Missing keys become NaN
data2 = [
    {'product': 'Coffee', 'price': 4.50},
    {'product': 'Tea', 'calories': 2}
]
df2 = pd.DataFrame(data2)
print(df2)
#   product  price  calories
# 0  Coffee   4.50       NaN
# 1     Tea    NaN       2.0
TEXT 📖 Display only
> **Output:** Run this in a local Python environment (pandas 2.x). The Piston server does not have pandas pre-installed — install it locally (`pip install pandas`) to follow along. Actual values may vary slightly depending on your pandas version.

(4) From a NumPy ndarray

▶ Example: Creating a DataFrame from an ndarray (Difficulty ⭐)

TEXT 📖 Display only
> **Output:** Run this in a local Python environment (pandas 2.x). The Piston server does not have pandas pre-installed — install it locally (`pip install pandas`) to follow along. Actual values may vary slightly depending on your pandas version.
PYTHON
import numpy as np
import pandas as pd

arr = np.random.randn(4, 3)  # 4 rows, 3 columns of random numbers
df = pd.DataFrame(arr, columns=['A', 'B', 'C'])
print(df.shape)   # (4, 3)
print(df.dtypes)  # all float64
TEXT 📖 Display only
> **Output:** Run this in a local Python environment (pandas 2.x). The Piston server does not have pandas pre-installed — install it locally (`pip install pandas`) to follow along. Actual values may vary slightly depending on your pandas version.

(5) Comparison of Creation Methods

Method Syntax Characteristics Use Case
Dictionary pd.DataFrame({'col': [data]}) Column-oriented, most natural Most common
List of lists pd.DataFrame([[r1c1, ...], ...]) Row-oriented Building row by row
List of dicts pd.DataFrame([{'col': val, ...}, ...]) Row-oriented, missing keys auto-NaN API/JSON data
ndarray pd.DataFrame(np.array(...)) Homogeneous data Converting NumPy data
read_csv pd.read_csv('file.csv') Load from file Most common in real projects


5. Inspecting and Exploring Data

(1) Quick Preview: head / tail / sample

▶ Example: Previewing a DataFrame (Difficulty ⭐)

TEXT 📖 Display only
> **Output:** Run this in a local Python environment (pandas 2.x). The Piston server does not have pandas pre-installed — install it locally (`pip install pandas`) to follow along. Actual values may vary slightly depending on your pandas version.
PYTHON
import pandas as pd

df = pd.DataFrame({
    'name': ['Laptop', 'Phone', 'Tablet', 'Monitor', 'Keyboard',
             'Mouse', 'Headset', 'Speaker', 'Camera', 'Charger'],
    'price': [999.99, 699.99, 349.99, 449.99, 79.99,
              29.99, 149.99, 89.99, 599.99, 19.99],
    'stock': [50, 120, 80, 35, 200, 300, 150, 180, 25, 500]
})

print(df.head())      # first 5 rows
print(df.head(3))     # first 3 rows
print(df.tail(2))     # last 2 rows
print(df.sample(3))   # random 3 rows (for inspection)
TEXT 📖 Display only
> **Output:** Run this in a local Python environment (pandas 2.x). The Piston server does not have pandas pre-installed — install it locally (`pip install pandas`) to follow along. Actual values may vary slightly depending on your pandas version.

(2) Data Overview: info

▶ Example: The info Method in Detail (Difficulty ⭐⭐)

TEXT 📖 Display only
> **Output:** Run this in a local Python environment (pandas 2.x). The Piston server does not have pandas pre-installed — install it locally (`pip install pandas`) to follow along. Actual values may vary slightly depending on your pandas version.
PYTHON
import pandas as pd
import numpy as np

df = pd.DataFrame({
    'name': ['Alice', 'Bob', 'Charlie', 'Carol', 'David'],
    'age': [28, 34, 25, 30, 45],
    'salary': [75000.0, 92000.0, np.nan, 88000.0, 105000.0],
    'department': ['Sales', 'Engineering', 'Marketing', 'Sales', 'Management']
})

df.info()
# <class 'pandas.core.frame.DataFrame'>
# RangeIndex: 5 entries, 0 to 4
# Data columns (total 4 columns):
#  #   Column      Non-Null Count  Dtype
# ---  ------      --------------  -----
#  0   name        5 non-null      object
#  1   age         5 non-null      int64
#  2   salary      4 non-null      float64  ← 1 missing value!
#  3   department  5 non-null      object
# dtypes: float64(1), int64(1), object(2)
# memory usage: 288.0+ bytes
TEXT 📖 Display only
> **Output:** Run this in a local Python environment (pandas 2.x). The Piston server does not have pandas pre-installed — install it locally (`pip install pandas`) to follow along. Actual values may vary slightly depending on your pandas version.

info() is the first step in data analysis — it tells you: how many rows there are, the dtype of each column, whether there are missing values, and memory usage.

(3) Statistical Summary: describe

▶ Example: Statistical Summary with describe (Difficulty ⭐)

TEXT 📖 Display only
> **Output:** Run this in a local Python environment (pandas 2.x). The Piston server does not have pandas pre-installed — install it locally (`pip install pandas`) to follow along. Actual values may vary slightly depending on your pandas version.
PYTHON
import pandas as pd

df = pd.DataFrame({
    'price': [999.99, 699.99, 349.99, 449.99, 79.99],
    'stock': [50, 120, 80, 35, 200],
    'rating': [4.7, 4.5, 4.3, 4.6, 4.2]
})

# Numeric columns only (default)
print(df.describe())
#           price    stock   rating
# count     5.00     5.00     5.00
# mean    515.79    97.00     4.46
# std     347.31    69.72     0.21
# min      79.99    35.00     4.20
# 25%     349.99    50.00     4.30
# 50%     449.99    80.00     4.50
# 75%     699.99   120.00     4.60
# max     999.99   200.00     4.70

# Include all columns
print(df.describe(include='all'))
TEXT 📖 Display only
> **Output:** Run this in a local Python environment (pandas 2.x). The Piston server does not have pandas pre-installed — install it locally (`pip install pandas`) to follow along. Actual values may vary slightly depending on your pandas version.
Method What It Shows Use Case
df.head() First 5 rows Quick look at data format
df.info() Row count / column dtypes / missing values / memory Must-check first step
df.describe() Statistical summary of numeric columns Understanding distribution
df.shape (rows, columns) Data dimensions
df.dtypes Dtype of each column Type checking


6. Core DataFrame Properties

(1) Property Quick Reference

Property Return Type Description Example
df.shape tuple (rows, columns) (5, 4)
df.index Index Row labels RangeIndex(0, 5)
df.columns Index Column names Index(['name', 'age', ...])
df.dtypes Series Dtype of each column name: object, age: int64
df.values ndarray Underlying data 2D array
df.ndim int Number of dimensions 2
df.size int Total number of elements 20 (5 rows x 4 cols)
df.T DataFrame Transpose Rows and columns swapped

▶ Example: Core Properties at a Glance (Difficulty ⭐)

TEXT 📖 Display only
> **Output:** Run this in a local Python environment (pandas 2.x). The Piston server does not have pandas pre-installed — install it locally (`pip install pandas`) to follow along. Actual values may vary slightly depending on your pandas version.
PYTHON
import pandas as pd

df = pd.DataFrame({
    'name': ['Alice', 'Bob', 'Charlie'],
    'age': [28, 34, 25],
    'salary': [75000.0, 92000.0, 68000.0]
})

print(f"Shape:    {df.shape}")      # (3, 3)
print(f"Index:    {df.index}")      # RangeIndex(0, 3)
print(f"Columns:  {df.columns}")    # Index(['name', 'age', 'salary'])
print(f"Dtypes:\n{df.dtypes}")
print(f"Size:     {df.size}")       # 9
print(f"Ndim:     {df.ndim}")       # 2
TEXT 📖 Display only
> **Output:** Run this in a local Python environment (pandas 2.x). The Piston server does not have pandas pre-installed — install it locally (`pip install pandas`) to follow along. Actual values may vary slightly depending on your pandas version.

(2) Column Selection and Addition

▶ Example: Column Operations (Difficulty ⭐)

TEXT 📖 Display only
> **Output:** Run this in a local Python environment (pandas 2.x). The Piston server does not have pandas pre-installed — install it locally (`pip install pandas`) to follow along. Actual values may vary slightly depending on your pandas version.
PYTHON
import pandas as pd

df = pd.DataFrame({
    'name': ['Alice', 'Bob', 'Charlie'],
    'age': [28, 34, 25],
    'salary': [75000.0, 92000.0, 68000.0]
})

# Select single column → Series
print(type(df['name']))   # <class 'pandas.core.series.Series'>

# Select multiple columns → DataFrame
print(df[['name', 'salary']])

# Add new column
df['bonus'] = df['salary'] * 0.1
df['level'] = df['age'].apply(lambda x: 'Senior' if x >= 30 else 'Junior')
print(df)
TEXT 📖 Display only
> **Output:** Run this in a local Python environment (pandas 2.x). The Piston server does not have pandas pre-installed — install it locally (`pip install pandas`) to follow along. Actual values may vary slightly depending on your pandas version.

(3) Transpose

▶ Example: Transposing a DataFrame (Difficulty ⭐)

TEXT 📖 Display only
> **Output:** Run this in a local Python environment (pandas 2.x). The Piston server does not have pandas pre-installed — install it locally (`pip install pandas`) to follow along. Actual values may vary slightly depending on your pandas version.
PYTHON
import pandas as pd

df = pd.DataFrame({
    'Q1': [320, 280, 350],
    'Q2': [410, 390, 420]
}, index=['Product A', 'Product B', 'Product C'])

print(df.T)
#              Product A  Product B  Product C
# Q1          320        280        350
# Q2          410        390        420
TEXT 📖 Display only
> **Output:** Run this in a local Python environment (pandas 2.x). The Piston server does not have pandas pre-installed — install it locally (`pip install pandas`) to follow along. Actual values may vary slightly depending on your pandas version.


7. Complete Example: E-Commerce Product Table End-to-End

▶ Example: Product Data Creation and Exploration (Difficulty ⭐⭐⭐)

TEXT 📖 Display only
> **Output:** Run this in a local Python environment (pandas 2.x). The Piston server does not have pandas pre-installed — install it locally (`pip install pandas`) to follow along. Actual values may vary slightly depending on your pandas version.
PYTHON
import pandas as pd
import numpy as np

# ============================================
# Comprehensive example: E-commerce product
# table creation and exploration
# ============================================

# 1. Create DataFrame
products = pd.DataFrame({
    'name': ['Laptop', 'Phone', 'Tablet', 'Monitor', 'Keyboard',
             'Mouse', 'Headset', 'Speaker'],
    'category': ['Electronics', 'Electronics', 'Electronics',
                 'Electronics', 'Accessories', 'Accessories',
                 'Accessories', 'Accessories'],
    'price': [999.99, 699.99, 349.99, 449.99, 79.99,
              29.99, 149.99, 89.99],
    'stock': [50, 120, 80, 35, 200, 300, 150, 180],
    'rating': [4.7, 4.5, 4.3, 4.6, 4.2, 4.0, 4.4, 4.1]
})

# 2. Overview
print("=== Product Catalog Overview ===")
print(f"Products: {len(products)}")
print(f"Categories: {products['category'].unique().tolist()}")
print(f"Columns: {products.columns.tolist()}")

# 3. Data types and memory
print(f"\n=== Data Types ===")
print(products.dtypes)
print(f"\nMemory usage: {products.memory_usage(deep=True).sum() / 1024:.1f} KB")

# 4. Quick statistics
print(f"\n=== Price Statistics ===")
print(products['price'].describe())

# 5. Inventory value per product
products['inventory_value'] = products['price'] * products['stock']
print(f"\n=== Top 3 by Inventory Value ===")
print(products.nlargest(3, 'inventory_value')[['name', 'inventory_value']])

# 6. Category breakdown
print(f"\n=== Category Summary ===")
cat_summary = products.groupby('category').agg(
    count=('name', 'count'),
    avg_price=('price', 'mean'),
    total_stock=('stock', 'sum')
)
print(cat_summary)
TEXT 📖 Display only
> **Output:** Run this in a local Python environment (pandas 2.x). The Piston server does not have pandas pre-installed — install it locally (`pip install pandas`) to follow along. Actual values may vary slightly depending on your pandas version.

Expected output (excerpt):

TEXT 📖 Display only
=== Product Catalog Overview ===
Products: 8
Categories: ['Electronics', 'Accessories']
Columns: ['name', 'category', 'price', 'stock', 'rating']

=== Price Statistics ===
count       8.00
mean      349.99
std       339.32
min        29.99
max       999.99

=== Top 3 by Inventory Value ===
      name  inventory_value
0   Laptop         49999.50
1    Phone         83998.80
3  Monitor         15749.65

=== Category Summary ===
              count  avg_price  total_stock
category
Accessories       4      87.24          830
Electronics       4     624.99          285

❓ FAQ

Q What is the relationship between DataFrame and Series?
A A DataFrame is an ordered collection of Series — each column is a Series, and all columns share the same row Index. Selecting a single column returns a Series; selecting multiple columns returns a DataFrame. Selecting a single row also returns a Series (with column names as the Index).
Q Can columns be accessed by numeric index?
A Yes. If column names are integers (e.g., 0, 1, 2), using df[0] is ambiguous — Pandas treats it as a column name, not a position. In that case, use df.iloc[:, 0] for positional access or df.loc[:, 0] for label-based access. It is best to use string column names to avoid confusion.
Q What is the difference between info and describe?
A info shows structural information (row count / column dtypes / missing values / memory), while describe shows a statistical summary (mean / std / quartiles / min-max). info answers "what does the data look like," and describe answers "how are the values distributed." They complement each other — check both when you first encounter a dataset.
Q How do I add or remove columns?
A To add a column, use df['new_col'] = values (appended at the end) or df.insert(pos, 'new_col', values) (at a specific position). To remove a column, use df.drop('col', axis=1) or del df['col']. drop returns a new DataFrame (the original is unchanged), while del modifies in place.
Q What does values return?
A df.values returns the underlying 2D NumPy ndarray. If the DataFrame has mixed types (e.g., object + int64), the ndarray dtype is upcast to object, losing vectorized performance. For purely numeric DataFrames, values retains the numeric dtype.
Q How do I transpose a DataFrame?
A Use df.T or df.transpose(). After transposing, rows become columns and columns become rows. Note: if the original DataFrame has mixed types, all columns become object dtype after transposition (because ndarray requires homogeneous types).
Q Should I use a dictionary or a list to create a DataFrame?
A A dictionary is the most natural approach (keys = column names, values = column data) and is recommended for everyday use. A list of dictionaries suits row-by-row construction (e.g., JSON data from an API). An ndarray suits purely numeric data. In real projects, 80% of the time you will use pd.read_csv() to load from a file.

📖 Summary


📝 Exercises

  1. Basic (Difficulty ⭐): Create a student table (name / math / english / science) using 3 different methods, then print the info and describe results.
  2. Intermediate (Difficulty ⭐⭐): Create an employee table with missing values (name / age / salary / department, where salary has 2 NaN entries), then: use info to check for missing values → calculate the non-null ratio for each column → add a salary_level column (salary > 80000 is "High", otherwise "Low", NaN is "Unknown").
  3. Challenge (Difficulty ⭐⭐⭐): Build a DataFrame from a list of dictionaries (5 records, some keys missing), then: check for missing values → fill with column mean/mode → count non-null fields per row → add a completeness column (non-null ratio), and finally output a full describe report.

← Previous: Introduction to Series · Next: The Index System →

Web-Tutorial.com

Web-Tutorial Tech Team

A team of developers maintaining programming tutorials. Each tutorial is written and reviewed by developers with expertise in that field. We work to keep our content accurate and reliable — if you spot an issue, please let us know.

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏