|
| 1 | +from collections import ChainMap |
| 2 | + |
| 3 | +import numpy as np |
| 4 | +import pytest |
| 5 | + |
| 6 | +from pandas import DataFrame, Index, MultiIndex |
| 7 | +import pandas._testing as tm |
| 8 | + |
| 9 | + |
| 10 | +class TestRename: |
| 11 | + def test_rename(self, float_frame): |
| 12 | + mapping = {"A": "a", "B": "b", "C": "c", "D": "d"} |
| 13 | + |
| 14 | + renamed = float_frame.rename(columns=mapping) |
| 15 | + renamed2 = float_frame.rename(columns=str.lower) |
| 16 | + |
| 17 | + tm.assert_frame_equal(renamed, renamed2) |
| 18 | + tm.assert_frame_equal( |
| 19 | + renamed2.rename(columns=str.upper), float_frame, check_names=False |
| 20 | + ) |
| 21 | + |
| 22 | + # index |
| 23 | + data = {"A": {"foo": 0, "bar": 1}} |
| 24 | + |
| 25 | + # gets sorted alphabetical |
| 26 | + df = DataFrame(data) |
| 27 | + renamed = df.rename(index={"foo": "bar", "bar": "foo"}) |
| 28 | + tm.assert_index_equal(renamed.index, Index(["foo", "bar"])) |
| 29 | + |
| 30 | + renamed = df.rename(index=str.upper) |
| 31 | + tm.assert_index_equal(renamed.index, Index(["BAR", "FOO"])) |
| 32 | + |
| 33 | + # have to pass something |
| 34 | + with pytest.raises(TypeError, match="must pass an index to rename"): |
| 35 | + float_frame.rename() |
| 36 | + |
| 37 | + # partial columns |
| 38 | + renamed = float_frame.rename(columns={"C": "foo", "D": "bar"}) |
| 39 | + tm.assert_index_equal(renamed.columns, Index(["A", "B", "foo", "bar"])) |
| 40 | + |
| 41 | + # other axis |
| 42 | + renamed = float_frame.T.rename(index={"C": "foo", "D": "bar"}) |
| 43 | + tm.assert_index_equal(renamed.index, Index(["A", "B", "foo", "bar"])) |
| 44 | + |
| 45 | + # index with name |
| 46 | + index = Index(["foo", "bar"], name="name") |
| 47 | + renamer = DataFrame(data, index=index) |
| 48 | + renamed = renamer.rename(index={"foo": "bar", "bar": "foo"}) |
| 49 | + tm.assert_index_equal(renamed.index, Index(["bar", "foo"], name="name")) |
| 50 | + assert renamed.index.name == renamer.index.name |
| 51 | + |
| 52 | + @pytest.mark.parametrize( |
| 53 | + "args,kwargs", |
| 54 | + [ |
| 55 | + ((ChainMap({"A": "a"}, {"B": "b"}),), dict(axis="columns")), |
| 56 | + ((), dict(columns=ChainMap({"A": "a"}, {"B": "b"}))), |
| 57 | + ], |
| 58 | + ) |
| 59 | + def test_rename_chainmap(self, args, kwargs): |
| 60 | + # see gh-23859 |
| 61 | + colAData = range(1, 11) |
| 62 | + colBdata = np.random.randn(10) |
| 63 | + |
| 64 | + df = DataFrame({"A": colAData, "B": colBdata}) |
| 65 | + result = df.rename(*args, **kwargs) |
| 66 | + |
| 67 | + expected = DataFrame({"a": colAData, "b": colBdata}) |
| 68 | + tm.assert_frame_equal(result, expected) |
| 69 | + |
| 70 | + @pytest.mark.parametrize( |
| 71 | + "kwargs, rename_index, rename_columns", |
| 72 | + [ |
| 73 | + ({"mapper": None, "axis": 0}, True, False), |
| 74 | + ({"mapper": None, "axis": 1}, False, True), |
| 75 | + ({"index": None}, True, False), |
| 76 | + ({"columns": None}, False, True), |
| 77 | + ({"index": None, "columns": None}, True, True), |
| 78 | + ({}, False, False), |
| 79 | + ], |
| 80 | + ) |
| 81 | + def test_rename_axis_none(self, kwargs, rename_index, rename_columns): |
| 82 | + # GH 25034 |
| 83 | + index = Index(list("abc"), name="foo") |
| 84 | + columns = Index(["col1", "col2"], name="bar") |
| 85 | + data = np.arange(6).reshape(3, 2) |
| 86 | + df = DataFrame(data, index, columns) |
| 87 | + |
| 88 | + result = df.rename_axis(**kwargs) |
| 89 | + expected_index = index.rename(None) if rename_index else index |
| 90 | + expected_columns = columns.rename(None) if rename_columns else columns |
| 91 | + expected = DataFrame(data, expected_index, expected_columns) |
| 92 | + tm.assert_frame_equal(result, expected) |
| 93 | + |
| 94 | + def test_rename_multiindex(self): |
| 95 | + |
| 96 | + tuples_index = [("foo1", "bar1"), ("foo2", "bar2")] |
| 97 | + tuples_columns = [("fizz1", "buzz1"), ("fizz2", "buzz2")] |
| 98 | + index = MultiIndex.from_tuples(tuples_index, names=["foo", "bar"]) |
| 99 | + columns = MultiIndex.from_tuples(tuples_columns, names=["fizz", "buzz"]) |
| 100 | + df = DataFrame([(0, 0), (1, 1)], index=index, columns=columns) |
| 101 | + |
| 102 | + # |
| 103 | + # without specifying level -> across all levels |
| 104 | + |
| 105 | + renamed = df.rename( |
| 106 | + index={"foo1": "foo3", "bar2": "bar3"}, |
| 107 | + columns={"fizz1": "fizz3", "buzz2": "buzz3"}, |
| 108 | + ) |
| 109 | + new_index = MultiIndex.from_tuples( |
| 110 | + [("foo3", "bar1"), ("foo2", "bar3")], names=["foo", "bar"] |
| 111 | + ) |
| 112 | + new_columns = MultiIndex.from_tuples( |
| 113 | + [("fizz3", "buzz1"), ("fizz2", "buzz3")], names=["fizz", "buzz"] |
| 114 | + ) |
| 115 | + tm.assert_index_equal(renamed.index, new_index) |
| 116 | + tm.assert_index_equal(renamed.columns, new_columns) |
| 117 | + assert renamed.index.names == df.index.names |
| 118 | + assert renamed.columns.names == df.columns.names |
| 119 | + |
| 120 | + # |
| 121 | + # with specifying a level (GH13766) |
| 122 | + |
| 123 | + # dict |
| 124 | + new_columns = MultiIndex.from_tuples( |
| 125 | + [("fizz3", "buzz1"), ("fizz2", "buzz2")], names=["fizz", "buzz"] |
| 126 | + ) |
| 127 | + renamed = df.rename(columns={"fizz1": "fizz3", "buzz2": "buzz3"}, level=0) |
| 128 | + tm.assert_index_equal(renamed.columns, new_columns) |
| 129 | + renamed = df.rename(columns={"fizz1": "fizz3", "buzz2": "buzz3"}, level="fizz") |
| 130 | + tm.assert_index_equal(renamed.columns, new_columns) |
| 131 | + |
| 132 | + new_columns = MultiIndex.from_tuples( |
| 133 | + [("fizz1", "buzz1"), ("fizz2", "buzz3")], names=["fizz", "buzz"] |
| 134 | + ) |
| 135 | + renamed = df.rename(columns={"fizz1": "fizz3", "buzz2": "buzz3"}, level=1) |
| 136 | + tm.assert_index_equal(renamed.columns, new_columns) |
| 137 | + renamed = df.rename(columns={"fizz1": "fizz3", "buzz2": "buzz3"}, level="buzz") |
| 138 | + tm.assert_index_equal(renamed.columns, new_columns) |
| 139 | + |
| 140 | + # function |
| 141 | + func = str.upper |
| 142 | + new_columns = MultiIndex.from_tuples( |
| 143 | + [("FIZZ1", "buzz1"), ("FIZZ2", "buzz2")], names=["fizz", "buzz"] |
| 144 | + ) |
| 145 | + renamed = df.rename(columns=func, level=0) |
| 146 | + tm.assert_index_equal(renamed.columns, new_columns) |
| 147 | + renamed = df.rename(columns=func, level="fizz") |
| 148 | + tm.assert_index_equal(renamed.columns, new_columns) |
| 149 | + |
| 150 | + new_columns = MultiIndex.from_tuples( |
| 151 | + [("fizz1", "BUZZ1"), ("fizz2", "BUZZ2")], names=["fizz", "buzz"] |
| 152 | + ) |
| 153 | + renamed = df.rename(columns=func, level=1) |
| 154 | + tm.assert_index_equal(renamed.columns, new_columns) |
| 155 | + renamed = df.rename(columns=func, level="buzz") |
| 156 | + tm.assert_index_equal(renamed.columns, new_columns) |
| 157 | + |
| 158 | + # index |
| 159 | + new_index = MultiIndex.from_tuples( |
| 160 | + [("foo3", "bar1"), ("foo2", "bar2")], names=["foo", "bar"] |
| 161 | + ) |
| 162 | + renamed = df.rename(index={"foo1": "foo3", "bar2": "bar3"}, level=0) |
| 163 | + tm.assert_index_equal(renamed.index, new_index) |
| 164 | + |
| 165 | + def test_rename_nocopy(self, float_frame): |
| 166 | + renamed = float_frame.rename(columns={"C": "foo"}, copy=False) |
| 167 | + renamed["foo"] = 1.0 |
| 168 | + assert (float_frame["C"] == 1.0).all() |
| 169 | + |
| 170 | + def test_rename_inplace(self, float_frame): |
| 171 | + float_frame.rename(columns={"C": "foo"}) |
| 172 | + assert "C" in float_frame |
| 173 | + assert "foo" not in float_frame |
| 174 | + |
| 175 | + c_id = id(float_frame["C"]) |
| 176 | + float_frame = float_frame.copy() |
| 177 | + float_frame.rename(columns={"C": "foo"}, inplace=True) |
| 178 | + |
| 179 | + assert "C" not in float_frame |
| 180 | + assert "foo" in float_frame |
| 181 | + assert id(float_frame["foo"]) != c_id |
| 182 | + |
| 183 | + def test_rename_bug(self): |
| 184 | + # GH 5344 |
| 185 | + # rename set ref_locs, and set_index was not resetting |
| 186 | + df = DataFrame({0: ["foo", "bar"], 1: ["bah", "bas"], 2: [1, 2]}) |
| 187 | + df = df.rename(columns={0: "a"}) |
| 188 | + df = df.rename(columns={1: "b"}) |
| 189 | + df = df.set_index(["a", "b"]) |
| 190 | + df.columns = ["2001-01-01"] |
| 191 | + expected = DataFrame( |
| 192 | + [[1], [2]], |
| 193 | + index=MultiIndex.from_tuples( |
| 194 | + [("foo", "bah"), ("bar", "bas")], names=["a", "b"] |
| 195 | + ), |
| 196 | + columns=["2001-01-01"], |
| 197 | + ) |
| 198 | + tm.assert_frame_equal(df, expected) |
| 199 | + |
| 200 | + def test_rename_bug2(self): |
| 201 | + # GH 19497 |
| 202 | + # rename was changing Index to MultiIndex if Index contained tuples |
| 203 | + |
| 204 | + df = DataFrame(data=np.arange(3), index=[(0, 0), (1, 1), (2, 2)], columns=["a"]) |
| 205 | + df = df.rename({(1, 1): (5, 4)}, axis="index") |
| 206 | + expected = DataFrame( |
| 207 | + data=np.arange(3), index=[(0, 0), (5, 4), (2, 2)], columns=["a"] |
| 208 | + ) |
| 209 | + tm.assert_frame_equal(df, expected) |
| 210 | + |
| 211 | + def test_rename_errors_raises(self): |
| 212 | + df = DataFrame(columns=["A", "B", "C", "D"]) |
| 213 | + with pytest.raises(KeyError, match="'E'] not found in axis"): |
| 214 | + df.rename(columns={"A": "a", "E": "e"}, errors="raise") |
| 215 | + |
| 216 | + @pytest.mark.parametrize( |
| 217 | + "mapper, errors, expected_columns", |
| 218 | + [ |
| 219 | + ({"A": "a", "E": "e"}, "ignore", ["a", "B", "C", "D"]), |
| 220 | + ({"A": "a"}, "raise", ["a", "B", "C", "D"]), |
| 221 | + (str.lower, "raise", ["a", "b", "c", "d"]), |
| 222 | + ], |
| 223 | + ) |
| 224 | + def test_rename_errors(self, mapper, errors, expected_columns): |
| 225 | + # GH 13473 |
| 226 | + # rename now works with errors parameter |
| 227 | + df = DataFrame(columns=["A", "B", "C", "D"]) |
| 228 | + result = df.rename(columns=mapper, errors=errors) |
| 229 | + expected = DataFrame(columns=expected_columns) |
| 230 | + tm.assert_frame_equal(result, expected) |
| 231 | + |
| 232 | + def test_rename_objects(self, float_string_frame): |
| 233 | + renamed = float_string_frame.rename(columns=str.upper) |
| 234 | + |
| 235 | + assert "FOO" in renamed |
| 236 | + assert "foo" not in renamed |
| 237 | + |
| 238 | + def test_rename_axis_style(self): |
| 239 | + # https://github.com/pandas-dev/pandas/issues/12392 |
| 240 | + df = DataFrame({"A": [1, 2], "B": [1, 2]}, index=["X", "Y"]) |
| 241 | + expected = DataFrame({"a": [1, 2], "b": [1, 2]}, index=["X", "Y"]) |
| 242 | + |
| 243 | + result = df.rename(str.lower, axis=1) |
| 244 | + tm.assert_frame_equal(result, expected) |
| 245 | + |
| 246 | + result = df.rename(str.lower, axis="columns") |
| 247 | + tm.assert_frame_equal(result, expected) |
| 248 | + |
| 249 | + result = df.rename({"A": "a", "B": "b"}, axis=1) |
| 250 | + tm.assert_frame_equal(result, expected) |
| 251 | + |
| 252 | + result = df.rename({"A": "a", "B": "b"}, axis="columns") |
| 253 | + tm.assert_frame_equal(result, expected) |
| 254 | + |
| 255 | + # Index |
| 256 | + expected = DataFrame({"A": [1, 2], "B": [1, 2]}, index=["x", "y"]) |
| 257 | + result = df.rename(str.lower, axis=0) |
| 258 | + tm.assert_frame_equal(result, expected) |
| 259 | + |
| 260 | + result = df.rename(str.lower, axis="index") |
| 261 | + tm.assert_frame_equal(result, expected) |
| 262 | + |
| 263 | + result = df.rename({"X": "x", "Y": "y"}, axis=0) |
| 264 | + tm.assert_frame_equal(result, expected) |
| 265 | + |
| 266 | + result = df.rename({"X": "x", "Y": "y"}, axis="index") |
| 267 | + tm.assert_frame_equal(result, expected) |
| 268 | + |
| 269 | + result = df.rename(mapper=str.lower, axis="index") |
| 270 | + tm.assert_frame_equal(result, expected) |
| 271 | + |
| 272 | + def test_rename_mapper_multi(self): |
| 273 | + df = DataFrame({"A": ["a", "b"], "B": ["c", "d"], "C": [1, 2]}).set_index( |
| 274 | + ["A", "B"] |
| 275 | + ) |
| 276 | + result = df.rename(str.upper) |
| 277 | + expected = df.rename(index=str.upper) |
| 278 | + tm.assert_frame_equal(result, expected) |
| 279 | + |
| 280 | + def test_rename_positional_named(self): |
| 281 | + # https://github.com/pandas-dev/pandas/issues/12392 |
| 282 | + df = DataFrame({"a": [1, 2], "b": [1, 2]}, index=["X", "Y"]) |
| 283 | + result = df.rename(index=str.lower, columns=str.upper) |
| 284 | + expected = DataFrame({"A": [1, 2], "B": [1, 2]}, index=["x", "y"]) |
| 285 | + tm.assert_frame_equal(result, expected) |
| 286 | + |
| 287 | + def test_rename_axis_style_raises(self): |
| 288 | + # see gh-12392 |
| 289 | + df = DataFrame({"A": [1, 2], "B": [1, 2]}, index=["0", "1"]) |
| 290 | + |
| 291 | + # Named target and axis |
| 292 | + over_spec_msg = "Cannot specify both 'axis' and any of 'index' or 'columns'" |
| 293 | + with pytest.raises(TypeError, match=over_spec_msg): |
| 294 | + df.rename(index=str.lower, axis=1) |
| 295 | + |
| 296 | + with pytest.raises(TypeError, match=over_spec_msg): |
| 297 | + df.rename(index=str.lower, axis="columns") |
| 298 | + |
| 299 | + with pytest.raises(TypeError, match=over_spec_msg): |
| 300 | + df.rename(columns=str.lower, axis="columns") |
| 301 | + |
| 302 | + with pytest.raises(TypeError, match=over_spec_msg): |
| 303 | + df.rename(index=str.lower, axis=0) |
| 304 | + |
| 305 | + # Multiple targets and axis |
| 306 | + with pytest.raises(TypeError, match=over_spec_msg): |
| 307 | + df.rename(str.lower, index=str.lower, axis="columns") |
| 308 | + |
| 309 | + # Too many targets |
| 310 | + over_spec_msg = "Cannot specify both 'mapper' and any of 'index' or 'columns'" |
| 311 | + with pytest.raises(TypeError, match=over_spec_msg): |
| 312 | + df.rename(str.lower, index=str.lower, columns=str.lower) |
| 313 | + |
| 314 | + # Duplicates |
| 315 | + with pytest.raises(TypeError, match="multiple values"): |
| 316 | + df.rename(id, mapper=id) |
| 317 | + |
| 318 | + def test_rename_positional_raises(self): |
| 319 | + # GH 29136 |
| 320 | + df = DataFrame(columns=["A", "B"]) |
| 321 | + msg = r"rename\(\) takes from 1 to 2 positional arguments" |
| 322 | + |
| 323 | + with pytest.raises(TypeError, match=msg): |
| 324 | + df.rename(None, str.lower) |
| 325 | + |
| 326 | + def test_rename_no_mappings_raises(self): |
| 327 | + # GH 29136 |
| 328 | + df = DataFrame([[1]]) |
| 329 | + msg = "must pass an index to rename" |
| 330 | + with pytest.raises(TypeError, match=msg): |
| 331 | + df.rename() |
| 332 | + |
| 333 | + with pytest.raises(TypeError, match=msg): |
| 334 | + df.rename(None, index=None) |
| 335 | + |
| 336 | + with pytest.raises(TypeError, match=msg): |
| 337 | + df.rename(None, columns=None) |
| 338 | + |
| 339 | + with pytest.raises(TypeError, match=msg): |
| 340 | + df.rename(None, columns=None, index=None) |
| 341 | + |
| 342 | + def test_rename_mapper_and_positional_arguments_raises(self): |
| 343 | + # GH 29136 |
| 344 | + df = DataFrame([[1]]) |
| 345 | + msg = "Cannot specify both 'mapper' and any of 'index' or 'columns'" |
| 346 | + with pytest.raises(TypeError, match=msg): |
| 347 | + df.rename({}, index={}) |
| 348 | + |
| 349 | + with pytest.raises(TypeError, match=msg): |
| 350 | + df.rename({}, columns={}) |
| 351 | + |
| 352 | + with pytest.raises(TypeError, match=msg): |
| 353 | + df.rename({}, columns={}, index={}) |
0 commit comments