Pandas: Getting Started with Series

Last updated: 2026-08-26

A Series is the most fundamental data structure in Pandas — think of it as a "labeled one-dimensional array". A Series is made of two parts: data (a NumPy ndarray) and labels (an Index). It is the Index that lifts a Series beyond an ordinary array and gives each value a "name". This section starts from what a Series really is and walks you through creating, operating on, and using its most common methods.

⚠️ Note: The code below must be run in a local Python environment.

1. What You'll Learn



2. Alice's Coffee Shop Sales Diary

(1) The Pain: Numbers Without Names

Alice runs a coffee shop. She used NumPy to record her daily sales for a week:

PYTHON
import numpy as np

sales = np.array([320, 280, 350, 410, 390, 520, 480])
# What day is 520? Position 5... but which day?
print(sales[5])  # 520 — but what does this number mean?
TEXT 📖 Display only
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.

Is 520 Friday or Saturday? sales[5] doesn't tell you. You have to maintain a separate "position → weekday" lookup table.

(2) The Solution: Series Makes Data Self-Describing

▶ Example: Labeled Sales with Series (Difficulty ⭐)

TEXT 📖 Display only
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

sales = pd.Series(
    [320, 280, 350, 410, 390, 520, 480],
    index=['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
    name='daily_sales'
)
print(sales)
# Mon    320
# Tue    280
# Wed    350
# Thu    410
# Fri    390
# Sat    520
# Sun    480
# Name: daily_sales, dtype: int64

print(sales['Sat'])  # 520 — label-based access
print(sales.iloc[5])  # 520 — position-based access
TEXT 📖 Display only
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.

A Series binds data and labels together — sales['Sat'] is far more self-explanatory than sales[5].

(3) The Payoff: The Index Is the Data's Name Tag

With Index labels, data becomes self-describing:



3. The Internal Structure of a Series

(1) Two Components: values + index

100%
graph LR
    A[Series] --> B[values: NumPy ndarray]
    A --> C[index: Index object]
    B --> D[320, 280, 350, ...]
    C --> E["Mon, Tue, Wed, ..."]
TEXT 📖 Display only
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.
Property Type Description
s.values np.ndarray The underlying data array
s.index pd.Index The row labels
s.name str The Series name
s.dtype np.dtype The element data type
s.shape tuple The shape (one-dimensional, e.g. (7,))
s.size int The number of elements

▶ Example: Inspecting Series Properties (Difficulty ⭐)

TEXT 📖 Display only
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

s = pd.Series([320, 280, 350], index=['Mon', 'Tue', 'Wed'])

print(f"Type of values: {type(s.values)}")  # <class 'numpy.ndarray'>
print(f"Type of index:  {type(s.index)}")   # <class 'pandas.core.indexes.base.Index'>
print(f"dtype: {s.dtype}")   # int64
print(f"shape: {s.shape}")   # (3,)
print(f"size:  {s.size}")    # 3
print(f"name:  {s.name}")    # None
TEXT 📖 Display only
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) Series vs ndarray Comparison

Feature NumPy ndarray Pandas Series
Labels None (position only) Yes (Index)
Mixed types Not supported Not recommended but possible (object)
Missing values np.nan (float only) NaN / pd.NA (full coverage)
Operation alignment By position By label
Name None name property
Common statistics np.mean etc. Method chain like .mean()
Under the hood ndarray ndarray + Index
📌 Key point: A Series is essentially "ndarray + Index + name". When you only use .values, it degrades into a plain ndarray.



4. Multiple Ways to Create a Series

(1) From a List

▶ Example: Creating a Series from a List (Difficulty ⭐)

TEXT 📖 Display only
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

# Default index: 0, 1, 2, ...
s1 = pd.Series([10, 20, 30, 40])
print(s1)
# 0    10
# 1    20
# 2    30
# 3    40

# Custom index
s2 = pd.Series([10, 20, 30, 40], index=['a', 'b', 'c', 'd'])
print(s2['b'])  # 20

