Wicked Smart Data
LearnInsightsAboutContact
Sign InLet's Build
LearnInsightsAboutContact
Sign InLet's Build
Wicked Smart Data

Intelligence, automation, and expert execution — plus an elite library of free knowledge. We turn complexity into competitive advantage.

Start a conversation

Platform

  • Learning Paths
  • Insights
  • RSS Feed

Company

  • About
  • Contact
  • Work With Us

Legal

  • Privacy Policy
  • Terms of Service

© 2026 Wicked Smart Data. All rights reserved.

Intelligence · Automation · Advantage

All Insights
Python

Sampling, Sorting, and Inspecting DataFrames in pandas: head, tail, sample, sort_values, and nlargest for Quick Data Exploration

Before you analyze anything, you need to orient yourself in your data. This lesson teaches you the five pandas methods every analyst uses in the first two minutes with a new dataset — and how to combine them into a fast, reliable exploration workflow.

🌱 Foundation15 min readSep 22, 2026Updated Sep 22, 2026
Sampling, Sorting, and Inspecting DataFrames in pandas: head, tail, sample, sort_values, and nlargest for Quick Data Exploration
On this page
  • Introduction
  • Prerequisites
  • Setting Up Our Example Dataset
  • Peeking at Your Data: head() and tail()
  • head() — The First Impression
  • tail() — Checking the End
  • Taking a Random Sample: sample()
  • Controlling Randomness with random_state
  • Sampling a Fraction of Rows
  • Sorting Data: sort_values()
  • Sorting by a Single Column
  • Sorting by Multiple Columns
  • Controlling Where NaN Values Land
  • Finding the Biggest and Smallest: nlargest() and nsmallest()
  • nlargest() with Multiple Columns for Tie-Breaking
  • A Practical Example: Top 5 Transactions Per Rep
  • Putting It Together: A Real Exploration Workflow
  • Chaining Methods for Concise Exploration
  • Hands-On Exercise
  • Common Mistakes & Troubleshooting
  • Summary & Next Steps
  • Sampling, Sorting, and Inspecting DataFrames in pandas: head, tail, sample, sort_values, and nlargest for Quick Data Exploration

    Introduction

    You've just loaded a dataset into pandas. Maybe it's 200,000 rows of sales transactions, a year of customer orders, or a dump from a production database. Now what? You can't scroll through 200,000 rows the way you'd skim an Excel sheet. You need a smarter way to look at your data — quickly, confidently, and without getting overwhelmed.

    This is exactly the problem that a handful of deceptively simple pandas methods solve. Before you filter, clean, aggregate, or visualize anything, you need to inspect your data: peek at the top and bottom rows, take a random sample to spot-check quality, sort to find your biggest or smallest values, and rank your top performers. These aren't glamorous operations, but they're the ones experienced analysts reach for within the first 30 seconds of touching a new dataset. Get comfortable with them and you'll develop instincts that catch problems early and guide your analysis in the right direction.

    By the end of this lesson, you'll be able to confidently orient yourself in any new DataFrame, surface the rows that matter most, and sort your data exactly the way you need it — all before writing a single line of complex analysis code.

    What you'll learn:

    • How to inspect the first and last rows of a DataFrame with head() and tail()
    • How to take a random sample with sample() to spot-check data quality
    • How to sort a DataFrame by one or more columns with sort_values()
    • How to quickly retrieve the top or bottom N rows by a numeric column with nlargest() and nsmallest()
    • How these methods fit together in a real exploratory workflow

    Prerequisites

    This lesson assumes you're comfortable with what a pandas DataFrame is and how to load data into one. If you're just getting started, work through Your First pandas DataFrame: Loading CSV and Excel Files and Exploring Data first. You should also have Python and pandas installed — if not, Setting Up Python for Data Analysis: Python, VS Code, Jupyter, and Virtual Environments will walk you through it.


    Setting Up Our Example Dataset

    Throughout this lesson, we'll work with a realistic sales dataset. Let's build one directly in Python so you can follow along without needing an external file:

    import pandas as pd
    import numpy as np
    
    np.random.seed(42)
    
    regions = ['North', 'South', 'East', 'West']
    products = ['Laptop', 'Monitor', 'Keyboard', 'Mouse', 'Headset', 'Webcam']
    reps = ['Alice', 'Bob', 'Carol', 'David', 'Eve', 'Frank']
    
    n = 500
    
    df = pd.DataFrame({
        'date': pd.date_range('2023-01-01', periods=n, freq='D').strftime('%Y-%m-%d'),
        'rep': np.random.choice(reps, n),
        'region': np.random.choice(regions, n),
        'product': np.random.choice(products, n),
        'units': np.random.randint(1, 50, n),
        'unit_price': np.random.choice([299.99, 499.99, 89.99, 29.99, 149.99, 79.99], n),
        'discount_pct': np.random.choice([0, 5, 10, 15, 20], n),
    })
    
    df['revenue'] = (df['units'] * df['unit_price'] * (1 - df['discount_pct'] / 100)).round(2)
    
    # Sprinkle in a few missing values to make it realistic
    df.loc[np.random.choice(df.index, 15), 'discount_pct'] = np.nan
    

    We now have 500 rows of sales data across multiple reps, regions, and products — realistic enough to make the examples meaningful.


    Peeking at Your Data: head() and tail()

    head() — The First Impression

    head() returns the first N rows of a DataFrame. By default, N is 5, but you can pass any number you want.

    df.head()
    
             date    rep region  product  units  unit_price  discount_pct    revenue
    0  2023-01-01  David   West  Monitor     14      499.99           0.0    6999.86
    1  2023-01-02   Carol  North  Webcam     23       79.99           5.0    1747.78
    2  2023-01-03    Eve   East  Laptop     41      299.99          10.0   11099.63
    3  2023-01-04   Alice  South  Mouse     36       29.99          20.0     863.71
    4  2023-01-05    Bob   West  Headset     18      149.99          15.0    2294.85
    
    df.head(10)  # First 10 rows
    

    This gives you an immediate feel for the columns that exist, what data types look plausible, and whether the data loaded correctly. Think of it as the pandas equivalent of pressing Ctrl+Home in Excel to jump to the top of your spreadsheet.

    tail() — Checking the End

    tail() works identically, but shows you the last N rows:

    df.tail()
    
               date   rep region   product  units  unit_price  discount_pct    revenue
    495  2023-05-12  Frank  West  Keyboard     33       89.99           0.0    2969.67
    496  2023-05-13  Alice  East    Webcam     12       79.99          20.0     767.90
    497  2023-05-14  Carol  North    Mouse     28       29.99          10.0     755.75
    498  2023-05-15    Bob  South   Laptop      7      299.99           5.0    1994.93
    499  2023-05-16  David   West  Monitor     42      499.99          15.0   17849.64
    

    Why bother checking the tail? Because the end of a file often reveals problems that the top doesn't: truncated imports, summary rows accidentally included in the data (a classic Excel gotcha), or data that stops partway through a time period. Always check both ends.

    Tip

    When loading data from an external source, check both df.head() and df.tail() before doing anything else. A mismatched row count or a weird trailing row is much easier to catch now than after you've already built analysis on top of it.


    Taking a Random Sample: sample()

    head() and tail() only show you the edges of your dataset. For large datasets, the rows at the top and bottom are often not representative — they might all be from the same date, region, or customer. That's where sample() comes in.

    sample() returns a random selection of rows from your DataFrame. It doesn't care about order — it just grabs rows at random, which makes it a great spot-check tool.

    df.sample(5)
    
               date    rep region   product  units  unit_price  discount_pct    revenue
    312  2023-11-09  Alice   East    Webcam     17       79.99          10.0    1223.85
    88   2023-03-30    Bob  North    Mouse     45       29.99           5.0    1282.07
    441  2023-02-27  Carol  South  Keyboard     11       89.99           NaN     989.89
    201  2023-07-20  Frank   West   Laptop     29      299.99           0.0    8699.71
    67   2023-03-08  David  South  Headset     39      149.99          15.0    4962.67
    

    Notice that row 441 shows a NaN in discount_pct — that's exactly the kind of data quality issue sample() helps surface. If you only ever looked at head(), you might miss that missing values exist at all.

    Controlling Randomness with random_state

    One frustration with random sampling: every time you run sample(), you get different rows. That's fine for exploration, but if you want reproducible results — for example, to share a specific sample with a colleague — use the random_state parameter:

    df.sample(5, random_state=99)
    

    With the same random_state, you'll get the same rows every time. Think of it as setting a seed for randomness.

    Sampling a Fraction of Rows

    Sometimes you don't want a fixed number of rows — you want a percentage. Use frac:

    df.sample(frac=0.1)  # Random 10% of the dataset (50 rows from our 500)
    

    This is especially useful when you're working with a large dataset and want to prototype your analysis on a manageable slice before running it on everything.

    Note

    sample() without random_state is non-deterministic — meaning you'll get different results every run. For exploratory work, that's fine. For anything you need to reproduce or share, always set random_state.


    Sorting Data: sort_values()

    Sorting in pandas works differently than sorting in Excel, but it's more powerful. In Excel, sorting rearranges your sheet permanently (unless you undo). In pandas, sort_values() returns a new sorted DataFrame — your original is untouched unless you explicitly tell pandas to modify it.

    Sorting by a Single Column

    df.sort_values('revenue')
    

    By default, this sorts ascending — lowest revenue first. To get the highest revenue first, use ascending=False:

    df.sort_values('revenue', ascending=False)
    
               date    rep region  product  units  unit_price  discount_pct     revenue
    499  2023-05-16  David   West  Monitor     42      499.99          15.0   17849.64
    396  2023-02-01    Eve  North  Monitor     49      499.99           0.0   24499.51
    ...
    

    Key insight

    sort_values() returns a new DataFrame — it doesn't modify df in place. If you want to sort and keep using that sorted version, assign it: df_sorted = df.sort_values('revenue', ascending=False). Or add inplace=True, but in practice, assigning to a new variable is cleaner and less confusing.

    Sorting by Multiple Columns

    This is where pandas pulls ahead of basic Excel sorting. You can sort by multiple columns at once by passing a list. Rows are sorted by the first column, then ties are broken by the second column, and so on.

    Suppose you want to see each sales rep's transactions, and within each rep, you want the most recent transaction first:

    df.sort_values(['rep', 'date'], ascending=[True, False])
    
             date    rep region   product  units  unit_price  discount_pct    revenue
    496  2023-05-13  Alice   East   Webcam     12       79.99          20.0     767.90
    489  2023-05-06  Alice  South    Mouse     32       29.99           5.0     911.69
    482  2023-04-29  Alice   West   Laptop      5      299.99          10.0    1349.96
    ...
    

    ascending takes a list that matches the columns list — True for ascending, False for descending.

    Controlling Where NaN Values Land

    By default, pandas sorts NaN values to the end of a sorted column, regardless of sort direction. That behavior is usually fine, but you can override it:

    df.sort_values('discount_pct', ascending=False, na_position='first')
    # NaN rows appear at the top
    

    This is useful when you specifically want to investigate rows with missing values — put them first so they're visible immediately.

    Warning

    Forgetting that sort_values() returns a new DataFrame is one of the most common pandas mistakes. If you write df.sort_values('revenue', ascending=False) and then on the next line do df.head(10), you'll see the original unsorted top 10 — not the top 10 by revenue. Always either chain the methods or save the result to a variable.


    Finding the Biggest and Smallest: nlargest() and nsmallest()

    If all you want is the top N rows by a numeric column, nlargest() is more convenient than sort_values() + head(). It's also slightly faster on large DataFrames.

    df.nlargest(10, 'revenue')
    

    This returns the 10 rows with the highest revenue values, already sorted from highest to lowest. No need to chain ascending=False and then head(10).

    df.nsmallest(5, 'units')
    

    This returns the 5 rows with the lowest units values — handy for finding your smallest orders or under-performing transactions.

    nlargest() with Multiple Columns for Tie-Breaking

    When values are tied, you can pass additional columns to break the tie:

    df.nlargest(10, ['revenue', 'units'])
    

    Pandas will return the 10 rows that are largest by revenue, breaking ties with units.

    Tip

    Use nlargest() and nsmallest() when you just want to find extremes quickly. Use sort_values() when you need full control — multiple sort columns with mixed ascending/descending, reuse of the sorted DataFrame, or sorting non-numeric columns like dates or text.

    A Practical Example: Top 5 Transactions Per Rep

    Here's a slightly more advanced pattern. What if you want the top 3 transactions for each sales rep? You can combine groupby() with apply() and nlargest():

    top3_per_rep = (
        df.groupby('rep', group_keys=False)
        .apply(lambda g: g.nlargest(3, 'revenue'))
    )
    top3_per_rep
    

    This gives you 3 rows per rep — the 3 biggest deals each person closed. This kind of grouped ranking is a building block for leaderboards and performance reports. Once you're comfortable with the basics, explore Grouping and Aggregating in pandas: groupby as the PivotTable Replacement to go deeper on this pattern.


    Putting It Together: A Real Exploration Workflow

    Let's walk through what a realistic first-look exploration looks like when you receive a new dataset. This is the actual sequence experienced analysts use:

    import pandas as pd
    import numpy as np
    
    # Step 1: Load the data (or use our in-memory DataFrame)
    # df = pd.read_csv('sales_2023.csv')
    
    # Step 2: Understand the shape and structure
    print(df.shape)         # (500, 8) — 500 rows, 8 columns
    print(df.dtypes)        # Column types
    print(df.columns.tolist())  # Column names
    
    # Step 3: Peek at the top and bottom
    print(df.head())
    print(df.tail())
    
    # Step 4: Take a random sample to spot-check middle of the data
    print(df.sample(10, random_state=1))
    
    # Step 5: Check for missing values
    print(df.isnull().sum())
    
    # Step 6: Sort to see biggest transactions — where's the money?
    print(df.sort_values('revenue', ascending=False).head(10))
    
    # Step 7: Quickly surface top 5 deals
    print(df.nlargest(5, 'revenue'))
    
    # Step 8: Find smallest orders (potential data issues or micro-transactions)
    print(df.nsmallest(5, 'revenue'))
    
    # Step 9: Sort by rep and date to spot-check one person's history
    alice_sorted = df[df['rep'] == 'Alice'].sort_values('date', ascending=False)
    print(alice_sorted.head(10))
    

    This entire workflow takes under two minutes and already answers: does the data look reasonable? Are there obvious missing values? Who are the top performers? Are there any suspicious micro-transactions?

    For a more systematic approach to data quality checks before analysis, see Validating and Profiling a New Dataset with pandas: Row Counts, Distributions, and Outlier Checks Before You Analyze.


    Chaining Methods for Concise Exploration

    One of the satisfying things about pandas is that you can chain these methods together into readable one-liners. Instead of:

    sorted_df = df.sort_values('revenue', ascending=False)
    top10 = sorted_df.head(10)
    print(top10)
    

    You can write:

    df.sort_values('revenue', ascending=False).head(10)
    

    Chaining works because each method returns a DataFrame, and the next method operates on that returned DataFrame. This is the same idea as nesting functions in Excel formulas, just written left-to-right instead of inside-out.

    A few useful chains:

    # Top 5 by revenue, showing only rep, product, and revenue columns
    df.nlargest(5, 'revenue')[['rep', 'product', 'revenue']]
    
    # Sort by region then revenue, and sample 3 from each region
    df.sort_values(['region', 'revenue'], ascending=[True, False]).groupby('region').head(3)
    
    # Bottom 10 transactions, randomly shuffled — useful for varied spot-checking
    df.nsmallest(10, 'revenue').sample(frac=1, random_state=7)
    

    Key insight

    Chaining methods is idiomatic pandas — it's how experienced practitioners write exploratory code. It keeps your intermediate results from cluttering the namespace and makes it easy to read what's happening in sequence. Just don't chain so many steps that debugging becomes painful.


    Hands-On Exercise

    Work through these tasks using the sales DataFrame we created at the start of the lesson. Try each one before reading the solution below.

    Task 1: Show the first 8 rows of the DataFrame.

    Task 2: Take a random sample of 20 rows with random_state=2024. How many of them have a NaN in discount_pct?

    Task 3: Sort the DataFrame by region (ascending) and then by revenue (descending). Display the first 15 rows.

    Task 4: Find the 5 transactions with the lowest units sold.

    Task 5: For the product "Monitor" only, find the top 3 transactions by revenue.


    Solutions:

    # Task 1
    df.head(8)
    
    # Task 2
    sample = df.sample(20, random_state=2024)
    print(sample['discount_pct'].isnull().sum())
    
    # Task 3
    df.sort_values(['region', 'revenue'], ascending=[True, False]).head(15)
    
    # Task 4
    df.nsmallest(5, 'units')
    
    # Task 5
    df[df['product'] == 'Monitor'].nlargest(3, 'revenue')
    

    Common Mistakes & Troubleshooting

    "I sorted my DataFrame but the original still looks unsorted." Right — sort_values() returns a new DataFrame. Either assign it (sorted_df = df.sort_values(...)) or use inplace=True. Prefer the assignment approach for clarity.

    "I used head() after sort_values() but got wrong results." Make sure you're chaining correctly. df.sort_values('revenue', ascending=False).head(5) works. But if you wrote df.sort_values('revenue', ascending=False) on one line and df.head(5) on the next, you're calling head() on the original df, not the sorted one.

    "nlargest() gives me an error about non-numeric data." nlargest() and nsmallest() only work on numeric columns. If your revenue column was accidentally loaded as a string (check with df.dtypes), you'll need to convert it first: df['revenue'] = pd.to_numeric(df['revenue'], errors='coerce'). See Cleaning Messy Data with pandas: Missing Values, Duplicates, and Data Types for a full guide to type conversion.

    "sample() gives different results every time." That's expected behavior. If you need reproducibility, always set random_state=<any integer>.

    "I sorted by date but the order looks wrong." If your date column is stored as a string (e.g., '2023-01-15'), alphabetical string sorting usually works for ISO-format dates (YYYY-MM-DD). But if your dates look like '01/15/2023', string sorting will fail. Convert your column to a proper datetime first: df['date'] = pd.to_datetime(df['date']). Learn more about working with date columns in Working with Dates and Time Series in pandas: Parsing, Resampling, and Rolling Windows.


    Summary & Next Steps

    Here's what you can now do:

    Method What it does When to use it
    head(n) First n rows (default 5) First look at structure and top rows
    tail(n) Last n rows (default 5) Check for trailing junk, truncation
    sample(n) Random n rows Spot-check data quality throughout
    sort_values(col) Sort by column(s) Full ordering, multiple columns, text
    nlargest(n, col) Top n rows by numeric column Quick top-N leaderboard
    nsmallest(n, col) Bottom n rows by numeric column Smallest orders, outliers

    These methods form the core of your first-look workflow every time you touch a new dataset. They're simple individually, but used together they give you a remarkably complete picture of what you're working with before you write a line of serious analysis.

    Where to go next:

    • To go beyond peeking at rows and start filtering to specific subsets, work through Selecting and Filtering Data in pandas: loc, iloc, and Boolean Masks
    • Once you're comfortable exploring, you'll want to aggregate and summarize — Grouping and Aggregating in pandas: groupby as the PivotTable Replacement is the natural next step
    • For a deeper framework on validating data quality as a whole, see Validating and Profiling a New Dataset with pandas: Row Counts, Distributions, and Outlier Checks Before You Analyze
    Work With Us

    From insight to implementation

    Reading is the start. When you're ready to build the data, automation, or AI systems behind it, our team turns strategy into shipped results.

    Let's Build

    Python for Data Analysis

    Previous

    Forecasting Seasonal Trends in pandas: Decomposing Time Series into Trend, Seasonality, and Residuals for Business Reporting

    Next

    Building a pandas Data Quality Scorecard: Automating Completeness, Consistency, and Validity Checks Across Every Column Before Analysis

    Related Insights

    PythonExpert

    Segmenting Customers with RFM Analysis in pandas: Calculating Recency, Frequency, and Monetary Scores from Transaction Data

    28 min
    PythonExpert

    Building a Self-Updating Sales Dashboard in pandas and openpyxl: Automated Charts, Conditional Formatting, and Named Ranges from a Live Data Source

    24 min
    PythonExpert

    Automating pandas Data Cleaning with Custom Validation Rules, Error Logs, and a Corrected Output File

    26 min

    On this page

    • Introduction
    • Prerequisites
    • Setting Up Our Example Dataset
    • Peeking at Your Data: head() and tail()
    • head() — The First Impression
    • tail() — Checking the End
    • Taking a Random Sample: sample()
    • Controlling Randomness with random_state
    • Sampling a Fraction of Rows
    • Sorting Data: sort_values()
    • Sorting by a Single Column
    • Sorting by Multiple Columns
    • Controlling Where NaN Values Land
    • Finding the Biggest and Smallest: nlargest() and nsmallest()
    • nlargest() with Multiple Columns for Tie-Breaking
    • A Practical Example: Top 5 Transactions Per Rep
    • Putting It Together: A Real Exploration Workflow
    • Chaining Methods for Concise Exploration
    • Hands-On Exercise
    • Common Mistakes & Troubleshooting
    • Summary & Next Steps