Skip to content

Commit 93cb736

Browse files
author
Christoph Möhl
committed
workaround for adding margins row to multiindex
1 parent 9c55b4d commit 93cb736

File tree

2 files changed

+43
-11
lines changed

2 files changed

+43
-11
lines changed

pandas/core/reshape/pivot.py

Lines changed: 41 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -254,13 +254,27 @@ def _add_margins(table, data, values, rows, cols, aggfunc,
254254

255255

256256
def _check_margins_name(margins_name, table):
257+
"""
258+
Checks if margins_name is a correct input argument for pivot_table
259+
or crosstab.
260+
261+
Parameters
262+
----------
263+
264+
margins_name : string, default 'All'
265+
Name of the row / column that will contain the totals
266+
when margins is True.
267+
table : DataFrame
268+
"""
269+
257270
if not isinstance(margins_name, compat.string_types):
258271
raise ValueError('margins_name argument must be a string')
259272

260273
exception_msg = 'Conflicting name "{0}" in margins'.format(margins_name)
261274
for level in table.index.names:
262275
if margins_name in table.index.get_level_values(level):
263276
raise ValueError(exception_msg)
277+
264278
# could be passed a Series object with no 'columns'
265279
if hasattr(table, 'columns'):
266280
for level in table.columns.names[1:]:
@@ -541,10 +555,13 @@ def crosstab(index, columns, values=None, rownames=None, colnames=None,
541555

542556
if normalize != 'columns':
543557
# add margin row
544-
if type(table.index) is MultiIndex:
545-
table = table.transpose()
546-
table[margins_name] = table.sum(axis=1)
547-
table = table.transpose()
558+
if isinstance(table.index, MultiIndex):
559+
# workaround for adding a margins row to a MultiIndex object
560+
# to be removed when GH 17024 is fixed
561+
new_index = _add_margins_to_multiindex(table.index,
562+
margins_name)
563+
table.loc[margins_name] = table.sum(axis=0)
564+
table.index = new_index
548565
else:
549566
table.loc[margins_name] = table.sum(axis=0)
550567
# Post-process
@@ -555,6 +572,25 @@ def crosstab(index, columns, values=None, rownames=None, colnames=None,
555572
return table
556573

557574

575+
def _add_margins_to_multiindex(index, margins_name):
576+
# workaround for adding a margins row to a MultiIndex object
577+
# to be removed when GH 17024 is fixed
578+
levels = list(index.levels)
579+
labels = list(index.labels)
580+
581+
levels[0] = levels[0].append(Index([margins_name]))
582+
for i in range(1, len(levels)):
583+
levels[i] = levels[i].append(Index(['']))
584+
for i in range(len(labels)):
585+
lbl = list(labels[i])
586+
lbl.append(max(labels[i] + 1))
587+
labels[i] = lbl
588+
589+
return MultiIndex(levels=levels,
590+
labels=labels,
591+
names=index.names)
592+
593+
558594
def _normalize(table, normalize, margins, margins_name='All'):
559595

560596
if not isinstance(normalize, bool) and not isinstance(normalize,
@@ -585,11 +621,7 @@ def _normalize(table, normalize, margins, margins_name='All'):
585621

586622
normalizers[True] = normalizers['all']
587623

588-
try:
589-
f = normalizers[normalize]
590-
except KeyError:
591-
raise ValueError(
592-
"Not a valid normalize argument: {!r}".format(normalize))
624+
f = normalizers[normalize]
593625

594626
table = f(table)
595627
table = table.fillna(0)

pandas/tests/reshape/test_pivot.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1477,8 +1477,8 @@ def test_crosstab_errors(self):
14771477
with tm.assert_raises_regex(ValueError, error):
14781478
pd.crosstab(df.a, df.b, aggfunc=np.mean)
14791479

1480-
error = "Not a valid normalize argument: '42'"
1481-
with tm.assert_raises_regex(ValueError, error):
1480+
error = "'42'"
1481+
with tm.assert_raises_regex(KeyError, error):
14821482
pd.crosstab(df.a, df.b, normalize='42')
14831483

14841484
error = "Not a valid normalize argument: 42"

0 commit comments

Comments
 (0)