How to Create a Pandas DataFrame from a List of Lists
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
Notice that the Budget column became float64 even though the original values were integers. This happens because standard NumPy integers cannot represent NaN, so Pandas automatically upcasts the column to float. If you need integer behavior with missing values, use the nullable integer type:
import pandas as pd
data = [
['Project A', 5000],
['Project B', None],
['Project C', 3000]
]
df = pd.DataFrame(data, columns=['Name', 'Budget'])
df['Budget'] = df['Budget'].astype('Int64') # Capital I for nullable integer
print(df['Budget'])
Output:
0 5000
1 <NA>
2 3000
Name: Budget, dtype: Int64
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
# Each inner list contains one column's data
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.