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