@@ -304,14 +304,15 @@ def putmask(self, mask, new, inplace=False):
304
304
if self ._can_hold_element (new ):
305
305
new = self ._try_cast (new )
306
306
np .putmask (new_values , mask , new )
307
- # upcast me
308
- else :
307
+
308
+ # maybe upcast me
309
+ elif mask .any ():
309
310
# type of the new block
310
311
if ((isinstance (new , np .ndarray ) and issubclass (new .dtype , np .number )) or
311
312
isinstance (new , float )):
312
- typ = float
313
+ typ = np . float64
313
314
else :
314
- typ = object
315
+ typ = np . object_
315
316
316
317
# we need to exiplicty astype here to make a copy
317
318
new_values = new_values .astype (typ )
@@ -384,17 +385,16 @@ def shift(self, indexer, periods):
384
385
new_values [:, periods :] = fill_value
385
386
return make_block (new_values , self .items , self .ref_items )
386
387
387
- def where (self , func , other , cond = None , raise_on_error = True , try_cast = False ):
388
+ def eval (self , func , other , raise_on_error = True , try_cast = False ):
388
389
"""
389
- evaluate the block; return result block(s) from the result
390
+ evaluate the block; return result block from the result
390
391
391
392
Parameters
392
393
----------
393
394
func : how to combine self, other
394
395
other : a ndarray/object
395
- cond : the condition to respect, optional
396
- raise_on_error : if True, raise when I can't perform the function,
397
- False by default (and just return the data that we had coming in)
396
+ raise_on_error : if True, raise when I can't perform the function, False by default (and just return
397
+ the data that we had coming in)
398
398
399
399
Returns
400
400
-------
@@ -414,28 +414,7 @@ def where(self, func, other, cond = None, raise_on_error = True, try_cast = Fals
414
414
values = values .T
415
415
is_transposed = True
416
416
417
- # see if we can align cond
418
- if cond is not None :
419
- if not hasattr (cond , 'shape' ):
420
- raise ValueError ('where must have a condition that is ndarray'
421
- ' like' )
422
- if hasattr (cond , 'reindex_axis' ):
423
- axis = getattr (cond , '_het_axis' , 0 )
424
- cond = cond .reindex_axis (self .items , axis = axis ,
425
- copy = True ).values
426
- else :
427
- cond = cond .values
428
-
429
- # may need to undo transpose of values
430
- if hasattr (values , 'ndim' ):
431
- if (values .ndim != cond .ndim or
432
- values .shape == cond .shape [::- 1 ]):
433
- values = values .T
434
- is_transposed = not is_transposed
435
-
436
417
args = [ values , other ]
437
- if cond is not None :
438
- args .append (cond )
439
418
try :
440
419
result = func (* args )
441
420
except :
@@ -458,7 +437,106 @@ def where(self, func, other, cond = None, raise_on_error = True, try_cast = Fals
458
437
if try_cast :
459
438
result = self ._try_cast_result (result )
460
439
461
- return [ make_block (result , self .items , self .ref_items ) ]
440
+ return make_block (result , self .items , self .ref_items )
441
+
442
+ def where (self , other , cond , raise_on_error = True , try_cast = False ):
443
+ """
444
+ evaluate the block; return result block(s) from the result
445
+
446
+ Parameters
447
+ ----------
448
+ other : a ndarray/object
449
+ cond : the condition to respect
450
+ raise_on_error : if True, raise when I can't perform the function, False by default (and just return
451
+ the data that we had coming in)
452
+
453
+ Returns
454
+ -------
455
+ a new block(s), the result of the func
456
+ """
457
+
458
+ values = self .values
459
+
460
+ # see if we can align other
461
+ if hasattr (other ,'reindex_axis' ):
462
+ axis = getattr (other ,'_het_axis' ,0 )
463
+ other = other .reindex_axis (self .items , axis = axis , copy = True ).values
464
+
465
+ # make sure that we can broadcast
466
+ is_transposed = False
467
+ if hasattr (other , 'ndim' ) and hasattr (values , 'ndim' ):
468
+ if values .ndim != other .ndim or values .shape == other .shape [::- 1 ]:
469
+ values = values .T
470
+ is_transposed = True
471
+
472
+ # see if we can align cond
473
+ if not hasattr (cond ,'shape' ):
474
+ raise ValueError ("where must have a condition that is ndarray like" )
475
+ if hasattr (cond ,'reindex_axis' ):
476
+ axis = getattr (cond ,'_het_axis' ,0 )
477
+ cond = cond .reindex_axis (self .items , axis = axis , copy = True ).values
478
+ else :
479
+ cond = cond .values
480
+
481
+ # may need to undo transpose of values
482
+ if hasattr (values , 'ndim' ):
483
+ if values .ndim != cond .ndim or values .shape == cond .shape [::- 1 ]:
484
+ values = values .T
485
+ is_transposed = not is_transposed
486
+
487
+ # our where function
488
+ def func (c ,v ,o ):
489
+ if c .flatten ().all ():
490
+ return v
491
+
492
+ try :
493
+ return np .where (c ,v ,o )
494
+ except :
495
+ if raise_on_error :
496
+ raise TypeError ('Coulnd not operate %s with block values'
497
+ % repr (o ))
498
+ else :
499
+ # return the values
500
+ result = np .empty (v .shape ,dtype = 'float64' )
501
+ result .fill (np .nan )
502
+ return result
503
+
504
+ def create_block (result , items , transpose = True ):
505
+ if not isinstance (result , np .ndarray ):
506
+ raise TypeError ('Could not compare %s with block values'
507
+ % repr (other ))
508
+
509
+ if transpose and is_transposed :
510
+ result = result .T
511
+
512
+ # try to cast if requested
513
+ if try_cast :
514
+ result = self ._try_cast_result (result )
515
+
516
+ return make_block (result , items , self .ref_items )
517
+
518
+ # see if we can operate on the entire block, or need item-by-item
519
+ if not self ._can_hold_na :
520
+ axis = cond .ndim - 1
521
+ result_blocks = []
522
+ for item in self .items :
523
+ loc = self .items .get_loc (item )
524
+ item = self .items .take ([loc ])
525
+ v = values .take ([loc ],axis = axis )
526
+ c = cond .take ([loc ],axis = axis )
527
+ o = other .take ([loc ],axis = axis ) if hasattr (other ,'shape' ) else other
528
+
529
+ result = func (c ,v ,o )
530
+ if len (result ) == 1 :
531
+ result = np .repeat (result ,self .shape [1 :])
532
+
533
+ result = result .reshape (((1 ,) + self .shape [1 :]))
534
+ result_blocks .append (create_block (result , item , transpose = False ))
535
+
536
+ return result_blocks
537
+ else :
538
+ result = func (cond ,values ,other )
539
+ return create_block (result , self .items )
462
540
463
541
def _mask_missing (array , missing_values ):
464
542
if not isinstance (missing_values , (list , np .ndarray )):
@@ -840,6 +918,9 @@ def apply(self, f, *args, **kwargs):
840
918
def where (self , * args , ** kwargs ):
841
919
return self .apply ('where' , * args , ** kwargs )
842
920
921
+ def eval (self , * args , ** kwargs ):
922
+ return self .apply ('eval' , * args , ** kwargs )
923
+
843
924
def putmask (self , * args , ** kwargs ):
844
925
return self .apply ('putmask' , * args , ** kwargs )
845
926
0 commit comments