 <p>There might be a way to do this with less duplication, but the following should work, anyway. First, find out which columns we need to shift, and then replace those columns by the shifted versions.</p> <pre><code>to_shift = pd.isnull(df2.iloc[-1]) df2.loc[:,to_shift] = df2.loc[:,to_shift].shift(1) </code></pre> <hr> <p>Get the last row:</p> <pre><code>&gt;&gt;&gt; df2.iloc[-1] one 5 two NaN three NaN Name: i, dtype: float64 </code></pre> <p>See where there's missing data:</p> <pre><code>&gt;&gt;&gt; pd.isnull(df2.iloc[-1]) one False two True three True Name: i, dtype: bool &gt;&gt;&gt; to_shift = pd.isnull(df2.iloc[-1]) </code></pre> <p>Select that portion of the frame:</p> <pre><code>&gt;&gt;&gt; df2.loc[:, to_shift] two three a -0.447225 0.240786 b NaN NaN c 1.736224 0.191835 d NaN NaN e -0.310505 2.121659 f 2.542979 -0.772117 g NaN NaN h -0.350395 0.825386 i NaN NaN </code></pre> <p>Shift it:</p> <pre><code>&gt;&gt;&gt; df2.loc[:, to_shift].shift(1) two three a NaN NaN b -0.447225 0.240786 c NaN NaN d 1.736224 0.191835 e NaN NaN f -0.310505 2.121659 g 2.542979 -0.772117 h NaN NaN i -0.350395 0.825386 </code></pre> <p>And fill the frame with the shifted data:</p> <pre><code>&gt;&gt;&gt; df2.loc[:, to_shift] = df2.loc[:, to_shift].shift(1) &gt;&gt;&gt; df2 one two three a -0.691010 NaN NaN b NaN -0.447225 0.240786 c 0.570639 NaN NaN d NaN 1.736224 0.191835 e 2.509598 NaN NaN f -2.053269 -0.310505 2.121659 g NaN 2.542979 -0.772117 h 1.812492 NaN NaN i 5.000000 -0.350395 0.825386 </code></pre>