Skip to content

How to Create a Pandas DataFrame from a List of Lists

Learn how to convert lists of lists into a Pandas DataFrame, handle missing data, customize indices, transpose column-oriented lists, and manage unequal row lengths for structured data processing.

Lists of lists are a natural format for row-oriented data in Python. Each inner list represents one complete record, making this structure common when reading parsed files, collecting results in loops, or receiving data from functions that return rows. Pandas converts this format directly into a DataFrame, with each inner list becoming a row in the resulting table.

In this guide, you will learn how to create DataFrames from lists of lists, add column names and custom indices, handle missing data and unequal row lengths, and deal with column-oriented lists.

Standard Row-Wise Conversion

Pass the list of lists to pd.DataFrame() and specify column names with the columns parameter:

import pandas as pd

data = [
    ['Apple', 999, 10],
    ['Samsung', 899, 20],
    ['Google', 799, 15]
]

df = pd.DataFrame(data, columns=['Brand', 'Price', 'Qty'])

print(df)

Output:

     Brand  Price  Qty
0    Apple    999   10
1  Samsung    899   20
2   Google    799   15

Each inner list maps to one row, and the columns parameter assigns meaningful names instead of the default numeric headers (0, 1, 2).

Adding a Custom Index

Replace the default sequential index with custom labels using the index parameter:

import pandas as pd

data = [
    ['Alice', 88],
    ['Bob', 92],
    ['Charlie', 78]
]

df = pd.DataFrame(
    data,
    columns=['Name', 'Score'],
    index=['s1', 's2', 's3']
)

print(df)

Output:

       Name  Score
s1    Alice     88
s2      Bob     92
s3  Charlie     78

Custom indices let you access rows by meaningful labels (e.g., df.loc['s1']) rather than by position.

Handling Missing Data

When inner lists contain None, Pandas automatically converts them to NaN:

import pandas as pd

data = [
    ['Project A', 5000],
    ['Project B', None],
    ['Project C', 3000]
]

df = pd.DataFrame(data, columns=['Name', 'Budget'])

print(df)
print()
print(df.dtypes)

Output:

        Name  Budget
0  Project A  5000.0
1  Project B     NaN
2  Project C  3000.0

Name       object
Budget    float64
dtype: object

Transposing When Lists Represent Columns

Sometimes each inner list represents a column's values rather than a row's values. Use .T (transpose) to swap rows and columns:

import pandas as pd

data = [
    [100, 200, 300],  # Sales values
    [10, 20, 30]      # Units values
]

df = pd.DataFrame(data).T
df.columns = ['Sales', 'Units']

print(df)

Output:

   Sales  Units
0    100     10
1    200     20
2    300     30

Without the transpose, you would get 2 rows and 3 columns instead of the intended 3 rows and 2 columns.

Handling Ragged Lists (Unequal Lengths)

When inner lists have different numbers of elements, Pandas pads shorter rows with None to create a rectangular DataFrame:

import pandas as pd

data = [
    ['A', 1, 2],
    ['B', 3],        # Missing one element
    ['C', 4, 5, 6]   # One extra element
]

df = pd.DataFrame(data)

print(df)

Output:

   0  1    2    3
0  A  1  2.0  NaN
1  B  3  NaN  NaN
2  C  4  5.0  6.0

The resulting DataFrame has 4 columns to accommodate the longest list. Shorter lists have NaN or None in the trailing positions.

Specifying Data Types After Creation

Pandas infers data types automatically, but you often need to convert columns to more appropriate types:

import pandas as pd

data = [
    ['2024-01-01', 100],
    ['2024-01-02', 200]
]

df = pd.DataFrame(data, columns=['Date', 'Value'])

df['Date'] = pd.to_datetime(df['Date'])
df['Value'] = df['Value'].astype('Int64')

print(df.dtypes)

Output:

Date     datetime64[ns]
Value             Int64
dtype: object

Practical Example: Building a DataFrame from Computed Results

A common pattern is generating rows in a loop and collecting them as a list of lists:

import pandas as pd

results = []
for i in range(1, 6):
    name = f"Item_{i}"
    price = i * 10.5
    in_stock = i % 2 == 0
    results.append([name, price, in_stock])

df = pd.DataFrame(results, columns=['Product', 'Price', 'In_Stock'])

print(df)

Output:

  Product  Price  In_Stock
0  Item_1   10.5     False
1  Item_2   21.0      True
2  Item_3   31.5     False
3  Item_4   42.0      True
4  Item_5   52.5     False

Quick Reference

Goal Method
Standard creation pd.DataFrame(data, columns=['X', 'Y'])
With custom index pd.DataFrame(data, columns=[...], index=[...])
Transpose pd.DataFrame(data).T
Handle None Automatic conversion to NaN
Nullable integers .astype('Int64') after creation
  • Lists of lists are ideal for row-by-row data such as parsed logs, query results, or computed records.
  • Always specify the columns parameter for immediate readability.
  • Use .T if your inner lists represent columns rather than rows.
  • Be aware that None values convert to NaN and may cause integer columns to become floats unless you use the nullable Int64 type.
Navigation