Skip to content

Python Pandas: How to Convert DataFrame Row to Column Headers

Learn how to fix misaligned DataFrame headers by converting a data row into column names using df.columns, rename(), or DataFrame reconstruction in Pandas.

Sometimes, data is loaded into a Pandas DataFrame where the actual column headers are incorrectly positioned as one of the data rows (e.g., the first or second row). To prepare such data for analysis, you need to promote this specific row to become the DataFrame's column names and then typically remove that row from the data body.

This guide explains several methods to convert a DataFrame row into column headers in Pandas, primarily using direct assignment to df.columns and the DataFrame.rename() method.

The Goal: Promoting a Data Row to Headers

Given a Pandas DataFrame where one of the rows (e.g., the first row at index 0, or another specific row) contains the intended column names, we want to:

  1. Set these values as the actual column headers.
  2. Remove this row from the DataFrame's data section.
  3. Optionally, reset the DataFrame's index to a standard 0-based integer index.

Example DataFrame

Assume our data was loaded, and the true headers are in the first data row (index 0 after default loading, or a specific known row).

import pandas as pd

data = {
    0: ['ID', 'Product_Name', 'Category', 'Price_USD'], # Intended headers
    1: ['P101', 'Laptop', 'Electronics', 1200],
    2: ['A205', 'Mouse', 'Accessory', 25],
    3: ['A210', 'Keyboard', 'Accessory', 75],
    4: ['P107', 'Monitor', 'Electronics', 300]
}
df_original = pd.DataFrame.from_dict(data, orient='index') # Create with 0,1,2.. as columns

data_with_headers = [
    ['Header1', 'Header2', 'Header3'], # This will be current headers
    ['Real_ID', 'Real_Name', 'Real_Value'], # This is the row we want as new headers
    ['ID001', 'Alice', 100],
    ['ID002', 'Bob', 150]
]
df = pd.DataFrame(data_with_headers[1:], columns=data_with_headers[0])

df_for_header_change = pd.DataFrame({
    'ColA': ['Name', 'Alice', 'Bob', 'Charlie'],
    'ColB': ['Age', 30, 25, 35],
    'ColC': ['City', 'New York', 'London', 'Paris']
})

print("Original DataFrame (where first data row should be headers):")
print(df_for_header_change)

Output:

Original DataFrame (where first data row should be headers):
      ColA ColB      ColC
0     Name  Age      City
1    Alice   30  New York
2      Bob   25    London
3  Charlie   35     Paris

Our goal is to make 'Name', 'Age', 'City' the actual column headers.

Method 1: Assigning a Row to df.columns (Direct and Common)

This is the most straightforward method: select the row containing the desired headers and assign its values to df.columns.

Selecting the Row for Headers using .iloc[]

DataFrame.iloc[row_index] selects a row by its integer position and returns it as a Series.

import pandas as pd

df = pd.DataFrame({
    'ColA': ['Name', 'Alice', 'Bob', 'Charlie'],
    'ColB': ['Age', 30, 25, 35],
    'ColC': ['City', 'New York', 'London', 'Paris']
})

new_headers = df.iloc[0]
print("Selected row for new headers:")
print(new_headers)

Output:

Selected row for new headers:
ColA    Name
ColB     Age
ColC    City
Name: 0, dtype: object

Assigning to df.columns

Assign this Series of new header names to the DataFrame's columns attribute.

import pandas as pd

df = pd.DataFrame({
    'ColA': ['Name', 'Alice', 'Bob', 'Charlie'],
    'ColB': ['Age', 30, 25, 35],
    'ColC': ['City', 'New York', 'London', 'Paris']
})
new_headers = df.iloc[0]

df.columns = new_headers

print("DataFrame after assigning new headers:")
print(df)

Output:

DataFrame after assigning new headers:
0     Name  Age      City
0     Name  Age      City
1    Alice   30  New York
2      Bob   25    London
3  Charlie   35     Paris

Now the column names are correct, but the row that was the header is still present as the first data row. The name of the columns object might also be set to the index of the row used.

Dropping the Original Header Row from Data

After setting the new headers, remove the row that was used for them.

import pandas as pd

df = pd.DataFrame(
    [['Name', 'Age', 'City'], ['Alice', 30, 'New York'], ['Bob', 25, 'London'], ['Charlie', 35, 'Paris']],
    columns=['ColA', 'ColB', 'ColC']
)
df.columns = df.iloc[0] # Set first row as headers

df = df.drop(0) # Drops row with index label 0

print("DataFrame after dropping the original header row:")
print(df)

Output:

DataFrame after dropping the original header row:
0     Name Age      City
1    Alice  30  New York
2      Bob  25    London
3  Charlie  35     Paris

Resetting the Index (Optional)

After dropping the header row, the DataFrame's index might not be sequential or start from 0. You can reset it.

import pandas as pd

df = pd.DataFrame(
    [['Alice', 30, 'New York'], ['Bob', 25, 'London'], ['Charlie', 35, 'Paris']],
    index=[1,2,3], # Simulating index after dropping original row 0
    columns=['Name', 'Age', 'City']
)
df.columns.name = 0 # Simulating state after header assignment

df = df.reset_index(drop=True)

df.columns.name = None

print("DataFrame after resetting index and clearing columns name:")
print(df)

Output:

DataFrame after resetting index and clearing columns name:
      Name  Age      City
0    Alice   30  New York
1      Bob   25    London
2  Charlie   35     Paris

Method 2: Using DataFrame.rename(columns=...)

The rename() method can also be used if you can create a dictionary mapping old column names (0, 1, 2... if no header was read) to the new names from the desired row.

import pandas as pd

data_for_rename_method = [
    ['ID_Val', 'Type_Val', 'Status_Val'], # This row contains new headers
    ['R1', 'Alpha', 'Active'],
    ['R2', 'Beta', 'Inactive']
]
df_no_header = pd.DataFrame(data_for_rename_method)
print("DataFrame with default integer headers:")
print(df_no_header)
print()

new_header_row = df_no_header.iloc[0]

rename_mapping = dict(enumerate(new_header_row))

df_renamed = df_no_header.rename(columns=rename_mapping)

df_renamed = df_renamed.drop(0)

df_renamed = df_renamed.reset_index(drop=True)

print("DataFrame after rename, drop, and reset_index:")
print(df_renamed)

Output:

DataFrame with default integer headers:
        0         1           2
0  ID_Val  Type_Val  Status_Val
1      R1     Alpha      Active
2      R2      Beta    Inactive

DataFrame after rename, drop, and reset_index:
  ID_Val Type_Val Status_Val
0     R1    Alpha     Active
1     R2     Beta   Inactive

Method 3: Creating a New DataFrame (Reconstruction)

You can select the row for headers and the subsequent data rows separately, then create a new DataFrame.

import pandas as pd

data_for_reconstruct = [
    ['Col_X_Name', 'Col_Y_Name', 'Col_Z_Name'], # Intended headers at row 0
    [10, 'Apple', True],
    [20, 'Banana', False],
    [30, 'Cherry', True]
]
df_raw = pd.DataFrame(data_for_reconstruct) # Columns will be 0, 1, 2
print("Raw DataFrame (headers in row 0):")
print(df_raw)
print()

new_headers_reconstruct = df_raw.iloc[0]

data_values = df_raw.values[1:] # Get data as NumPy array, skipping first row

df_reconstructed = pd.DataFrame(data_values, columns=new_headers_reconstruct)

print("Reconstructed DataFrame with correct headers:")
print(df_reconstructed)

Output:

Raw DataFrame (headers in row 0):
            0           1           2
0  Col_X_Name  Col_Y_Name  Col_Z_Name
1          10       Apple        True
2          20      Banana       False
3          30      Cherry        True

Reconstructed DataFrame with correct headers:
0 Col_X_Name Col_Y_Name Col_Z_Name
0         10      Apple       True
1         20     Banana      False
2         30     Cherry       True

Important Considerations (Data Types, Duplicate Header Names)

  • Data Types: When a row is promoted to headers, all values in that row are treated as strings for the column names. The underlying data in the columns retains its original type.
  • Duplicate Header Names: If the row you promote to headers contains duplicate values, your DataFrame will have duplicate column names. This is generally allowed but can make column selection ambiguous (e.g., df['DuplicateName'] would return multiple columns). It's best to ensure header names are unique.
  • Column Axis Name: Assigning a row to df.columns might set df.columns.name to the index label of the row used. You can clear this with df.columns.name = None.

Conclusion

To convert a specific row of a Pandas DataFrame into its column headers:

  1. Select the target row (e.g., using desired_headers_row = df.iloc[N]).
  2. Assign these values to the DataFrame's columns: df.columns = desired_headers_row.
  3. Drop the original row that now serves as headers from the DataFrame's data: df = df.drop(index_label_of_header_row). (If you used df.iloc[N] to get headers, the label is likely df.index[N]).
  4. (Optional) Reset the index: df = df.reset_index(drop=True) for a clean 0-based integer index.

The method of creating a new DataFrame by selecting headers and data separately is also very effective, especially if the headers are known to be the very first row of the initially loaded (or raw) data.

Navigation