# With name
s3 = pd.Series([10, 20, 30], name='scores')
print(s3.name)  # scores
TEXT 📖 Display only
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 Dictionary

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

TEXT 📖 Display only
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

# Keys become index, values become data
population = pd.Series({
    'Tokyo': 13960000,
    'New York': 8336000,
    'London': 8982000,
    'Paris': 2161000
})
print(population)
# Tokyo      13960000
# New York    8336000
# London      8982000
# Paris       2161000

print(population['London'])  # 8982000
TEXT 📖 Display only
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.

The advantage of creating from a dictionary: keys automatically become the Index, with no need to specify it manually.

(3) From a NumPy ndarray

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

TEXT 📖 Display only
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.array([3.14, 2.72, 1.41, 1.73])
s = pd.Series(arr, index=['pi', 'e', 'sqrt2', 'sqrt3'])
print(s)
# pi      3.14
# e       2.72
# sqrt2   1.41
# sqrt3   1.73
print(f"Underlying type: {type(s.values)}")  # numpy.ndarray
TEXT 📖 Display only
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 Scalar (Broadcasting)

▶ Example: Creating a Series by Broadcasting a Scalar (Difficulty ⭐)

TEXT 📖 Display only
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

# Broadcast scalar to fill all index positions
s = pd.Series(0, index=['A', 'B', 'C', 'D'])
print(s)
# A    0
# B    0
# C    0
# D    0
TEXT 📖 Display only
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 Index Source Use Case
List pd.Series([1,2,3]) Default RangeIndex Quick testing
List + index pd.Series([1,2,3], index=...) Manually specified When you need custom labels
Dictionary pd.Series({'a':1, 'b':2}) Dictionary keys Label-value pairs
ndarray pd.Series(np.array(...)) Default or specified Converting NumPy data
Scalar pd.Series(0, index=...) Manually specified Initialization / filling


5. Accessing a Series

(1) Label Access vs Position Access

▶ Example: Two Ways to Access (Difficulty ⭐⭐)

TEXT 📖 Display only
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

s = pd.Series([320, 280, 350, 410],
              index=['Mon', 'Tue', 'Wed', 'Thu'])

# Label-based access (preferred)
print(s['Tue'])       # 280
print(s.loc['Tue'])   # 280 — explicit label access

# Position-based access
print(s.iloc[1])      # 280 — explicit position access

# Slice by label (INCLUDES endpoint)
print(s['Mon':'Wed'])
# Mon    320
# Tue    280
# Wed    350

# Slice by position (EXCLUDES endpoint, like Python)
print(s.iloc[0:3])
# Mon    320
# Tue    280
# Wed    350
TEXT 📖 Display only
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.
🔥 Common pitfall: Label slicing includes the endpoint ('Mon':'Wed' includes Wed), while position slicing excludes the endpoint (iloc[0:3] does not include position 3). This is the most common point of confusion for Pandas beginners.

(2) Comparison of Access Methods

Method Syntax Endpoint Recommended For
s[label] Shorthand A single label
s.loc[label] Explicit label Includes endpoint Making intent clear
s.iloc[pos] Explicit position Excludes endpoint Indexing by position
s[[l1,l2]] List selection Multiple labels


6. Operations on a Series

(1) Vectorized Operations

▶ Example: Vectorized Operations on a Series (Difficulty ⭐)

TEXT 📖 Display only
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

sales = pd.Series([320, 280, 350, 410],
                  index=['Mon', 'Tue', 'Wed', 'Thu'])

# Arithmetic operations
print(sales * 1.1)      # 10% price increase
# Mon    352.0
# Tue    308.0
# Wed    385.0
# Thu    451.0

# Comparison operations
print(sales > 300)
# Mon     True
# Tue    False
# Wed     True
# Thu     True

# Filter with boolean
print(sales[sales > 300])
# Mon    320
# Wed    350
# Thu    410
TEXT 📖 Display only
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) Index-Aligned Operations

