@@ -632,7 +632,8 @@ def _is_empty_indexer(indexer):
632
632
633
633
return [self ]
634
634
635
- def putmask (self , mask , new , align = True , inplace = False ):
635
+ def putmask (self , mask , new , align = True , inplace = False ,
636
+ axis = 0 , transpose = False ):
636
637
""" putmask the data to the block; it is possible that we may create a
637
638
new dtype of block
638
639
@@ -644,37 +645,55 @@ def putmask(self, mask, new, align=True, inplace=False):
644
645
new : a ndarray/object
645
646
align : boolean, perform alignment on other/cond, default is True
646
647
inplace : perform inplace modification, default is False
648
+ axis : int
649
+ transpose : boolean
650
+ Set to True if self is stored with axes reversed
647
651
648
652
Returns
649
653
-------
650
- a new block(s) , the result of the putmask
654
+ a list of new blocks , the result of the putmask
651
655
"""
652
656
653
657
new_values = self .values if inplace else self .values .copy ()
654
658
655
- # may need to align the new
656
659
if hasattr (new , 'reindex_axis' ):
657
- new = new .values . T
660
+ new = new .values
658
661
659
- # may need to align the mask
660
662
if hasattr (mask , 'reindex_axis' ):
661
- mask = mask .values . T
663
+ mask = mask .values
662
664
663
665
# if we are passed a scalar None, convert it here
664
666
if not is_list_like (new ) and isnull (new ) and not self .is_object :
665
667
new = self .fill_value
666
668
667
669
if self ._can_hold_element (new ):
670
+ if transpose :
671
+ new_values = new_values .T
672
+
668
673
new = self ._try_cast (new )
669
674
670
- # pseudo-broadcast
671
- if isinstance (new , np .ndarray ) and new .ndim == self .ndim - 1 :
672
- new = np .repeat (new , self .shape [- 1 ]).reshape (self .shape )
675
+ # If the default repeat behavior in np.putmask would go in the wrong
676
+ # direction, then explictly repeat and reshape new instead
677
+ if getattr (new , 'ndim' , 0 ) >= 1 :
678
+ if self .ndim - 1 == new .ndim and axis == 1 :
679
+ new = np .repeat (new , new_values .shape [- 1 ]).reshape (self .shape )
673
680
674
681
np .putmask (new_values , mask , new )
675
682
676
683
# maybe upcast me
677
684
elif mask .any ():
685
+ if transpose :
686
+ mask = mask .T
687
+ if isinstance (new , np .ndarray ):
688
+ new = new .T
689
+ axis = new_values .ndim - axis - 1
690
+
691
+ # Pseudo-broadcast
692
+ if getattr (new , 'ndim' , 0 ) >= 1 :
693
+ if self .ndim - 1 == new .ndim :
694
+ new_shape = list (new .shape )
695
+ new_shape .insert (axis , 1 )
696
+ new = new .reshape (tuple (new_shape ))
678
697
679
698
# need to go column by column
680
699
new_blocks = []
@@ -685,14 +704,15 @@ def putmask(self, mask, new, align=True, inplace=False):
685
704
686
705
# need a new block
687
706
if m .any ():
688
-
689
- n = new [i ] if isinstance (
690
- new , np .ndarray ) else np .array (new )
707
+ if isinstance (new , np .ndarray ):
708
+ n = np .squeeze (new [i % new .shape [0 ]])
709
+ else :
710
+ n = np .array (new )
691
711
692
712
# type of the new block
693
713
dtype , _ = com ._maybe_promote (n .dtype )
694
714
695
- # we need to exiplicty astype here to make a copy
715
+ # we need to explicitly astype here to make a copy
696
716
n = n .astype (dtype )
697
717
698
718
nv = _putmask_smart (v , m , n )
@@ -718,8 +738,10 @@ def putmask(self, mask, new, align=True, inplace=False):
718
738
if inplace :
719
739
return [self ]
720
740
721
- return [make_block (new_values ,
722
- placement = self .mgr_locs , fastpath = True )]
741
+ if transpose :
742
+ new_values = new_values .T
743
+
744
+ return [make_block (new_values , placement = self .mgr_locs , fastpath = True )]
723
745
724
746
def interpolate (self , method = 'pad' , axis = 0 , index = None ,
725
747
values = None , inplace = False , limit = None ,
@@ -1003,7 +1025,7 @@ def handle_error():
1003
1025
fastpath = True , placement = self .mgr_locs )]
1004
1026
1005
1027
def where (self , other , cond , align = True , raise_on_error = True ,
1006
- try_cast = False ):
1028
+ try_cast = False , axis = 0 , transpose = False ):
1007
1029
"""
1008
1030
evaluate the block; return result block(s) from the result
1009
1031
@@ -1014,50 +1036,33 @@ def where(self, other, cond, align=True, raise_on_error=True,
1014
1036
align : boolean, perform alignment on other/cond
1015
1037
raise_on_error : if True, raise when I can't perform the function,
1016
1038
False by default (and just return the data that we had coming in)
1039
+ axis : int
1040
+ transpose : boolean
1041
+ Set to True if self is stored with axes reversed
1017
1042
1018
1043
Returns
1019
1044
-------
1020
1045
a new block(s), the result of the func
1021
1046
"""
1022
1047
1023
1048
values = self .values
1049
+ if transpose :
1050
+ values = values .T
1024
1051
1025
- # see if we can align other
1026
1052
if hasattr (other , 'reindex_axis' ):
1027
1053
other = other .values
1028
1054
1029
- # make sure that we can broadcast
1030
- is_transposed = False
1031
- if hasattr (other , 'ndim' ) and hasattr (values , 'ndim' ):
1032
- if values .ndim != other .ndim or values .shape == other .shape [::- 1 ]:
1033
-
1034
- # if its symmetric are ok, no reshaping needed (GH 7506)
1035
- if (values .shape [0 ] == np .array (values .shape )).all ():
1036
- pass
1037
-
1038
- # pseodo broadcast (its a 2d vs 1d say and where needs it in a
1039
- # specific direction)
1040
- elif (other .ndim >= 1 and values .ndim - 1 == other .ndim and
1041
- values .shape [0 ] != other .shape [0 ]):
1042
- other = _block_shape (other ).T
1043
- else :
1044
- values = values .T
1045
- is_transposed = True
1046
-
1047
- # see if we can align cond
1048
- if not hasattr (cond , 'shape' ):
1049
- raise ValueError (
1050
- "where must have a condition that is ndarray like" )
1051
-
1052
1055
if hasattr (cond , 'reindex_axis' ):
1053
1056
cond = cond .values
1054
1057
1055
- # may need to undo transpose of values
1056
- if hasattr (values , 'ndim' ):
1057
- if values .ndim != cond .ndim or values .shape == cond .shape [::- 1 ]:
1058
+ # If the default broadcasting would go in the wrong direction, then
1059
+ # explictly reshape other instead
1060
+ if getattr (other , 'ndim' , 0 ) >= 1 :
1061
+ if values .ndim - 1 == other .ndim and axis == 1 :
1062
+ other = other .reshape (tuple (other .shape + (1 ,)))
1058
1063
1059
- values = values . T
1060
- is_transposed = not is_transposed
1064
+ if not hasattr ( cond , 'shape' ):
1065
+ raise ValueError ( "where must have a condition that is ndarray like" )
1061
1066
1062
1067
other = _maybe_convert_string_to_object (other )
1063
1068
@@ -1090,15 +1095,14 @@ def func(c, v, o):
1090
1095
raise TypeError ('Could not compare [%s] with block values'
1091
1096
% repr (other ))
1092
1097
1093
- if is_transposed :
1098
+ if transpose :
1094
1099
result = result .T
1095
1100
1096
1101
# try to cast if requested
1097
1102
if try_cast :
1098
1103
result = self ._try_cast_result (result )
1099
1104
1100
- return make_block (result ,
1101
- ndim = self .ndim , placement = self .mgr_locs )
1105
+ return make_block (result , ndim = self .ndim , placement = self .mgr_locs )
1102
1106
1103
1107
# might need to separate out blocks
1104
1108
axis = cond .ndim - 1
@@ -1744,7 +1748,8 @@ def take_nd(self, indexer, axis=0, new_mgr_locs=None, fill_tuple=None):
1744
1748
1745
1749
return self .make_block_same_class (new_values , new_mgr_locs )
1746
1750
1747
- def putmask (self , mask , new , align = True , inplace = False ):
1751
+ def putmask (self , mask , new , align = True , inplace = False ,
1752
+ axis = 0 , transpose = False ):
1748
1753
""" putmask the data to the block; it is possible that we may create a
1749
1754
new dtype of block
1750
1755
@@ -2436,12 +2441,18 @@ def apply(self, f, axes=None, filter=None, do_integrity_check=False, **kwargs):
2436
2441
else :
2437
2442
kwargs ['filter' ] = filter_locs
2438
2443
2439
- if f == 'where' and kwargs . get ( 'align' , True ) :
2444
+ if f == 'where' :
2440
2445
align_copy = True
2441
- align_keys = ['other' , 'cond' ]
2442
- elif f == 'putmask' and kwargs .get ('align' , True ):
2446
+ if kwargs .get ('align' , True ):
2447
+ align_keys = ['other' , 'cond' ]
2448
+ else :
2449
+ align_keys = ['cond' ]
2450
+ elif f == 'putmask' :
2443
2451
align_copy = False
2444
- align_keys = ['new' , 'mask' ]
2452
+ if kwargs .get ('align' , True ):
2453
+ align_keys = ['new' , 'mask' ]
2454
+ else :
2455
+ align_keys = ['mask' ]
2445
2456
elif f == 'eval' :
2446
2457
align_copy = False
2447
2458
align_keys = ['other' ]
0 commit comments