@@ -39,6 +39,7 @@ class Block(PandasObject):
39
39
is_float = False
40
40
is_integer = False
41
41
is_complex = False
42
+ is_datetime = False
42
43
is_bool = False
43
44
is_object = False
44
45
is_sparse = False
@@ -453,10 +454,19 @@ def _can_hold_element(self, value):
453
454
def _try_cast (self , value ):
454
455
raise NotImplementedError ()
455
456
456
- def _try_cast_result (self , result ):
457
+ def _try_cast_result (self , result , dtype = None ):
457
458
""" try to cast the result to our original type,
458
459
we may have roundtripped thru object in the mean-time """
459
- return result
460
+ if dtype is None :
461
+ dtype = self .dtype
462
+
463
+ if self .is_integer or self .is_bool or self .is_datetime :
464
+ pass
465
+ elif self .is_float and result .dtype == self .dtype :
466
+ return result
467
+
468
+ # may need to change the dtype here
469
+ return _possibly_downcast_to_dtype (result , dtype )
460
470
461
471
def _try_coerce_args (self , values , other ):
462
472
""" provide coercion to our input arguments """
@@ -513,27 +523,29 @@ def setitem(self, indexer, value):
513
523
""" set the value inplace; return a new block (of a possibly different dtype)
514
524
indexer is a direct slice/positional indexer; value must be a compaitable shape """
515
525
516
- values = self . values
517
- if self . ndim == 2 :
518
- values = values . T
526
+ # coerce args
527
+ values , value = self . _try_coerce_args ( self . values , value )
528
+ arr_value = np . array ( value )
519
529
520
- # 2-d (DataFrame) are represented as a transposed array
521
- if self ._can_hold_element (value ):
522
- try :
523
- values [indexer ] = value
524
- return [ self ]
525
- except (IndexError ):
526
- return [ self ]
527
- except :
528
- pass
530
+ # cast the values to a type that can hold nan (if necessary)
531
+ if not self ._can_hold_element (value ):
532
+ dtype , _ = com ._maybe_promote (arr_value .dtype )
533
+ values = values .astype (dtype )
529
534
530
- # create an indexing mask, the putmask which potentially changes the dtype
531
- indices = np .arange (np .prod (values .shape )).reshape (values .shape )
532
- mask = indices [indexer ] == indices
533
- if self .ndim == 2 :
534
- mask = mask .T
535
+ try :
536
+ # set and return a block
537
+ transf = (lambda x : x .T ) if self .ndim == 2 else (lambda x : x )
538
+ values = transf (values )
539
+ values [indexer ] = value
540
+
541
+ # coerce and try to infer the dtypes of the result
542
+ values = self ._try_coerce_result (values )
543
+ values = self ._try_cast_result (values , 'infer' )
544
+ return [make_block (transf (values ), self .items , self .ref_items , ndim = self .ndim , fastpath = True )]
545
+ except :
546
+ pass
535
547
536
- return self . putmask ( mask , value , inplace = True )
548
+ return [ self ]
537
549
538
550
def putmask (self , mask , new , inplace = False ):
539
551
""" putmask the data to the block; it is possible that we may create a new dtype of block
@@ -585,7 +597,10 @@ def create_block(v, m, n, item, reshape=True):
585
597
if nv is None :
586
598
dtype , _ = com ._maybe_promote (n .dtype )
587
599
nv = v .astype (dtype )
588
- np .putmask (nv , m , n )
600
+ try :
601
+ nv [m ] = n
602
+ except :
603
+ np .putmask (nv , m , n )
589
604
590
605
if reshape :
591
606
nv = _block_shape (nv )
@@ -842,10 +857,6 @@ class NumericBlock(Block):
842
857
is_numeric = True
843
858
_can_hold_na = True
844
859
845
- def _try_cast_result (self , result ):
846
- return _possibly_downcast_to_dtype (result , self .dtype )
847
-
848
-
849
860
class FloatBlock (NumericBlock ):
850
861
is_float = True
851
862
_downcast_dtype = 'int64'
@@ -1104,6 +1115,7 @@ def re_replacer(s):
1104
1115
1105
1116
1106
1117
class DatetimeBlock (Block ):
1118
+ is_datetime = True
1107
1119
_can_hold_na = True
1108
1120
1109
1121
def __init__ (self , values , items , ref_items , fastpath = False , placement = None , ** kwargs ):
@@ -1119,8 +1131,8 @@ def _gi(self, arg):
1119
1131
def _can_hold_element (self , element ):
1120
1132
if is_list_like (element ):
1121
1133
element = np .array (element )
1122
- return element .dtype == _NS_DTYPE
1123
- return com .is_integer (element ) or isinstance (element , datetime )
1134
+ return element .dtype == _NS_DTYPE or element . dtype == np . int64
1135
+ return com .is_integer (element ) or isinstance (element , datetime ) or isnull ( element )
1124
1136
1125
1137
def _try_cast (self , element ):
1126
1138
try :
@@ -1133,10 +1145,10 @@ def _try_coerce_args(self, values, other):
1133
1145
we are going to compare vs i8, so coerce to integer
1134
1146
values is always ndarra like, other may not be """
1135
1147
values = values .view ('i8' )
1136
- if isinstance (other , datetime ):
1137
- other = lib .Timestamp (other ).asm8 .view ('i8' )
1138
- elif isnull (other ):
1148
+ if isnull (other ) or (np .isscalar (other ) and other == tslib .iNaT ):
1139
1149
other = tslib .iNaT
1150
+ elif isinstance (other , datetime ):
1151
+ other = lib .Timestamp (other ).asm8 .view ('i8' )
1140
1152
else :
1141
1153
other = other .view ('i8' )
1142
1154
@@ -1438,6 +1450,8 @@ def split_block_at(self, item):
1438
1450
return []
1439
1451
return super (SparseBlock , self ).split_block_at (self , item )
1440
1452
1453
+ def _try_cast_result (self , result , dtype = None ):
1454
+ return result
1441
1455
1442
1456
def make_block (values , items , ref_items , klass = None , ndim = None , dtype = None , fastpath = False , placement = None ):
1443
1457
0 commit comments