This is one of the most important features of a Series: operations align by Index, not by position.

▶ Example: Index-Aligned Operations (Difficulty ⭐⭐)

TEXT 📖 Display only
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

week1 = pd.Series({'Mon': 320, 'Tue': 280, 'Wed': 350})
week2 = pd.Series({'Tue': 310, 'Wed': 370, 'Thu': 400})

# Auto-align by index, non-matching → NaN
total = week1 + week2
print(total)
# Mon      NaN   # only in week1
# Tue    590.0   # 280 + 310
# Wed    720.0   # 350 + 370
# Thu      NaN   # only in week2

# Fill missing with 0 instead of NaN
total_filled = week1.add(week2, fill_value=0)
print(total_filled)
# Mon    320.0
# Tue    590.0
# Wed    720.0
# Thu    400.0
TEXT 📖 Display only
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.
💡 Tip: When two Series don't have identical Index values, Pandas aligns them automatically — matching labels are computed, and non-matching ones are filled with NaN. This avoids subtle "misaligned position" bugs. Methods like .add(fill_value=0) can replace the + operator to specify a fill strategy for missing values.



7. Common Series Methods

(1) Statistics and Description

Method Description NumPy Equivalent
s.mean() Mean np.mean(arr)
s.median() Median np.median(arr)
s.std() Standard deviation np.std(arr)
s.min() / s.max() Min / max np.min() / np.max()
s.sum() Sum np.sum(arr)
s.describe() Statistical summary None
s.value_counts() Frequency counts None
s.unique() Unique values np.unique(arr)

▶ Example: Statistical Methods (Difficulty ⭐)

TEXT 📖 Display only
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

scores = pd.Series([85, 92, 78, 95, 88, 92, 78, 85, 90, 92],
                   name='exam_score')

print(scores.describe())
# count    10.000000
# mean     87.500000
# std       5.976143
# min      78.000000
# 25%      85.000000
# 50%      89.000000
# 75%      92.000000
# max      95.000000

print(scores.value_counts())
# 92    3
# 85    2
# 78    2
# 95    1
# 90    1
# 88    1
TEXT 📖 Display only
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) Inspection and Filtering

▶ Example: head / tail / isin (Difficulty ⭐)

TEXT 📖 Display only
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

s = pd.Series(range(1, 101))  # 1 to 100

print(s.head())    # first 5
print(s.tail(3))   # last 3

# isin: membership test
fruits = pd.Series(['apple', 'banana', 'cherry', 'apple', 'date'])
print(fruits.isin(['apple', 'cherry']))
# 0     True
# 1    False
# 2     True
# 3     True
# 4    False
TEXT 📖 Display only
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) Handling NaN

▶ Example: NaN Handling Methods (Difficulty ⭐)

TEXT 📖 Display only
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

s = pd.Series([10, np.nan, 30, np.nan, 50])

print(s.isna())     # detect NaN
# 0    False
# 1     True
# 2    False
# 3     True
# 4    False

print(s.notna())    # detect non-NaN
print(s.dropna())   # remove NaN: [10.0, 30.0, 50.0]
print(s.fillna(0))  # fill NaN with 0
print(s.fillna(s.mean()))  # fill with mean value
TEXT 📖 Display only
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.


8. Complete Example: Coffee Shop Weekly Sales Analysis

▶ Example: End-to-End Coffee Shop Sales Analysis (Difficulty ⭐⭐⭐)

TEXT 📖 Display only
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: Coffee shop weekly
# sales analysis using Series
# ============================================

# 1. Create sales data with day labels
sales = pd.Series({
    'Mon': 320, 'Tue': 280, 'Wed': 350,
    'Thu': 410, 'Fri': 390, 'Sat': 520, 'Sun': 480
}, name='daily_sales_USD')

# 2. Basic statistics
print("=== Weekly Sales Report ===")
print(f"Total:      ${sales.sum():,}")
print(f"Daily avg:  ${sales.mean():.0f}")
print(f"Best day:   {sales.idxmax()} (${sales.max():,})")
print(f"Worst day:  {sales.idxmin()} (${sales.min():,})")
print(f"Std dev:    ${sales.std():.0f}")

