diff --git a/doc/source/indexing.rst b/doc/source/indexing.rst index 2eabc35fd831d..1729a9d76cacd 100644 --- a/doc/source/indexing.rst +++ b/doc/source/indexing.rst @@ -249,6 +249,14 @@ new column. If you are using the IPython environment, you may also use tab-completion to see these accessible attributes. +You can also assign a ``dict`` to a row of a ``DataFrame``: + +.. ipython:: python + + x = pd.DataFrame({'x': [1, 2, 3], 'y': [3, 4, 5]}) + x.iloc[1] = dict(x=9, y=99) + x + Slicing ranges -------------- diff --git a/doc/source/whatsnew/v0.16.1.txt b/doc/source/whatsnew/v0.16.1.txt index 6c6adec68f6bd..57eb3c6087836 100644 --- a/doc/source/whatsnew/v0.16.1.txt +++ b/doc/source/whatsnew/v0.16.1.txt @@ -136,4 +136,6 @@ Bug Fixes - Bug in unequal comparisons between categorical data and a scalar, which was not in the categories (e.g. ``Series(Categorical(list("abc"), ordered=True)) > "d"``. This returned ``False`` for all elements, but now raises a ``TypeError``. Equality comparisons also now return ``False`` for ``==`` and ``True`` for ``!=``. (:issue:`9848`) +- Bug in DataFrame ``__setitem__`` when right hand side is a dictionary (:issue:`9874`) + - Bug in ``MultiIndex.sortlevel()`` results in unicode level name breaks (:issue:`9875`) diff --git a/pandas/core/frame.py b/pandas/core/frame.py index 8b683ad89558a..19f15f58afffd 100644 --- a/pandas/core/frame.py +++ b/pandas/core/frame.py @@ -4414,12 +4414,12 @@ def mode(self, axis=0, numeric_only=False): """ Gets the mode(s) of each element along the axis selected. Empty if nothing has 2+ occurrences. Adds a row for each mode per label, fills in gaps - with nan. - + with nan. + Note that there could be multiple values returned for the selected - axis (when more than one item share the maximum frequency), which is the - reason why a dataframe is returned. If you want to impute missing values - with the mode in a dataframe ``df``, you can just do this: + axis (when more than one item share the maximum frequency), which is the + reason why a dataframe is returned. If you want to impute missing values + with the mode in a dataframe ``df``, you can just do this: ``df.fillna(df.mode().iloc[0])`` Parameters diff --git a/pandas/core/indexing.py b/pandas/core/indexing.py index 920e8aa04aa1f..8154eb1bb6c8b 100644 --- a/pandas/core/indexing.py +++ b/pandas/core/indexing.py @@ -200,7 +200,6 @@ def _has_valid_positional_setitem_indexer(self, indexer): return True def _setitem_with_indexer(self, indexer, value): - self._has_valid_setitem_indexer(indexer) # also has the side effect of consolidating in-place @@ -486,8 +485,8 @@ def can_do_equal_len(): self.obj[item_labels[indexer[info_axis]]] = value return - if isinstance(value, ABCSeries): - value = self._align_series(indexer, value) + if isinstance(value, (ABCSeries, dict)): + value = self._align_series(indexer, Series(value)) elif isinstance(value, ABCDataFrame): value = self._align_frame(indexer, value) diff --git a/pandas/tests/test_frame.py b/pandas/tests/test_frame.py index 14178f99d6313..58a0a25206b0c 100644 --- a/pandas/tests/test_frame.py +++ b/pandas/tests/test_frame.py @@ -5970,18 +5970,18 @@ def test_boolean_comparison(self): def test_equals_different_blocks(self): # GH 9330 - df0 = pd.DataFrame({"A": ["x","y"], "B": [1,2], + df0 = pd.DataFrame({"A": ["x","y"], "B": [1,2], "C": ["w","z"]}) df1 = df0.reset_index()[["A","B","C"]] - # this assert verifies that the above operations have + # this assert verifies that the above operations have # induced a block rearrangement - self.assertTrue(df0._data.blocks[0].dtype != + self.assertTrue(df0._data.blocks[0].dtype != df1._data.blocks[0].dtype) # do the real tests self.assert_frame_equal(df0, df1) self.assertTrue(df0.equals(df1)) self.assertTrue(df1.equals(df0)) - + def test_to_csv_from_csv(self): pname = '__tmp_to_csv_from_csv__' diff --git a/pandas/tests/test_indexing.py b/pandas/tests/test_indexing.py index ee6140828882c..5f109212add06 100644 --- a/pandas/tests/test_indexing.py +++ b/pandas/tests/test_indexing.py @@ -4411,6 +4411,16 @@ def test_slice_with_zero_step_raises(self): self.assertRaisesRegexp(ValueError, 'slice step cannot be zero', lambda: s.ix[::0]) + def test_indexing_assignment_dict_already_exists(self): + df = pd.DataFrame({'x': [1, 2, 6], + 'y': [2, 2, 8], + 'z': [-5, 0, 5]}).set_index('z') + expected = df.copy() + rhs = dict(x=9, y=99) + df.loc[5] = rhs + expected.loc[5] = [9, 99] + tm.assert_frame_equal(df, expected) + class TestSeriesNoneCoercion(tm.TestCase): EXPECTED_RESULTS = [