# How to Use pandas shift to Move a DataFrame Column Upwards by One Row

> Learn how to use pandas shift to move a DataFrame column upwards by one row.  Efficiently reorder your data with the shift(-1) method.

- Repository: [pandas/pandas](https://github.com/pandas-dev/pandas)
- Tags: how-to-guide
- Published: 2026-02-16

---

**To shift a pandas DataFrame column upwards by one row, use the `shift()` method with a negative `periods` argument, such as `df['column'].shift(-1)`, which moves data up and inserts `NaN` (or a specified `fill_value`) at the bottom.**

The `pandas shift` method is a core data manipulation tool in the **pandas-dev/pandas** library for offsetting data along the index axis. Whether you need to calculate differences between consecutive rows or realign time series data, understanding how to shift columns upwards efficiently is essential for data analysis workflows.

## Understanding the pandas shift Implementation

According to the pandas-dev/pandas source code, the `shift` operation is implemented across three core files. In **[`pandas/core/frame.py`](https://github.com/pandas-dev/pandas/blob/main/pandas/core/frame.py)** at line 6394, the `DataFrame.shift` method defines the public API entry point. This method delegates to the generic implementation in **[`pandas/core/generic.py`](https://github.com/pandas-dev/pandas/blob/main/pandas/core/generic.py)** at line 10509, which handles the actual re-indexing logic and parameter validation.

The low-level data movement occurs in **[`pandas/core/internals/managers.py`](https://github.com/pandas-dev/pandas/blob/main/pandas/core/internals/managers.py)** at line 543 within the `BlockManager` class. When `periods` is negative, this manager shifts the underlying data blocks upward and inserts the specified `fill_value` (defaulting to `NaN`) at the bottom rows. Because this operates directly on the block structure, it remains efficient for both homogeneous and heterogeneous column types.

## How to Shift a pandas Column Upwards by One Row

To move data upward in a DataFrame, pass a negative integer to the `periods` parameter of the `shift` method.

### Shifting a Single Column

Target a specific Series using column selection, then assign the result to a new column:

```python
import pandas as pd

df = pd.DataFrame({
    "A": [10, 20, 30, 40],
    "B": list("abcd")
})

# Shift column A upwards by one row

df["A_up"] = df["A"].shift(-1)
print(df)

```

**Output:**

```

    A  B  A_up
0  10  a  20.0
1  20  b  30.0
2  30  c  40.0
3  40  d   NaN

```

The values move up one position, and `NaN` fills the last row.

### Shifting the Entire DataFrame

Apply `shift` to the DataFrame itself to move all columns simultaneously:

```python

# Shift all columns upwards by one row

df_shifted = df.shift(-1)
print(df_shifted)

```

This returns a new DataFrame where every column has been shifted upward, leaving the original `df` unchanged.

### Handling Missing Values with fill_value

Control the value inserted at the bottom rows using the `fill_value` parameter:

```python

# Shift up and fill the last row with 0 instead of NaN

df["A_up_filled"] = df["A"].shift(-1, fill_value=0)
print(df)

```

This is particularly useful when working with integer columns where `NaN` would force a type conversion to float.

## Performance Characteristics

The `pandas shift` method operates efficiently on the underlying `BlockManager` structure. Because the implementation in [`pandas/core/internals/managers.py`](https://github.com/pandas-dev/pandas/blob/main/pandas/core/internals/managers.py) manipulates data blocks directly rather than iterating row-by-row, the operation achieves **O(n)** complexity relative to the number of elements. This block-level optimization applies uniformly to both single-column Series shifts and multi-column DataFrame operations, ensuring consistent performance across heterogeneous data types.

## Summary

- Use **`df['col'].shift(-1)`** to move a single column upwards by one row, or **`df.shift(-1)`** to shift the entire DataFrame.
- The operation returns a **new object**; the original DataFrame remains unmodified according to pandas' functional design principles.
- Pass **`fill_value`** to replace the default `NaN` inserted at the bottom rows with a custom value.
- The implementation leverages the **`BlockManager`** in [`pandas/core/internals/managers.py`](https://github.com/pandas-dev/pandas/blob/main/pandas/core/internals/managers.py) for efficient block-level data movement.

## Frequently Asked Questions

### How do I shift a pandas column up without getting NaN values?

Use the `fill_value` parameter to specify a replacement value for the empty rows created at the bottom. For example: `df['col'].shift(-1, fill_value=0)` fills the last row with `0` instead of `NaN`.

### Does pandas shift modify the original DataFrame?

No, the `shift` method returns a new DataFrame or Series and leaves the original object unchanged. This follows pandas' functional programming paradigm where operations produce new objects rather than modifying data in-place.

### Can I shift multiple columns up by different amounts simultaneously?

No, a single call to `shift` applies the same `periods` value to all columns. To shift different columns by different amounts, you must call `shift` separately for each column and combine the results: `df['A'] = df['A'].shift(-1)` and `df['B'] = df['B'].shift(-2)`.

### What is the performance complexity of pandas shift?

The `shift` operation runs in **O(n)** time relative to the number of elements, as it operates directly on the underlying `BlockManager` structure without row-by-row iteration. This makes it efficient even for large DataFrames with millions of rows.