44from  numpy  import  nan 
55import  numpy  as  np 
66
7- from  pandas .core .common  import  _possibly_downcast_to_dtype 
7+ from  pandas .core .common  import  _possibly_downcast_to_dtype ,  isnull 
88from  pandas .core .index  import  Index , _ensure_index , _handle_legacy_indexes 
99from  pandas .core .indexing  import  _check_slice_bounds , _maybe_convert_indices 
1010import  pandas .core .common  as  com 
@@ -260,32 +260,14 @@ def _try_cast_result(self, result):
260260 return  result 
261261
262262 def  replace (self , to_replace , value , inplace = False ):
263-  new_values  =  self .values  if  inplace  else  self .values .copy ()
264-  if  self ._can_hold_element (value ):
265-  value  =  self ._try_cast (value )
266- 
267-  if  not  isinstance (to_replace , (list , np .ndarray )):
268-  if  self ._can_hold_element (to_replace ):
269-  to_replace  =  self ._try_cast (to_replace )
270-  msk  =  com .mask_missing (new_values , to_replace )
271-  np .putmask (new_values , msk , value )
272-  else :
273-  try :
274-  to_replace  =  np .array (to_replace , dtype = self .dtype )
275-  msk  =  com .mask_missing (new_values , to_replace )
276-  np .putmask (new_values , msk , value )
277-  except  Exception :
278-  to_replace  =  np .array (to_replace , dtype = object )
279-  for  r  in  to_replace :
280-  if  self ._can_hold_element (r ):
281-  r  =  self ._try_cast (r )
282-  msk  =  com .mask_missing (new_values , to_replace )
283-  np .putmask (new_values , msk , value )
284- 
285-  if  inplace :
286-  return  self 
287-  else :
288-  return  make_block (new_values , self .items , self .ref_items )
263+  """ replace the to_replace value with value, possible to create new blocks here 
264+  this is just a call to putmask """ 
265+  mask  =  com .mask_missing (self .values , to_replace )
266+  if  not  mask .any ():
267+  if  inplace :
268+  return  [ self  ]
269+  return  [ self .copy () ]
270+  return  self .putmask (mask , value , inplace = inplace )
289271
290272 def  putmask (self , mask , new , inplace = False ):
291273 """ putmask the data to the block; it is possible that we may create a new dtype of block 
@@ -309,19 +291,34 @@ def putmask(self, mask, new, inplace=False):
309291
310292 # maybe upcast me 
311293 elif  mask .any ():
312-  # type of the new block 
313-  if  ((isinstance (new , np .ndarray ) and  issubclass (new .dtype , np .number )) or 
314-  isinstance (new , float )):
315-  typ  =  np .float64 
316-  else :
317-  typ  =  np .object_ 
318294
319-  # we need to exiplicty astype here to make a copy 
320-  new_values  =  new_values .astype (typ )
295+  # need to go column by column 
296+  new_blocks  =  []
297+  for  i , item  in  enumerate (self .items ):
321298
322-  # we create a new block type 
323-  np .putmask (new_values , mask , new )
324-  return  [ make_block (new_values , self .items , self .ref_items ) ]
299+  m  =  mask [i ]
300+ 
301+  # need a new block 
302+  if  m .any ():
303+ 
304+  n  =  new [i ] if  isinstance (new , np .ndarray ) else  new 
305+ 
306+  # type of the new block 
307+  dtype , _  =  com ._maybe_promote (np .array (n ).dtype )
308+ 
309+  # we need to exiplicty astype here to make a copy 
310+  nv  =  new_values [i ].astype (dtype )
311+ 
312+  # we create a new block type 
313+  np .putmask (nv , m , n )
314+ 
315+  else :
316+  nv  =  new_values [i ] if  inplace  else  new_values [i ].copy ()
317+ 
318+  nv  =  _block_shape (nv )
319+  new_blocks .append (make_block (nv , [ item  ], self .ref_items ))
320+ 
321+  return  new_blocks 
325322
326323 if  inplace :
327324 return  [ self  ]
@@ -350,7 +347,7 @@ def interpolate(self, method='pad', axis=0, inplace=False,
350347 if  missing  is  None :
351348 mask  =  None 
352349 else : # todo create faster fill func without masking 
353-  mask  =  _mask_missing (transf (values ), missing )
350+  mask  =  com . mask_missing (transf (values ), missing )
354351
355352 if  method  ==  'pad' :
356353 com .pad_2d (transf (values ), limit = limit , mask = mask )
@@ -532,31 +529,14 @@ def create_block(result, items, transpose = True):
532529 if  len (result ) ==  1 :
533530 result  =  np .repeat (result ,self .shape [1 :])
534531
535-  result  =  result . reshape ((( 1 ,)  +   self .shape [1 :]) )
532+  result  =  _block_shape ( result , ndim = self . ndim , shape = self .shape [1 :])
536533 result_blocks .append (create_block (result , item , transpose  =  False ))
537534
538535 return  result_blocks 
539536 else :
540537 result  =  func (cond ,values ,other )
541538 return  create_block (result , self .items )
542539
543- def  _mask_missing (array , missing_values ):
544-  if  not  isinstance (missing_values , (list , np .ndarray )):
545-  missing_values  =  [missing_values ]
546- 
547-  mask  =  None 
548-  missing_values  =  np .array (missing_values , dtype = object )
549-  if  com .isnull (missing_values ).any ():
550-  mask  =  com .isnull (array )
551-  missing_values  =  missing_values [com .notnull (missing_values )]
552- 
553-  for  v  in  missing_values :
554-  if  mask  is  None :
555-  mask  =  array  ==  missing_values 
556-  else :
557-  mask  |=  array  ==  missing_values 
558-  return  mask 
559- 
560540class  NumericBlock (Block ):
561541 is_numeric  =  True 
562542 _can_hold_na  =  True 
@@ -659,7 +639,7 @@ def convert(self, convert_dates = True, convert_numeric = True, copy = True):
659639 values  =  self .get (c )
660640
661641 values  =  com ._possibly_convert_objects (values , convert_dates = convert_dates , convert_numeric = convert_numeric )
662-  values  =  values . reshape ((( 1 ,)  +   values . shape ) )
642+  values  =  _block_shape ( values )
663643 items  =  self .items .take ([i ])
664644 newb  =  make_block (values , items , self .ref_items )
665645 blocks .append (newb )
@@ -949,23 +929,37 @@ def replace(self, *args, **kwargs):
949929
950930 def  replace_list (self , src_lst , dest_lst , inplace = False ):
951931 """ do a list replace """ 
952-  if  not  inplace :
953-  self  =  self .copy ()
954- 
955-  sset  =  set (src_lst )
956-  if  any ([k  in  sset  for  k  in  dest_lst ]):
957-  masks  =  {}
958-  for  s  in  src_lst :
959-  masks [s ] =  [b .values  ==  s  for  b  in  self .blocks ]
960- 
961-  for  s , d  in  zip (src_lst , dest_lst ):
962-  [b .putmask (masks [s ][i ], d , inplace = True ) for  i , b  in 
963-  enumerate (self .blocks )]
964-  else :
965-  for  s , d  in  zip (src_lst , dest_lst ):
966-  self .replace (s , d , inplace = True )
967932
968-  return  self 
933+  # figure out our mask a-priori to avoid repeated replacements 
934+  values  =  self .as_matrix ()
935+  def  comp (s ):
936+  if  isnull (s ):
937+  return  isnull (values )
938+  return  values  ==  s 
939+  masks  =  [ comp (s ) for  i , s  in  enumerate (src_lst ) ]
940+ 
941+  result_blocks  =  []
942+  for  blk  in  self .blocks :
943+ 
944+  # its possible to get multiple result blocks here 
945+  # replace ALWAYS will return a list 
946+  rb  =  [ blk  if  inplace  else  blk .copy () ]
947+  for  i , d  in  enumerate (dest_lst ):
948+  new_rb  =  []
949+  for  b  in  rb :
950+  # get our mask for this element, sized to this  
951+  # particular block 
952+  m  =  masks [i ][b .ref_locs ]
953+  if  m .any ():
954+  new_rb .extend (b .putmask (m , d , inplace = True ))
955+  else :
956+  new_rb .append (b )
957+  rb  =  new_rb 
958+  result_blocks .extend (rb )
959+ 
960+  bm  =  self .__class__ (result_blocks , self .axes )
961+  bm ._consolidate_inplace ()
962+  return  bm 
969963
970964 def  is_consolidated (self ):
971965 """ 
@@ -1302,8 +1296,7 @@ def set(self, item, value):
13021296 Set new item in-place. Does not consolidate. Adds new Block if not 
13031297 contained in the current set of items 
13041298 """ 
1305-  if  value .ndim  ==  self .ndim  -  1 :
1306-  value  =  value .reshape ((1 ,) +  value .shape )
1299+  value  =  _block_shape (value ,self .ndim - 1 )
13071300 if  value .shape [1 :] !=  self .shape [1 :]:
13081301 raise  AssertionError ('Shape of new values must be compatible ' 
13091302 'with manager shape' )
@@ -1873,6 +1866,14 @@ def _merge_blocks(blocks, items):
18731866 return  new_block .reindex_items_from (items )
18741867
18751868
1869+ def  _block_shape (values , ndim = 1 , shape = None ):
1870+  """ guarantee the shape of the values to be at least 1 d """ 
1871+  if  values .ndim  ==  ndim :
1872+  if  shape  is  None :
1873+  shape  =  values .shape 
1874+  values  =  values .reshape (tuple ((1 ,) +  shape ))
1875+  return  values 
1876+ 
18761877def  _vstack (to_stack ):
18771878 if  all (x .dtype  ==  _NS_DTYPE  for  x  in  to_stack ):
18781879 # work around NumPy 1.6 bug 
0 commit comments