Skip to content

Commit 0da6cc3

Browse files
committed
BUG: GH #12223, GH #15262. Allow ints for names in MultiIndex
1 parent 61deba5 commit 0da6cc3

File tree

10 files changed

+57
-15
lines changed

10 files changed

+57
-15
lines changed

doc/source/whatsnew/v0.20.0.txt

+1
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ Other enhancements
153153
- ``Series/DataFrame.resample.asfreq`` have gained a ``fill_value`` parameter, to fill missing values during resampling (:issue:`3715`).
154154
- ``pandas.tools.hashing`` has gained a ``hash_tuples`` routine, and ``hash_pandas_object`` has gained the ability to hash a ``MultiIndex`` (:issue:`15224`)
155155
- ``Series/DataFrame.squeeze()`` have gained the ``axis`` parameter. (:issue:`15339`)
156+
- Using numerical names in ``MultiIndex`` causes less errors. (:issue:`12223`) (:issue:`15262`)
156157

157158
.. _ISO 8601 duration: https://en.wikipedia.org/wiki/ISO_8601#Durations
158159

pandas/core/frame.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -2860,7 +2860,7 @@ def set_index(self, keys, drop=True, append=False, inplace=False,
28602860
names = [x for x in self.index.names]
28612861
if isinstance(self.index, MultiIndex):
28622862
for i in range(self.index.nlevels):
2863-
arrays.append(self.index.get_level_values(i))
2863+
arrays.append(self.index._get_level_values_by_level(i))
28642864
else:
28652865
arrays.append(self.index)
28662866

@@ -2870,9 +2870,9 @@ def set_index(self, keys, drop=True, append=False, inplace=False,
28702870
# append all but the last column so we don't have to modify
28712871
# the end of this loop
28722872
for n in range(col.nlevels - 1):
2873-
arrays.append(col.get_level_values(n))
2873+
arrays.append(col._get_level_values_by_level(n))
28742874

2875-
level = col.get_level_values(col.nlevels - 1)
2875+
level = col._get_level_values_by_level(col.nlevels - 1)
28762876
names.extend(col.names)
28772877
elif isinstance(col, Series):
28782878
level = col._values

pandas/core/groupby.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -289,7 +289,7 @@ def _set_grouper(self, obj, sort=False):
289289
# equivalent to the axis name
290290
if isinstance(ax, MultiIndex):
291291
level = ax._get_level_number(level)
292-
ax = Index(ax.get_level_values(
292+
ax = Index(ax._get_level_values_by_level(
293293
level), name=ax.names[level])
294294

295295
else:
@@ -759,7 +759,7 @@ def _index_with_as_index(self, b):
759759
gp = self.grouper
760760
levels = chain((gp.levels[i][gp.labels[i][b]]
761761
for i in range(len(gp.groupings))),
762-
(original.get_level_values(i)[b]
762+
(original._get_level_values_by_level(i)[b]
763763
for i in range(original.nlevels)))
764764
new = MultiIndex.from_arrays(list(levels))
765765
new.names = gp.names + original.names

pandas/core/reshape.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -814,7 +814,8 @@ def melt(frame, id_vars=None, value_vars=None, var_name=None,
814814
mdata[value_name] = frame.values.ravel('F')
815815
for i, col in enumerate(var_name):
816816
# asanyarray will keep the columns as an Index
817-
mdata[col] = np.asanyarray(frame.columns.get_level_values(i)).repeat(N)
817+
mdata[col] = np.asanyarray(frame.columns
818+
._get_level_values_by_level(i)).repeat(N)
818819

819820
return DataFrame(mdata, columns=mcolumns)
820821

pandas/formats/format.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1566,7 +1566,7 @@ def _save_header(self):
15661566
if isinstance(index_label, list) and len(index_label) > 1:
15671567
col_line.extend([''] * (len(index_label) - 1))
15681568

1569-
col_line.extend(columns.get_level_values(i))
1569+
col_line.extend(columns._get_level_values_by_level(i))
15701570

15711571
writer.writerow(col_line)
15721572

pandas/indexes/base.py

+5
Original file line numberDiff line numberDiff line change
@@ -2346,6 +2346,11 @@ def get_level_values(self, level):
23462346
self._validate_index_level(level)
23472347
return self
23482348

2349+
def _get_level_values_by_level(self, num):
2350+
# Used to mirror implementation for MultiIndex
2351+
# GH #10461
2352+
return self.get_level_values(num)
2353+
23492354
def get_indexer(self, target, method=None, limit=None, tolerance=None):
23502355
"""
23512356
Compute indexer and mask for new index given the current index. The

pandas/indexes/multi.py

+22-4
Original file line numberDiff line numberDiff line change
@@ -761,7 +761,24 @@ def get_level_values(self, level):
761761
-------
762762
values : ndarray
763763
"""
764-
num = self._get_level_number(level)
764+
return self._get_level_values_by_level(self._get_level_number(level))
765+
766+
def _get_level_values_by_level(self, num):
767+
"""
768+
Return vector of label values for requested level, equal to the length
769+
of the index. Assumes a level number. For internal use
770+
771+
Parameters
772+
----------
773+
num : int
774+
775+
Returns
776+
-------
777+
values : ndarray
778+
"""
779+
# Discussion in GH 10461
780+
# When you know the parameter is a level number, use this
781+
# Provides better support when names in a MultiIndex are ints
765782
unique = self.levels[num] # .values
766783
labels = self.labels[num]
767784
filled = algos.take_1d(unique.values, labels,
@@ -850,7 +867,8 @@ def to_frame(self, index=True):
850867
"""
851868

852869
from pandas import DataFrame
853-
result = DataFrame({(name or level): self.get_level_values(level)
870+
result = DataFrame({(name or level):
871+
self._get_level_values_by_level(level)
854872
for name, level in
855873
zip(self.names, range(len(self.levels)))})
856874
if index:
@@ -1184,8 +1202,8 @@ def append(self, other):
11841202
for o in other):
11851203
arrays = []
11861204
for i in range(self.nlevels):
1187-
label = self.get_level_values(i)
1188-
appended = [o.get_level_values(i) for o in other]
1205+
label = self._get_level_values_by_level(i)
1206+
appended = [o._get_level_values_by_level(i) for o in other]
11891207
arrays.append(label.append(appended))
11901208
return MultiIndex.from_arrays(arrays, names=self.names)
11911209

pandas/io/sql.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -748,7 +748,7 @@ def _get_column_names_and_types(self, dtype_mapper):
748748
if self.index is not None:
749749
for i, idx_label in enumerate(self.index):
750750
idx_type = dtype_mapper(
751-
self.frame.index.get_level_values(i))
751+
self.frame.index._get_level_values_by_level(i))
752752
column_names_and_types.append((idx_label, idx_type, True))
753753

754754
column_names_and_types += [

pandas/tests/frame/test_combine_concat.py

+17
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,23 @@ def test_concat_axis_parameter(self):
422422
with assertRaisesRegexp(ValueError, 'No axis named'):
423423
pd.concat([series1, series2], axis='something')
424424

425+
def test_concat_numerical_names(self):
426+
# #15262 # #12223
427+
df = pd.DataFrame({'col': range(9)},
428+
index=(pd.MultiIndex
429+
.from_product([['A0', 'A1', 'A2'],
430+
['B0', 'B1', 'B2']],
431+
names=[1, 2])))
432+
result = pd.concat((df.iloc[:2, :], df.iloc[-2:, :]))
433+
expected = pd.DataFrame({'col': [0, 1, 7, 8]},
434+
dtype='int32',
435+
index=pd.MultiIndex.from_tuples([('A0', 'B0'),
436+
('A0', 'B1'),
437+
('A2', 'B1'),
438+
('A2', 'B2')],
439+
names=[1, 2]))
440+
tm.assert_frame_equal(result, expected)
441+
425442

426443
class TestDataFrameCombineFirst(tm.TestCase, TestData):
427444

pandas/util/doctools.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -113,12 +113,12 @@ def _insert_index(self, data):
113113
else:
114114
for i in range(idx_nlevels):
115115
data.insert(i, 'Index{0}'.format(i),
116-
data.index.get_level_values(i))
116+
data.index._get_level_values_by_level(i))
117117

118118
col_nlevels = data.columns.nlevels
119119
if col_nlevels > 1:
120-
col = data.columns.get_level_values(0)
121-
values = [data.columns.get_level_values(i).values
120+
col = data.columns._get_level_values_by_level(0)
121+
values = [data.columns._get_level_values_by_level(i).values
122122
for i in range(1, col_nlevels)]
123123
col_df = pd.DataFrame(values)
124124
data.columns = col_df.columns

0 commit comments

Comments
 (0)