Skip to content

Commit 4216178

Browse files
Merge pull request pandas-dev#5505 from jsexauer/fix5505
ENH: Have pivot and pivot_table take similar arguments
2 parents dcbbc59 + 6e7054a commit 4216178

File tree

4 files changed

+152
-77
lines changed

4 files changed

+152
-77
lines changed

doc/source/release.rst

+5
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,11 @@ API Changes
125125
DataFrame returned by ``GroupBy.apply`` (:issue:`6124`). This facilitates
126126
``DataFrame.stack`` operations where the name of the column index is used as
127127
the name of the inserted column containing the pivoted data.
128+
129+
- The :func:`pivot_table`/:meth:`DataFrame.pivot_table` and :func:`crosstab` functions
130+
now take arguments ``index`` and ``columns`` instead of ``rows`` and ``cols``. A
131+
``FutureWarning`` is raised to alert that the old ``rows`` and ``cols`` arguments
132+
will not be supported in a future release (:issue:`5505`)
128133

129134
Experimental Features
130135
~~~~~~~~~~~~~~~~~~~~~

doc/source/v0.14.0.txt

+5
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,11 @@ These are out-of-bounds selections
167167
# New output, 4-level MultiIndex
168168
df_multi.set_index([df_multi.index, df_multi.index])
169169

170+
- The :func:`pivot_table`/:meth:`DataFrame.pivot_table` and :func:`crosstab` functions
171+
now take arguments ``index`` and ``columns`` instead of ``rows`` and ``cols``. A
172+
``FutureWarning`` is raised to alert that the old ``rows`` and ``cols`` arguments
173+
will not be supported in a future release (:issue:`5505`)
174+
170175

171176
MultiIndexing Using Slicers
172177
~~~~~~~~~~~~~~~~~~~~~~~~~~~

pandas/tools/pivot.py

+76-26
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# pylint: disable=E1103
22

3+
import warnings
4+
35
from pandas import Series, DataFrame
46
from pandas.core.index import MultiIndex
57
from pandas.tools.merge import concat
@@ -10,8 +12,8 @@
1012
import numpy as np
1113

1214

13-
def pivot_table(data, values=None, rows=None, cols=None, aggfunc='mean',
14-
fill_value=None, margins=False, dropna=True):
15+
def pivot_table(data, values=None, index=None, columns=None, aggfunc='mean',
16+
fill_value=None, margins=False, dropna=True, **kwarg):
1517
"""
1618
Create a spreadsheet-style pivot table as a DataFrame. The levels in the
1719
pivot table will be stored in MultiIndex objects (hierarchical indexes) on
@@ -21,9 +23,9 @@ def pivot_table(data, values=None, rows=None, cols=None, aggfunc='mean',
2123
----------
2224
data : DataFrame
2325
values : column to aggregate, optional
24-
rows : list of column names or arrays to group on
26+
index : list of column names or arrays to group on
2527
Keys to group on the x-axis of the pivot table
26-
cols : list of column names or arrays to group on
28+
columns : list of column names or arrays to group on
2729
Keys to group on the y-axis of the pivot table
2830
aggfunc : function, default numpy.mean, or list of functions
2931
If list of functions passed, the resulting pivot table will have
@@ -35,6 +37,8 @@ def pivot_table(data, values=None, rows=None, cols=None, aggfunc='mean',
3537
Add all row / columns (e.g. for subtotal / grand totals)
3638
dropna : boolean, default True
3739
Do not include columns whose entries are all NaN
40+
rows : kwarg only alias of index [deprecated]
41+
cols : kwarg only alias of columns [deprecated]
3842
3943
Examples
4044
--------
@@ -50,8 +54,8 @@ def pivot_table(data, values=None, rows=None, cols=None, aggfunc='mean',
5054
7 bar two small 6
5155
8 bar two large 7
5256
53-
>>> table = pivot_table(df, values='D', rows=['A', 'B'],
54-
... cols=['C'], aggfunc=np.sum)
57+
>>> table = pivot_table(df, values='D', index=['A', 'B'],
58+
... columns=['C'], aggfunc=np.sum)
5559
>>> table
5660
small large
5761
foo one 1 4
@@ -63,21 +67,43 @@ def pivot_table(data, values=None, rows=None, cols=None, aggfunc='mean',
6367
-------
6468
table : DataFrame
6569
"""
66-
rows = _convert_by(rows)
67-
cols = _convert_by(cols)
70+
# Parse old-style keyword arguments
71+
rows = kwarg.pop('rows', None)
72+
if rows is not None:
73+
warnings.warn("rows is deprecated, use index", FutureWarning)
74+
if index is None:
75+
index = rows
76+
else:
77+
msg = "Can only specify either 'rows' or 'index'"
78+
raise TypeError(msg)
79+
80+
cols = kwarg.pop('cols', None)
81+
if cols is not None:
82+
warnings.warn("cols is deprecated, use columns", FutureWarning)
83+
if columns is None:
84+
columns = cols
85+
else:
86+
msg = "Can only specify either 'cols' or 'columns'"
87+
raise TypeError(msg)
88+
89+
if kwarg:
90+
raise TypeError("Unexpected argument(s): %s" % kwarg.keys())
91+
92+
index = _convert_by(index)
93+
columns = _convert_by(columns)
6894

