From 9e517acb8720fd5f34541f12cd11d5ddb4e6afc5 Mon Sep 17 00:00:00 2001 From: Jeff Reback Date: Wed, 24 Jun 2015 08:51:07 -0400 Subject: [PATCH] BUG: using .loc[:,column] fails when the object is a multi-index, #10408 --- pandas/core/common.py | 5 +++++ pandas/core/indexing.py | 10 +++++----- pandas/tests/test_indexing.py | 27 +++++++++++++++++++++++---- 3 files changed, 33 insertions(+), 9 deletions(-) diff --git a/pandas/core/common.py b/pandas/core/common.py index 990eec08d0bd6..d85e3f079e09d 100644 --- a/pandas/core/common.py +++ b/pandas/core/common.py @@ -2605,9 +2605,14 @@ def is_list_like(arg): not isinstance(arg, compat.string_and_binary_types)) def is_null_slice(obj): + """ we have a null slice """ return (isinstance(obj, slice) and obj.start is None and obj.stop is None and obj.step is None) +def is_full_slice(obj, l): + """ we have a full length slice """ + return (isinstance(obj, slice) and obj.start == 0 and + obj.stop == l and obj.step is None) def is_hashable(arg): """Return True if hash(arg) will succeed, False otherwise. diff --git a/pandas/core/indexing.py b/pandas/core/indexing.py index 02309e6e4e3b5..a9d277088f178 100644 --- a/pandas/core/indexing.py +++ b/pandas/core/indexing.py @@ -6,7 +6,7 @@ import pandas.core.common as com from pandas.core.common import (is_bool_indexer, is_integer_dtype, _asarray_tuplesafe, is_list_like, isnull, - is_null_slice, + is_null_slice, is_full_slice, ABCSeries, ABCDataFrame, ABCPanel, is_float, _values_from_object, _infer_fill_value, is_integer) import numpy as np @@ -399,10 +399,10 @@ def setter(item, v): pi = plane_indexer[0] if lplane_indexer == 1 else plane_indexer # perform the equivalent of a setitem on the info axis - # as we have a null slice which means essentially reassign to the columns - # of a multi-dim object - # GH6149 - if isinstance(pi, tuple) and all(is_null_slice(idx) for idx in pi): + # as we have a null slice or a slice with full bounds + # which means essentially reassign to the columns of a multi-dim object + # GH6149 (null slice), GH10408 (full bounds) + if isinstance(pi, tuple) and all(is_null_slice(idx) or is_full_slice(idx, len(self.obj)) for idx in pi): s = v else: # set the item, possibly having a dtype change diff --git a/pandas/tests/test_indexing.py b/pandas/tests/test_indexing.py index 710367bf04605..9ed8554e90b80 100644 --- a/pandas/tests/test_indexing.py +++ b/pandas/tests/test_indexing.py @@ -1072,6 +1072,25 @@ def test_loc_setitem_consistency(self): df['x'] = 1 assert_frame_equal(df,expected) + # .loc[:,column] setting with slice == len of the column + # GH10408 + data = """Level_0,,,Respondent,Respondent,Respondent,OtherCat,OtherCat +Level_1,,,Something,StartDate,EndDate,Yes/No,SomethingElse +Region,Site,RespondentID,,,,, +Region_1,Site_1,3987227376,A,5/25/2015 10:59,5/25/2015 11:22,Yes, +Region_1,Site_1,3980680971,A,5/21/2015 9:40,5/21/2015 9:52,Yes,Yes +Region_1,Site_2,3977723249,A,5/20/2015 8:27,5/20/2015 8:41,Yes, +Region_1,Site_2,3977723089,A,5/20/2015 8:33,5/20/2015 9:09,Yes,No""" + + df = pd.read_csv(StringIO(data),header=[0,1], index_col=[0,1,2]) + df.loc[:,('Respondent','StartDate')] = pd.to_datetime(df.loc[:,('Respondent','StartDate')]) + df.loc[:,('Respondent','EndDate')] = pd.to_datetime(df.loc[:,('Respondent','EndDate')]) + df.loc[:,('Respondent','Duration')] = df.loc[:,('Respondent','EndDate')] - df.loc[:,('Respondent','StartDate')] + + df.loc[:,('Respondent','Duration')] = df.loc[:,('Respondent','Duration')].astype('timedelta64[s]') + expected = Series([1380,720,840,2160.],index=df.index,name=('Respondent','Duration')) + assert_series_equal(df[('Respondent','Duration')],expected) + def test_loc_setitem_frame(self): df = self.frame_labels @@ -2331,14 +2350,14 @@ def test_setitem_dtype_upcast(self): assert_frame_equal(df,expected) # GH10280 - df = DataFrame(np.arange(6,dtype='int64').reshape(2, 3), + df = DataFrame(np.arange(6,dtype='int64').reshape(2, 3), index=list('ab'), columns=['foo', 'bar', 'baz']) for val in [3.14, 'wxyz']: left = df.copy() left.loc['a', 'bar'] = val - right = DataFrame([[0, val, 2], [3, 4, 5]], + right = DataFrame([[0, val, 2], [3, 4, 5]], index=list('ab'), columns=['foo', 'bar', 'baz']) @@ -2346,12 +2365,12 @@ def test_setitem_dtype_upcast(self): self.assertTrue(com.is_integer_dtype(left['foo'])) self.assertTrue(com.is_integer_dtype(left['baz'])) - left = DataFrame(np.arange(6,dtype='int64').reshape(2, 3) / 10.0, + left = DataFrame(np.arange(6,dtype='int64').reshape(2, 3) / 10.0, index=list('ab'), columns=['foo', 'bar', 'baz']) left.loc['a', 'bar'] = 'wxyz' - right = DataFrame([[0, 'wxyz', .2], [.3, .4, .5]], + right = DataFrame([[0, 'wxyz', .2], [.3, .4, .5]], index=list('ab'), columns=['foo', 'bar', 'baz'])