@@ -5080,28 +5080,45 @@ def shift(
5080
5080
axis = self ._get_axis_number (axis )
5081
5081
5082
5082
ncols = len (self .columns )
5083
- if axis == 1 and periods != 0 and fill_value is lib .no_default and ncols > 0 :
5084
- # We will infer fill_value to match the closest column
5085
5083
5086
- # Use a column that we know is valid for our column's dtype GH#38434
5087
- label = self .columns [0 ]
5084
+ if (
5085
+ axis == 1
5086
+ and periods != 0
5087
+ and ncols > 0
5088
+ and (fill_value is lib .no_default or len (self ._mgr .arrays ) > 1 )
5089
+ ):
5090
+ # Exclude single-array-with-fill_value case so we issue a FutureWarning
5091
+ # if an integer is passed with datetimelike dtype GH#31971
5092
+ from pandas import concat
5088
5093
5094
+ # tail: the data that is still in our shifted DataFrame
5089
5095
if periods > 0 :
5090
- result = self .iloc [:, :- periods ]
5091
- for col in range (min (ncols , abs (periods ))):
5092
- # TODO(EA2D): doing this in a loop unnecessary with 2D EAs
5093
- # Define filler inside loop so we get a copy
5094
- filler = self .iloc [:, 0 ].shift (len (self ))
5095
- result .insert (0 , label , filler , allow_duplicates = True )
5096
+ tail = self .iloc [:, :- periods ]
5096
5097
else :
5097
- result = self .iloc [:, - periods :]
5098
- for col in range (min (ncols , abs (periods ))):
5099
- # Define filler inside loop so we get a copy
5100
- filler = self .iloc [:, - 1 ].shift (len (self ))
5101
- result .insert (
5102
- len (result .columns ), label , filler , allow_duplicates = True
5103
- )
5098
+ tail = self .iloc [:, - periods :]
5099
+ # pin a simple Index to avoid costly casting
5100
+ tail .columns = range (len (tail .columns ))
5101
+
5102
+ if fill_value is not lib .no_default :
5103
+ # GH#35488
5104
+ # TODO(EA2D): with 2D EAs we could construct other directly
5105
+ ser = Series (fill_value , index = self .index )
5106
+ else :
5107
+ # We infer fill_value to match the closest column
5108
+ if periods > 0 :
5109
+ ser = self .iloc [:, 0 ].shift (len (self ))
5110
+ else :
5111
+ ser = self .iloc [:, - 1 ].shift (len (self ))
5112
+
5113
+ width = min (abs (periods ), ncols )
5114
+ other = concat ([ser ] * width , axis = 1 )
5115
+
5116
+ if periods > 0 :
5117
+ result = concat ([other , tail ], axis = 1 )
5118
+ else :
5119
+ result = concat ([tail , other ], axis = 1 )
5104
5120
5121
+ result = cast (DataFrame , result )
5105
5122
result .columns = self .columns .copy ()
5106
5123
return result
5107
5124
0 commit comments