6995
if isinstance(aggfunc, list):
7096
pieces = []
7197
keys = []
7298
for func in aggfunc:
73-
table = pivot_table(data, values=values, rows=rows, cols=cols,
99+
table = pivot_table(data, values=values, index=index, columns=columns,
74100
fill_value=fill_value, aggfunc=func,
75101
margins=margins)
76102
pieces.append(table)
77103
keys.append(func.__name__)
78104
return concat(pieces, keys=keys, axis=1)
79105

80-
keys = rows + cols
106+
keys = index + columns
81107

82108
values_passed = values is not None
83109
if values_passed:
@@ -106,7 +132,7 @@ def pivot_table(data, values=None, rows=None, cols=None, aggfunc='mean',
106132
table = agged
107133
if table.index.nlevels > 1:
108134
to_unstack = [agged.index.names[i]
109-
for i in range(len(rows), len(keys))]
135+
for i in range(len(index), len(keys))]
110136
table = agged.unstack(to_unstack)
111137

112138
if not dropna:
@@ -132,14 +158,14 @@ def pivot_table(data, values=None, rows=None, cols=None, aggfunc='mean',
132158
table = table.fillna(value=fill_value, downcast='infer')
133159

134160
if margins:
135-
table = _add_margins(table, data, values, rows=rows,
136-
cols=cols, aggfunc=aggfunc)
161+
table = _add_margins(table, data, values, rows=index,
162+
cols=columns, aggfunc=aggfunc)
137163

138164
# discard the top level
139165
if values_passed and not values_multi:
140166
table = table[values[0]]
141167

142-
if len(rows) == 0 and len(cols) > 0:
168+
if len(index) == 0 and len(columns) > 0:
143169
table = table.T
144170

145171
return table
@@ -299,18 +325,18 @@ def _convert_by(by):
299325
return by
300326

301327

302-
def crosstab(rows, cols, values=None, rownames=None, colnames=None,
303-
aggfunc=None, margins=False, dropna=True):
328+
def crosstab(index, columns, values=None, rownames=None, colnames=None,
329+
aggfunc=None, margins=False, dropna=True, **kwarg):
304330
"""
305331
Compute a simple cross-tabulation of two (or more) factors. By default
306332
computes a frequency table of the factors unless an array of values and an
307333
aggregation function are passed
308334
309335
Parameters
310336
----------
311-
rows : array-like, Series, or list of arrays/Series
337+
index : array-like, Series, or list of arrays/Series
312338
Values to group by in the rows
313-
cols : array-like, Series, or list of arrays/Series
339+
columns : array-like, Series, or list of arrays/Series
314340
Values to group by in the columns
315341
values : array-like, optional
316342
Array of values to aggregate according to the factors
@@ -324,6 +350,8 @@ def crosstab(rows, cols, values=None, rownames=None, colnames=None,
324350
Add row/column margins (subtotals)
325351
dropna : boolean, default True
326352
Do not include columns whose entries are all NaN
353+
rows : kwarg only alias of index [deprecated]
354+
cols : kwarg only alias of columns [deprecated]
327355
328356
Notes
329357
-----
@@ -353,26 +381,48 @@ def crosstab(rows, cols, values=None, rownames=None, colnames=None,
353381
-------
354382
crosstab : DataFrame
355383
"""
356-
rows = com._maybe_make_list(rows)
357-
cols = com._maybe_make_list(cols)
384+
# Parse old-style keyword arguments
385+
rows = kwarg.pop('rows', None)
386+
if rows is not None:
387+
warnings.warn("rows is deprecated, use index", FutureWarning)
388+
if index is None:
389+
index = rows
390+
else:
391+
msg = "Can only specify either 'rows' or 'index'"
392+
raise TypeError(msg)
393+
394+
cols = kwarg.pop('cols', None)
395+
if cols is not None:
396+
warnings.warn("cols is deprecated, use columns", FutureWarning)
397+
if columns is None:
398+
columns = cols
399+
else:
400+
msg = "Can only specify either 'cols' or 'columns'"
401+
raise TypeError(msg)
402+
403+
if kwarg:
404+
raise TypeError("Unexpected argument(s): %s" % kwarg.keys())
405+
406+
index = com._maybe_make_list(index)
407+
columns = com._maybe_make_list(columns)
358408

359-
rownames = _get_names(rows, rownames, prefix='row')
360-
colnames = _get_names(cols, colnames, prefix='col')
409+
rownames = _get_names(index, rownames, prefix='row')
410+
colnames = _get_names(columns, colnames, prefix='col')
361411

362412
data = {}
363-
data.update(zip(rownames, rows))
364-
data.update(zip(colnames, cols))
413+
data.update(zip(rownames, index))
414+
data.update(zip(colnames, columns))
365415

366416
if values is None:
367417
df = DataFrame(data)
368418
df['__dummy__'] = 0
369-
table = df.pivot_table('__dummy__', rows=rownames, cols=colnames,
419+
table = df.pivot_table('__dummy__', index=rownames, columns=colnames,
370420
aggfunc=len, margins=margins, dropna=dropna)
371421
return table.fillna(0).astype(np.int64)
372422
else:
373423
data['__dummy__'] = values
374424
df = DataFrame(data)
375-
table = df.pivot_table('__dummy__', rows=rownames, cols=colnames,
425+
table = df.pivot_table('__dummy__', index=rownames, columns=colnames,
376426
aggfunc=aggfunc, margins=margins, dropna=dropna)
377427
return table
378428

0 commit comments

Comments
 (0)