@@ -188,6 +188,78 @@ def _get_frame_op_default_axis(name):
188
188
return 'columns'
189
189
190
190
191
+ def _get_opstr (op , cls ):
192
+ """
193
+ Find the operation string, if any, to pass to numexpr for this
194
+ operation.
195
+
196
+ Parameters
197
+ ----------
198
+ op : binary operator
199
+ cls : class
200
+
201
+ Returns
202
+ -------
203
+ op_str : string or None
204
+ """
205
+ # numexpr is available for non-sparse classes
206
+ subtyp = getattr (cls , '_subtyp' , '' )
207
+ use_numexpr = 'sparse' not in subtyp
208
+
209
+ if not use_numexpr :
210
+ # if we're not using numexpr, then don't pass a str_rep
211
+ return None
212
+
213
+ return {operator .add : '+' ,
214
+ radd : '+' ,
215
+ operator .mul : '*' ,
216
+ rmul : '*' ,
217
+ operator .sub : '-' ,
218
+ rsub : '-' ,
219
+ operator .truediv : '/' ,
220
+ rtruediv : '/' ,
221
+ operator .floordiv : '//' ,
222
+ rfloordiv : '//' ,
223
+ operator .mod : None , # TODO: Why None for mod but '%' for rmod?
224
+ rmod : '%' ,
225
+ operator .pow : '**' ,
226
+ rpow : '**' ,
227
+ operator .eq : '==' ,
228
+ operator .ne : '!=' ,
229
+ operator .le : '<=' ,
230
+ operator .lt : '<' ,
231
+ operator .ge : '>=' ,
232
+ operator .gt : '>' ,
233
+ operator .and_ : '&' ,
234
+ rand_ : '&' ,
235
+ operator .or_ : '|' ,
236
+ ror_ : '|' ,
237
+ operator .xor : '^' ,
238
+ rxor : '^' ,
239
+ divmod : None ,
240
+ rdivmod : None }[op ]
241
+
242
+
243
+ def _get_op_name (op , special ):
244
+ """
245
+ Find the name to attach to this method according to conventions
246
+ for special and non-special methods.
247
+
248
+ Parameters
249
+ ----------
250
+ op : binary operator
251
+ special : bool
252
+
253
+ Returns
254
+ -------
255
+ op_name : str
256
+ """
257
+ opname = op .__name__ .strip ('_' )
258
+ if special :
259
+ opname = '__{opname}__' .format (opname = opname )
260
+ return opname
261
+
262
+
191
263
# -----------------------------------------------------------------------------
192
264
# Docstring Generation and Templates
193
265
@@ -408,75 +480,56 @@ def _create_methods(cls, arith_method, comp_method, bool_method,
408
480
# creates actual methods based upon arithmetic, comp and bool method
409
481
# constructors.
410
482
411
- # numexpr is available for non-sparse classes
412
- subtyp = getattr (cls , '_subtyp' , '' )
413
- use_numexpr = 'sparse' not in subtyp
414
-
415
483
have_divmod = issubclass (cls , ABCSeries )
416
484
# divmod is available for Series and SparseSeries
417
485
418
- # if we're not using numexpr, then don't pass a str_rep
419
- if use_numexpr :
420
- op = lambda x : x
421
- else :
422
- op = lambda x : None
423
- if special :
424
-
425
- def names (x ):
426
- if x [- 1 ] == "_" :
427
- return "__{name}_" .format (name = x )
428
- else :
429
- return "__{name}__" .format (name = x )
430
- else :
431
- names = lambda x : x
432
-
433
486
# yapf: disable
434
487
new_methods = dict (
435
- add = arith_method (operator .add , names ( 'add' ), op ( '+' ) ),
436
- radd = arith_method (radd , names ( ' radd' ), op ( '+' ) ),
437
- sub = arith_method (operator .sub , names ( 'sub' ), op ( '-' ) ),
438
- mul = arith_method (operator .mul , names ( 'mul' ), op ( '*' ) ),
439
- truediv = arith_method (operator .truediv , names ( 'truediv' ), op ( '/' ) ),
440
- floordiv = arith_method (operator .floordiv , names ( 'floordiv' ), op ( '//' ) ),
488
+ add = arith_method (cls , operator .add , special ),
489
+ radd = arith_method (cls , radd , special ),
490
+ sub = arith_method (cls , operator .sub , special ),
491
+ mul = arith_method (cls , operator .mul , special ),
492
+ truediv = arith_method (cls , operator .truediv , special ),
493
+ floordiv = arith_method (cls , operator .floordiv , special ),
441
494
# Causes a floating point exception in the tests when numexpr enabled,
442
495
# so for now no speedup
443
- mod = arith_method (operator .mod , names ( 'mod' ), None ),
444
- pow = arith_method (operator .pow , names ( 'pow' ), op ( '**' ) ),
496
+ mod = arith_method (cls , operator .mod , special ),
497
+ pow = arith_method (cls , operator .pow , special ),
445
498
# not entirely sure why this is necessary, but previously was included
446
499
# so it's here to maintain compatibility
447
- rmul = arith_method (operator . mul , names ( ' rmul' ), op ( '*' ) ),
448
- rsub = arith_method (rsub , names ( ' rsub' ), op ( '-' ) ),
449
- rtruediv = arith_method (rtruediv , names ( ' rtruediv' ), op ( '/' ) ),
450
- rfloordiv = arith_method (rfloordiv , names ( ' rfloordiv' ), op ( '//' ) ),
451
- rpow = arith_method (rpow , names ( ' rpow' ), op ( '**' ) ),
452
- rmod = arith_method (rmod , names ( ' rmod' ), op ( '%' ) ))
500
+ rmul = arith_method (cls , rmul , special ),
501
+ rsub = arith_method (cls , rsub , special ),
502
+ rtruediv = arith_method (cls , rtruediv , special ),
503
+ rfloordiv = arith_method (cls , rfloordiv , special ),
504
+ rpow = arith_method (cls , rpow , special ),
505
+ rmod = arith_method (cls , rmod , special ))
453
506
# yapf: enable
454
507
new_methods ['div' ] = new_methods ['truediv' ]
455
508
new_methods ['rdiv' ] = new_methods ['rtruediv' ]
456
509
457
510
# Comp methods never had a default axis set
458
511
if comp_method :
459
512
new_methods .update (dict (
460
- eq = comp_method (operator .eq , names ( 'eq' ), op ( '==' ) ),
461
- ne = comp_method (operator .ne , names ( 'ne' ), op ( '!=' ) ),
462
- lt = comp_method (operator .lt , names ( 'lt' ), op ( '<' ) ),
463
- gt = comp_method (operator .gt , names ( 'gt' ), op ( '>' ) ),
464
- le = comp_method (operator .le , names ( 'le' ), op ( '<=' ) ),
465
- ge = comp_method (operator .ge , names ( 'ge' ), op ( '>=' ) )))
513
+ eq = comp_method (cls , operator .eq , special ),
514
+ ne = comp_method (cls , operator .ne , special ),
515
+ lt = comp_method (cls , operator .lt , special ),
516
+ gt = comp_method (cls , operator .gt , special ),
517
+ le = comp_method (cls , operator .le , special ),
518
+ ge = comp_method (cls , operator .ge , special )))
466
519
if bool_method :
467
520
new_methods .update (
468
- dict (and_ = bool_method (operator .and_ , names ( 'and_' ), op ( '&' ) ),
469
- or_ = bool_method (operator .or_ , names ( 'or_' ), op ( '|' ) ),
521
+ dict (and_ = bool_method (cls , operator .and_ , special ),
522
+ or_ = bool_method (cls , operator .or_ , special ),
470
523
# For some reason ``^`` wasn't used in original.
471
- xor = bool_method (operator .xor , names ( 'xor' ), op ( '^' ) ),
472
- rand_ = bool_method (rand_ , names ( ' rand_' ), op ( '&' ) ),
473
- ror_ = bool_method (ror_ , names ( ' ror_' ), op ( '|' ) ),
474
- rxor = bool_method (rxor , names ( ' rxor' ), op ( '^' ) )))
524
+ xor = bool_method (cls , operator .xor , special ),
525
+ rand_ = bool_method (cls , rand_ , special ),
526
+ ror_ = bool_method (cls , ror_ , special ),
527
+ rxor = bool_method (cls , rxor , special )))
475
528
if have_divmod :
476
529
# divmod doesn't have an op that is supported by numexpr
477
- new_methods ['divmod' ] = arith_method (divmod , names ( ' divmod' ), None )
530
+ new_methods ['divmod' ] = arith_method (cls , divmod , special )
478
531
479
- new_methods = {names ( k ) : v for k , v in new_methods .items ()}
532
+ new_methods = {v . __name__ : v for k , v in new_methods .items ()}
480
533
return new_methods
481
534
482
535
@@ -503,12 +556,12 @@ def add_special_arithmetic_methods(cls, arith_method=None,
503
556
Parameters
504
557
----------
505
558
arith_method : function (optional)
506
- factory for special arithmetic methods, with op string :
507
- f(op, name, str_rep )
559
+ factory for special arithmetic methods:
560
+ f(cls, op, special )
508
561
comp_method : function (optional)
509
- factory for rich comparison - signature: f(op, name, str_rep )
562
+ factory for rich comparison - signature: f(cls, op, special )
510
563
bool_method : function (optional)
511
- factory for boolean methods - signature: f(op, name, str_rep )
564
+ factory for boolean methods - signature: f(cls, op, special )
512
565
"""
513
566
new_methods = _create_methods (cls , arith_method , comp_method , bool_method ,
514
567
special = True )
@@ -552,22 +605,21 @@ def f(self, other):
552
605
add_methods (cls , new_methods = new_methods )
553
606
554
607
555
- def add_flex_arithmetic_methods (cls , flex_arith_method ,
556
- flex_comp_method = None , flex_bool_method = None ):
608
+ def add_flex_arithmetic_methods (cls , flex_arith_method , flex_comp_method = None ):
557
609
"""
558
610
Adds the full suite of flex arithmetic methods (``pow``, ``mul``, ``add``)
559
611
to the class.
560
612
561
613
Parameters
562
614
----------
563
615
flex_arith_method : function
564
- factory for flex arithmetic methods, with op string :
565
- f(op, name, str_rep )
616
+ factory for flex arithmetic methods:
617
+ f(cls, op, special )
566
618
flex_comp_method : function, optional,
567
- factory for rich comparison - signature: f(op, name, str_rep )
619
+ factory for rich comparison - signature: f(cls, op, special )
568
620
"""
569
621
new_methods = _create_methods (cls , flex_arith_method ,
570
- flex_comp_method , flex_bool_method ,
622
+ flex_comp_method , bool_method = None ,
571
623
special = False )
572
624
new_methods .update (dict (multiply = new_methods ['mul' ],
573
625
subtract = new_methods ['sub' ],
@@ -626,11 +678,13 @@ def _construct_divmod_result(left, result, index, name, dtype):
626
678
)
627
679
628
680
629
- def _arith_method_SERIES (op , name , str_rep ):
681
+ def _arith_method_SERIES (cls , op , special ):
630
682
"""
631
683
Wrapper function for Series arithmetic operations, to avoid
632
684
code duplication.
633
685
"""
686
+ str_rep = _get_opstr (op , cls )
687
+ name = _get_op_name (op , special )
634
688
eval_kwargs = _gen_eval_kwargs (name )
635
689
fill_zeros = _gen_fill_zeros (name )
636
690
construct_result = (_construct_divmod_result
@@ -763,11 +817,12 @@ def _comp_method_OBJECT_ARRAY(op, x, y):
763
817
return result
764
818
765
819
766
- def _comp_method_SERIES (op , name , str_rep ):
820
+ def _comp_method_SERIES (cls , op , special ):
767
821
"""
768
822
Wrapper function for Series arithmetic operations, to avoid
769
823
code duplication.
770
824
"""
825
+ name = _get_op_name (op , special )
771
826
masker = _gen_eval_kwargs (name ).get ('masker' , False )
772
827
773
828
def na_op (x , y ):
@@ -890,7 +945,7 @@ def wrapper(self, other, axis=None):
890
945
return wrapper
891
946
892
947
893
- def _bool_method_SERIES (op , name , str_rep ):
948
+ def _bool_method_SERIES (cls , op , special ):
894
949
"""
895
950
Wrapper function for Series arithmetic operations, to avoid
896
951
code duplication.
@@ -961,7 +1016,8 @@ def wrapper(self, other):
961
1016
return wrapper
962
1017
963
1018
964
- def _flex_method_SERIES (op , name , str_rep ):
1019
+ def _flex_method_SERIES (cls , op , special ):
1020
+ name = _get_op_name (op , special )
965
1021
doc = _make_flex_doc (name , 'series' )
966
1022
967
1023
@Appender (doc )
@@ -1042,7 +1098,9 @@ def to_series(right):
1042
1098
return right
1043
1099
1044
1100
1045
- def _arith_method_FRAME (op , name , str_rep = None ):
1101
+ def _arith_method_FRAME (cls , op , special ):
1102
+ str_rep = _get_opstr (op , cls )
1103
+ name = _get_op_name (op , special )
1046
1104
eval_kwargs = _gen_eval_kwargs (name )
1047
1105
fill_zeros = _gen_fill_zeros (name )
1048
1106
default_axis = _get_frame_op_default_axis (name )
@@ -1119,7 +1177,9 @@ def f(self, other, axis=default_axis, level=None, fill_value=None):
1119
1177
return f
1120
1178
1121
1179
1122
- def _flex_comp_method_FRAME (op , name , str_rep = None ):
1180
+ def _flex_comp_method_FRAME (cls , op , special ):
1181
+ str_rep = _get_opstr (op , cls )
1182
+ name = _get_op_name (op , special )
1123
1183
default_axis = _get_frame_op_default_axis (name )
1124
1184
1125
1185
def na_op (x , y ):
@@ -1167,7 +1227,10 @@ def f(self, other, axis=default_axis, level=None):
1167
1227
return f
1168
1228
1169
1229
1170
- def _comp_method_FRAME (func , name , str_rep ):
1230
+ def _comp_method_FRAME (cls , func , special ):
1231
+ str_rep = _get_opstr (func , cls )
1232
+ name = _get_op_name (func , special )
1233
+
1171
1234
@Appender ('Wrapper for comparison method {name}' .format (name = name ))
1172
1235
def f (self , other ):
1173
1236
if isinstance (other , ABCDataFrame ): # Another DataFrame
@@ -1200,8 +1263,10 @@ def f(self, other):
1200
1263
# -----------------------------------------------------------------------------
1201
1264
# Panel
1202
1265
1203
- def _arith_method_PANEL (op , name , str_rep = None ):
1266
+ def _arith_method_PANEL (cls , op , special ):
1204
1267
# work only for scalars
1268
+ name = _get_op_name (op , special )
1269
+
1205
1270
def f (self , other ):
1206
1271
if not is_scalar (other ):
1207
1272
raise ValueError ('Simple arithmetic with {name} can only be '
@@ -1214,7 +1279,10 @@ def f(self, other):
1214
1279
return f
1215
1280
1216
1281
1217
- def _comp_method_PANEL (op , name , str_rep = None ):
1282
+ def _comp_method_PANEL (cls , op , special ):
1283
+ str_rep = _get_opstr (op , cls )
1284
+ name = _get_op_name (op , special )
1285
+
1218
1286
def na_op (x , y ):
1219
1287
import pandas .core .computation .expressions as expressions
1220
1288
@@ -1260,7 +1328,9 @@ def f(self, other, axis=None):
1260
1328
return f
1261
1329
1262
1330
1263
- def _flex_method_PANEL (op , name , str_rep = None ):
1331
+ def _flex_method_PANEL (cls , op , special ):
1332
+ str_rep = _get_opstr (op , cls )
1333
+ name = _get_op_name (op , special )
1264
1334
eval_kwargs = _gen_eval_kwargs (name )
1265
1335
fill_zeros = _gen_fill_zeros (name )
1266
1336
@@ -1298,18 +1368,19 @@ def f(self, other, axis=0):
1298
1368
comp_method = _comp_method_PANEL ,
1299
1369
bool_method = _arith_method_PANEL )
1300
1370
1371
+ panel_flex_funcs = dict (arith_method = _flex_method_PANEL ,
1372
+ flex_comp_method = _comp_method_PANEL )
1301
1373
1302
1374
# -----------------------------------------------------------------------------
1303
1375
# Sparse
1304
1376
1305
1377
1306
- def _arith_method_SPARSE_SERIES (op , name , str_rep = None ):
1378
+ def _arith_method_SPARSE_SERIES (cls , op , special ):
1307
1379
"""
1308
1380
Wrapper function for Series arithmetic operations, to avoid
1309
1381
code duplication.
1310
-
1311
- str_rep is not used, but is present for compatibility.
1312
1382
"""
1383
+ name = _get_op_name (op , special )
1313
1384
1314
1385
def wrapper (self , other ):
1315
1386
if isinstance (other , ABCDataFrame ):
@@ -1347,11 +1418,12 @@ def _sparse_series_op(left, right, op, name):
1347
1418
return left ._constructor (result , index = new_index , name = new_name )
1348
1419
1349
1420
1350
- def _arith_method_SPARSE_ARRAY (op , name , str_rep = None ):
1421
+ def _arith_method_SPARSE_ARRAY (cls , op , special ):
1351
1422
"""
1352
1423
Wrapper function for Series arithmetic operations, to avoid
1353
1424
code duplication.
1354
1425
"""
1426
+ name = _get_op_name (op , special )
1355
1427
1356
1428
def wrapper (self , other ):
1357
1429
from pandas .core .sparse .array import (
@@ -1379,3 +1451,12 @@ def wrapper(self, other):
1379
1451
name = name [2 :- 2 ]
1380
1452
wrapper .__name__ = name
1381
1453
return wrapper
1454
+
1455
+
1456
+ sparse_array_special_funcs = dict (arith_method = _arith_method_SPARSE_ARRAY ,
1457
+ comp_method = _arith_method_SPARSE_ARRAY ,
1458
+ bool_method = _arith_method_SPARSE_ARRAY )
1459
+
1460
+ sparse_series_special_funcs = dict (arith_method = _arith_method_SPARSE_SERIES ,
1461
+ comp_method = _arith_method_SPARSE_SERIES ,
1462
+ bool_method = None )
0 commit comments