10
10
from pandas .core .groupby .base import transformation_kernels
11
11
from pandas .tests .frame .common import zip_frames
12
12
13
-
14
- def test_transform_ufunc (axis , float_frame ):
13
+ # tshift only works on time index and is deprecated
14
+ # There is no DataFrame.cumcount
15
+ frame_kernels = [
16
+ x for x in sorted (transformation_kernels ) if x not in ["tshift" , "cumcount" ]
17
+ ]
18
+
19
+
20
+ def unpack_obj (obj , klass , axis ):
21
+ """
22
+ Helper to ensure we have the right type of object for a test parametrized
23
+ over frame_or_series.
24
+ """
25
+ if klass is not DataFrame :
26
+ obj = obj ["A" ]
27
+ if axis != 0 :
28
+ pytest .skip (f"Test is only for DataFrame with axis={ axis } " )
29
+ return obj
30
+
31
+
32
+ def test_transform_ufunc (axis , float_frame , frame_or_series ):
15
33
# GH 35964
34
+ obj = unpack_obj (float_frame , frame_or_series , axis )
35
+
16
36
with np .errstate (all = "ignore" ):
17
- f_sqrt = np .sqrt (float_frame )
18
- result = float_frame .transform (np .sqrt , axis = axis )
37
+ f_sqrt = np .sqrt (obj )
38
+
39
+ # ufunc
40
+ result = obj .transform (np .sqrt , axis = axis )
19
41
expected = f_sqrt
20
- tm .assert_frame_equal (result , expected )
42
+ tm .assert_equal (result , expected )
21
43
22
44
23
- @pytest .mark .parametrize ("op" , sorted ( transformation_kernels ) )
45
+ @pytest .mark .parametrize ("op" , frame_kernels )
24
46
def test_transform_groupby_kernel (axis , float_frame , op ):
25
47
# GH 35964
26
- if op == "cumcount" :
27
- pytest .xfail ("DataFrame.cumcount does not exist" )
28
- if op == "tshift" :
29
- pytest .xfail ("Only works on time index and is deprecated" )
30
48
31
49
args = [0.0 ] if op == "fillna" else []
32
50
if axis == 0 or axis == "index" :
@@ -61,9 +79,11 @@ def test_transform_listlike(axis, float_frame, ops, names):
61
79
62
80
63
81
@pytest .mark .parametrize ("ops" , [[], np .array ([])])
64
- def test_transform_empty_listlike (float_frame , ops ):
82
+ def test_transform_empty_listlike (float_frame , ops , frame_or_series ):
83
+ obj = unpack_obj (float_frame , frame_or_series , 0 )
84
+
65
85
with pytest .raises (ValueError , match = "No transform functions were provided" ):
66
- float_frame .transform (ops )
86
+ obj .transform (ops )
67
87
68
88
69
89
@pytest .mark .parametrize ("box" , [dict , Series ])
@@ -90,25 +110,29 @@ def test_transform_dictlike(axis, float_frame, box):
90
110
{"A" : ["cumsum" ], "B" : []},
91
111
],
92
112
)
93
- def test_transform_empty_dictlike (float_frame , ops ):
113
+ def test_transform_empty_dictlike (float_frame , ops , frame_or_series ):
114
+ obj = unpack_obj (float_frame , frame_or_series , 0 )
115
+
94
116
with pytest .raises (ValueError , match = "No transform functions were provided" ):
95
- float_frame .transform (ops )
117
+ obj .transform (ops )
96
118
97
119
98
120
@pytest .mark .parametrize ("use_apply" , [True , False ])
99
- def test_transform_udf (axis , float_frame , use_apply ):
121
+ def test_transform_udf (axis , float_frame , use_apply , frame_or_series ):
100
122
# GH 35964
123
+ obj = unpack_obj (float_frame , frame_or_series , axis )
124
+
101
125
# transform uses UDF either via apply or passing the entire DataFrame
102
126
def func (x ):
103
127
# transform is using apply iff x is not a DataFrame
104
- if use_apply == isinstance (x , DataFrame ):
128
+ if use_apply == isinstance (x , frame_or_series ):
105
129
# Force transform to fallback
106
130
raise ValueError
107
131
return x + 1
108
132
109
- result = float_frame .transform (func , axis = axis )
110
- expected = float_frame + 1
111
- tm .assert_frame_equal (result , expected )
133
+ result = obj .transform (func , axis = axis )
134
+ expected = obj + 1
135
+ tm .assert_equal (result , expected )
112
136
113
137
114
138
@pytest .mark .parametrize ("method" , ["abs" , "shift" , "pct_change" , "cumsum" , "rank" ])
@@ -142,54 +166,56 @@ def test_agg_dict_nested_renaming_depr():
142
166
df .transform ({"A" : {"foo" : "min" }, "B" : {"bar" : "max" }})
143
167
144
168
145
- def test_transform_reducer_raises (all_reductions ):
169
+ def test_transform_reducer_raises (all_reductions , frame_or_series ):
146
170
# GH 35964
147
171
op = all_reductions
148
- df = DataFrame ({"A" : [1 , 2 , 3 ]})
172
+
173
+ obj = DataFrame ({"A" : [1 , 2 , 3 ]})
174
+ if frame_or_series is not DataFrame :
175
+ obj = obj ["A" ]
176
+
149
177
msg = "Function did not transform"
150
178
with pytest .raises (ValueError , match = msg ):
151
- df .transform (op )
179
+ obj .transform (op )
152
180
with pytest .raises (ValueError , match = msg ):
153
- df .transform ([op ])
181
+ obj .transform ([op ])
154
182
with pytest .raises (ValueError , match = msg ):
155
- df .transform ({"A" : op })
183
+ obj .transform ({"A" : op })
156
184
with pytest .raises (ValueError , match = msg ):
157
- df .transform ({"A" : [op ]})
185
+ obj .transform ({"A" : [op ]})
186
+
187
+
188
+ wont_fail = ["ffill" , "bfill" , "fillna" , "pad" , "backfill" , "shift" ]
189
+ frame_kernels_raise = [x for x in frame_kernels if x not in wont_fail ]
158
190
159
191
160
192
# mypy doesn't allow adding lists of different types
161
193
# https://github.com/python/mypy/issues/5492
162
- @pytest .mark .parametrize ("op" , [* sorted ( transformation_kernels ) , lambda x : x + 1 ])
163
- def test_transform_bad_dtype (op ):
194
+ @pytest .mark .parametrize ("op" , [* frame_kernels_raise , lambda x : x + 1 ])
195
+ def test_transform_bad_dtype (op , frame_or_series ):
164
196
# GH 35964
165
- df = DataFrame ({"A" : 3 * [object ]}) # DataFrame that will fail on most transforms
166
- if op in ("backfill" , "shift" , "pad" , "bfill" , "ffill" ):
167
- pytest .xfail ("Transform function works on any datatype" )
197
+ obj = DataFrame ({"A" : 3 * [object ]}) # DataFrame that will fail on most transforms
198
+ if frame_or_series is not DataFrame :
199
+ obj = obj ["A" ]
200
+
168
201
msg = "Transform function failed"
169
202
170
203
# tshift is deprecated
171
204
warn = None if op != "tshift" else FutureWarning
172
205
with tm .assert_produces_warning (warn , check_stacklevel = False ):
173
206
with pytest .raises (ValueError , match = msg ):
174
- df .transform (op )
207
+ obj .transform (op )
175
208
with pytest .raises (ValueError , match = msg ):
176
- df .transform ([op ])
209
+ obj .transform ([op ])
177
210
with pytest .raises (ValueError , match = msg ):
178
- df .transform ({"A" : op })
211
+ obj .transform ({"A" : op })
179
212
with pytest .raises (ValueError , match = msg ):
180
- df .transform ({"A" : [op ]})
213
+ obj .transform ({"A" : [op ]})
181
214
182
215
183
- @pytest .mark .parametrize ("op" , sorted ( transformation_kernels ) )
216
+ @pytest .mark .parametrize ("op" , frame_kernels_raise )
184
217
def test_transform_partial_failure (op ):
185
218
# GH 35964
186
- wont_fail = ["ffill" , "bfill" , "fillna" , "pad" , "backfill" , "shift" ]
187
- if op in wont_fail :
188
- pytest .xfail ("Transform kernel is successful on all dtypes" )
189
- if op == "cumcount" :
190
- pytest .xfail ("transform('cumcount') not implemented" )
191
- if op == "tshift" :
192
- pytest .xfail ("Only works on time index; deprecated" )
193
219
194
220
# Using object makes most transform kernels fail
195
221
df = DataFrame ({"A" : 3 * [object ], "B" : [1 , 2 , 3 ]})
@@ -208,22 +234,22 @@ def test_transform_partial_failure(op):
208
234
209
235
210
236
@pytest .mark .parametrize ("use_apply" , [True , False ])
211
- def test_transform_passes_args (use_apply ):
237
+ def test_transform_passes_args (use_apply , frame_or_series ):
212
238
# GH 35964
213
239
# transform uses UDF either via apply or passing the entire DataFrame
214
240
expected_args = [1 , 2 ]
215
241
expected_kwargs = {"c" : 3 }
216
242
217
243
def f (x , a , b , c ):
218
244
# transform is using apply iff x is not a DataFrame
219
- if use_apply == isinstance (x , DataFrame ):
245
+ if use_apply == isinstance (x , frame_or_series ):
220
246
# Force transform to fallback
221
247
raise ValueError
222
248
assert [a , b ] == expected_args
223
249
assert c == expected_kwargs ["c" ]
224
250
return x
225
251
226
- DataFrame ([1 ]).transform (f , 0 , * expected_args , ** expected_kwargs )
252
+ frame_or_series ([1 ]).transform (f , 0 , * expected_args , ** expected_kwargs )
227
253
228
254
229
255
def test_transform_missing_columns (axis ):
0 commit comments