# 3. Weekend vs weekday analysis
weekday_avg = sales[['Mon','Tue','Wed','Thu','Fri']].mean()
weekend_avg = sales[['Sat','Sun']].mean()
print(f"\nWeekday avg: ${weekday_avg:.0f}")
print(f"Weekend avg: ${weekend_avg:.0f}")
print(f"Weekend boost: {(weekend_avg/weekday_avg - 1)*100:.1f}%")

# 4. Daily change
change = sales.pct_change() * 100
print(f"\nBiggest daily drop: {change.min():.1f}% on {change.idxmin()}")
print(f"Biggest daily gain: {change.max():.1f}% on {change.idxmax()}")

# 5. Cumulative sales
cum_sales = sales.cumsum()
print(f"\nSales target $2,000 reached on: {cum_sales[cum_sales >= 2000].index[0]}")

# 6. Ranking
print(f"\nSales ranking:\n{sales.rank(ascending=False).astype(int)}")
TEXT 📖 Display only
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
=== Weekly Sales Report ===
Total:      $2,750
Daily avg:  $393
Best day:   Sat ($520)
Worst day:  Tue ($280)
Std dev:    $82

Weekday avg: $350
Weekend avg: $500
Weekend boost: 42.9%

Biggest daily drop: -12.5% on Tue
Biggest daily gain: 33.3% on Sat

❓ FAQ

Q What is the difference between a Series and an ndarray?
A Series = ndarray + Index + name. The underlying values of a Series are an ndarray, but with an added label index and name. During operations, a Series aligns by Index while an ndarray aligns by position. When you don't need labels, just use .values to extract the ndarray.
Q Can an Index have duplicates?
A Yes. Pandas allows duplicate Index values, but it hurts performance, and accessing a duplicate label returns multiple values (a Series rather than a scalar). It's best to keep the Index unique where possible — check with s.index.is_unique.
Q How is NaN handled during operations?
A By default NaN propagates — any operation involving NaN yields NaN. Methods like s.mean(skipna=True) automatically skip NaN (the default behavior). s.dropna() removes missing values, and s.fillna() fills them.
Q What's the difference between value_counts and unique?
A unique() returns the de-duplicated array (no counts), while value_counts() returns how often each value appears (sorted in descending order). Use value_counts for frequencies, and unique when you just need the distinct list.
Q Can a Series hold different types?
A Technically yes (dtype=object), but it's not recommended. A mixed-type Series loses vectorized operations and suffers a big performance hit. When you need mixed types, use a DataFrame instead — each column has its own type.
Q Which should I use, loc or iloc?
A Use loc for label-based access and iloc for position-based access. It's best to declare your intent explicitly with loc/iloc and avoid the ambiguity of s[...] (which could be either a label or a position).
Q What's the difference between s[label] and s.loc[label]?
A For a Series they have the same effect. But s[...] is ambiguous — it could be a label or a position (when the Index is integer-based). s.loc[label] explicitly means by label, and s.iloc[pos] explicitly means by position, so the explicit form is recommended.

📖 Summary


📝 Exercises

  1. Basic (Difficulty ⭐): Create a Series in 3 ways (list + index / dictionary / ndarray), and print the index and values properties for each.
  2. Intermediate (Difficulty ⭐⭐): Create two Series whose Index values don't fully match (e.g. monthly sales), add them with add(fill_value=0), and compare the result against using the + operator directly.
  3. Challenge (Difficulty ⭐⭐⭐): Use a Series to simulate a product's monthly sales data (12 months), then: calculate cumulative sales → find the month the cumulative total breaks 50,000 → compute the month-over-month growth rate → identify the months with the highest and lowest growth rates.

← Previous: Getting Started with Pandas · Next: DataFrame Core →

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%

🙏 帮我们做得更好

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

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