@@ -627,7 +627,8 @@ def _is_empty_indexer(indexer):
627
627
628
628
return [self ]
629
629
630
- def putmask (self , mask , new , align = True , inplace = False ):
630
+ def putmask (self , mask , new , align = True , inplace = False ,
631
+ axis = 0 , transpose = False ):
631
632
""" putmask the data to the block; it is possible that we may create a
632
633
new dtype of block
633
634
@@ -639,37 +640,55 @@ def putmask(self, mask, new, align=True, inplace=False):
639
640
new : a ndarray/object
640
641
align : boolean, perform alignment on other/cond, default is True
641
642
inplace : perform inplace modification, default is False
643
+ axis : int
644
+ transpose : boolean
645
+ Set to True if self is stored with axes reversed
642
646
643
647
Returns
644
648
-------
645
- a new block(s) , the result of the putmask
649
+ a list of new blocks , the result of the putmask
646
650
"""
647
651
648
652
new_values = self .values if inplace else self .values .copy ()
649
653
650
- # may need to align the new
651
654
if hasattr (new , 'reindex_axis' ):
652
- new = new .values . T
655
+ new = new .values
653
656
654
- # may need to align the mask
655
657
if hasattr (mask , 'reindex_axis' ):
656
- mask = mask .values . T
658
+ mask = mask .values
657
659
658
660
# if we are passed a scalar None, convert it here
659
661
if not is_list_like (new ) and isnull (new ) and not self .is_object :
660
662
new = self .fill_value
661
663
662
664
if self ._can_hold_element (new ):
665
+ if transpose :
666
+ new_values = new_values .T
667
+
663
668
new = self ._try_cast (new )
664
669
665
- # pseudo-broadcast
666
- if isinstance (new , np .ndarray ) and new .ndim == self .ndim - 1 :
667
- new = np .repeat (new , self .shape [- 1 ]).reshape (self .shape )
670
+ # If the default repeat behavior in np.putmask would go in the wrong
671
+ # direction, then explictly repeat and reshape new instead
672
+ if getattr (new , 'ndim' , 0 ) >= 1 :
673
+ if self .ndim - 1 == new .ndim and axis == 1 :
674
+ new = np .repeat (new , self .shape [- 1 ]).reshape (self .shape )
668
675
669
676
np .putmask (new_values , mask , new )
670
677
671
678
# maybe upcast me
672
679
elif mask .any ():
680
+ if transpose :
681
+ mask = mask .T
682
+ if isinstance (new , np .ndarray ):
683
+ new = new .T
684
+ axis = new_values .ndim - axis - 1
685
+
686
+ # Pseudo-broadcast
687
+ if getattr (new , 'ndim' , 0 ) >= 1 :
688
+ if self .ndim - 1 == new .ndim :
689
+ new_shape = list (new .shape )
690
+ new_shape .insert (axis , 1 )
691
+ new = new .reshape (tuple (new_shape ))
673
692
674
693
# need to go column by column
675
694
new_blocks = []
@@ -680,14 +699,15 @@ def putmask(self, mask, new, align=True, inplace=False):
680
699
681
700
# need a new block
682
701
if m .any ():
683
-
684
- n = new [i ] if isinstance (
685
- new , np .ndarray ) else np .array (new )
702
+ if isinstance (new , np .ndarray ):
703
+ n = np .squeeze (new [i % new .shape [0 ]])
704
+ else :
705
+ n = np .array (new )
686
706
687
707
# type of the new block
688
708
dtype , _ = com ._maybe_promote (n .dtype )
689
709
690
- # we need to exiplicty astype here to make a copy
710
+ # we need to explicitly astype here to make a copy
691
711
n = n .astype (dtype )
692
712
693
713
nv = _putmask_smart (v , m , n )
@@ -713,8 +733,10 @@ def putmask(self, mask, new, align=True, inplace=False):
713
733
if inplace :
714
734
return [self ]
715
735
716
- return [make_block (new_values ,
717
- placement = self .mgr_locs , fastpath = True )]
736
+ if transpose :
737
+ new_values = new_values .T
738
+
739
+ return [make_block (new_values , placement = self .mgr_locs , fastpath = True )]
718
740
719
741
def interpolate (self , method = 'pad' , axis = 0 , index = None ,
720
742
values = None , inplace = False , limit = None ,
@@ -998,7 +1020,7 @@ def handle_error():
998
1020
fastpath = True , placement = self .mgr_locs )]
999
1021
1000
1022
def where (self , other , cond , align = True , raise_on_error = True ,
1001
- try_cast = False ):
1023
+ try_cast = False , axis = 0 , transpose = False ):
1002
1024
"""
1003
1025
evaluate the block; return result block(s) from the result
1004
1026
@@ -1009,50 +1031,33 @@ def where(self, other, cond, align=True, raise_on_error=True,
1009
1031
align : boolean, perform alignment on other/cond
1010
1032
raise_on_error : if True, raise when I can't perform the function,
1011
1033
False by default (and just return the data that we had coming in)
1034
+ axis : int
1035
+ transpose : boolean
1036
+ Set to True if self is stored with axes reversed
1012
1037
1013
1038
Returns
1014
1039
-------
1015
1040
a new block(s), the result of the func
1016
1041
"""
1017
1042
1018
1043
values = self .values
1044
+ if transpose :
1045
+ values = values .T
1019
1046
1020
- # see if we can align other
1021
1047
if hasattr (other , 'reindex_axis' ):
1022
1048
other = other .values
1023
1049
1024
- # make sure that we can broadcast
1025
- is_transposed = False
1026
- if hasattr (other , 'ndim' ) and hasattr (values , 'ndim' ):
1027
- if values .ndim != other .ndim or values .shape == other .shape [::- 1 ]:
1028
-
1029
- # if its symmetric are ok, no reshaping needed (GH 7506)
1030
- if (values .shape [0 ] == np .array (values .shape )).all ():
1031
- pass
1032
-
1033
- # pseodo broadcast (its a 2d vs 1d say and where needs it in a
1034
- # specific direction)
1035
- elif (other .ndim >= 1 and values .ndim - 1 == other .ndim and
1036
- values .shape [0 ] != other .shape [0 ]):
1037
- other = _block_shape (other ).T
1038
- else :
1039
- values = values .T
1040
- is_transposed = True
1041
-
1042
- # see if we can align cond
1043
- if not hasattr (cond , 'shape' ):
1044
- raise ValueError (
1045
- "where must have a condition that is ndarray like" )
1046
-
1047
1050
if hasattr (cond , 'reindex_axis' ):
1048
1051
cond = cond .values
1049
1052
1050
- # may need to undo transpose of values
1051
- if hasattr (values , 'ndim' ):
1052
- if values .ndim != cond .ndim or values .shape == cond .shape [::- 1 ]:
1053
+ # If the default broadcasting would go in the wrong direction, then
1054
+ # explictly reshape other instead
1055
+ if getattr (other , 'ndim' , 0 ) >= 1 :
1056
+ if values .ndim - 1 == other .ndim and axis == 1 :
1057
+ other = other .reshape (tuple (other .shape + (1 ,)))
1053
1058
1054
- values = values . T
1055
- is_transposed = not is_transposed
1059
+ if not hasattr ( cond , 'shape' ):
1060
+ raise ValueError ( "where must have a condition that is ndarray like" )
1056
1061
1057
1062
other = _maybe_convert_string_to_object (other )
1058
1063
@@ -1085,15 +1090,14 @@ def func(c, v, o):
1085
1090
raise TypeError ('Could not compare [%s] with block values'
1086
1091
% repr (other ))
1087
1092
1088
- if is_transposed :
1093
+ if transpose :
1089
1094
result = result .T
1090
1095
1091
1096
# try to cast if requested
1092
1097
if try_cast :
1093
1098
result = self ._try_cast_result (result )
1094
1099
1095
- return make_block (result ,
1096
- ndim = self .ndim , placement = self .mgr_locs )
1100
+ return make_block (result , ndim = self .ndim , placement = self .mgr_locs )
1097
1101
1098
1102
# might need to separate out blocks
1099
1103
axis = cond .ndim - 1
@@ -1723,7 +1727,8 @@ def take_nd(self, indexer, axis=0, new_mgr_locs=None, fill_tuple=None):
1723
1727
1724
1728
return self .make_block_same_class (new_values , new_mgr_locs )
1725
1729
1726
- def putmask (self , mask , new , align = True , inplace = False ):
1730
+ def putmask (self , mask , new , align = True , inplace = False ,
1731
+ axis = 0 , transpose = False ):
1727
1732
""" putmask the data to the block; it is possible that we may create a
1728
1733
new dtype of block
1729
1734
0 commit comments