Skip to content

WIP: Panel Transpose Cleanup #25958

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 0 additions & 17 deletions pandas/compat/numpy/function.py
Original file line number Diff line number Diff line change
Expand Up @@ -282,23 +282,6 @@ def validate_take_with_convert(convert, args, kwargs):
method='both', max_fname_arg_count=0)


def validate_transpose_for_generic(inst, kwargs):
try:
validate_transpose(tuple(), kwargs)
except ValueError as e:
klass = type(inst).__name__
msg = str(e)

# the Panel class actual relies on the 'axes' parameter if called
# via the 'numpy' library, so let's make sure the error is specific
# about saying that the parameter is not supported for particular
# implementations of 'transpose'
if "the 'axes' parameter is not supported" in msg:
msg += " for {klass} instances".format(klass=klass)

raise ValueError(msg)


def validate_window_func(name, args, kwargs):
numpy_args = ('axis', 'dtype', 'out')
msg = ("numpy operations are not "
Expand Down
8 changes: 2 additions & 6 deletions pandas/core/frame.py
Original file line number Diff line number Diff line change
Expand Up @@ -2545,7 +2545,7 @@ def memory_usage(self, index=True, deep=False):
index=['Index']).append(result)
return result

def transpose(self, *args, **kwargs):
def transpose(self, copy=False):
"""
Transpose index and columns.

Expand All @@ -2558,9 +2558,6 @@ def transpose(self, *args, **kwargs):
copy : bool, default False
If True, the underlying data is copied. Otherwise (default), no
copy is made if possible.
*args, **kwargs
Additional keywords have no effect but might be accepted for
compatibility with numpy.

Returns
-------
Expand Down Expand Up @@ -2640,8 +2637,7 @@ def transpose(self, *args, **kwargs):
1 object
dtype: object
"""
nv.validate_transpose(args, dict())
return super(DataFrame, self).transpose(1, 0, **kwargs)
return super().transpose(copy)

T = property(transpose)

Expand Down
22 changes: 6 additions & 16 deletions pandas/core/generic.py
Original file line number Diff line number Diff line change
Expand Up @@ -306,9 +306,8 @@ def _construct_axes_from_arguments(
supplied; useful to distinguish when a user explicitly passes None
in scenarios where None has special meaning.
"""

# construct the args
args = list(args)
# construct the args
for a in self._AXIS_ORDERS:

# if we have an alias for this axis
Expand Down Expand Up @@ -651,32 +650,24 @@ def _set_axis(self, axis, labels):
self._data.set_axis(axis, labels)
self._clear_item_cache()

def transpose(self, *args, **kwargs):
def transpose(self, copy, valid_axes=[1, 0]):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you make the default valid_axes=None and then handle as appropriate within the method? Mutable default arguments can lead to problems so probably best to avoid just to be safe.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great callout! Do you think better to define here or even just move this code to the DataFrame class?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not super familiar with this, so don't want my opinion to carry too much weight, but I think it'd be cleaner to push this back to the DataFrame class and remove it from here entirely. If we're removing Panel.transpose then I think DataFrame is the only thing that uses this method, so seems more direct that way? Looks like Series/Index inherit from IndexOpsMixin and sparse things have their own implementation, so should be safe to remove unless I'm forgetting something?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We probably could move the "core" implementation into DataFrame, but I would think we should keep a skeleton implementation on transpose in NDFrame (even simple as raise NotImplemented, as transpose is arguably something that should be part of the implementation of anything that inherits from this base class).

"""
Permute the dimensions of the %(klass)s

Parameters
----------
args : %(args_transpose)s
copy : boolean, default False
Make a copy of the underlying data. Mixed-dtype data will
always result in a copy
**kwargs
Additional keyword arguments will be passed to the function.
valid_axes : list of str or int
Names / aliases for axes to be transposed.

Returns
-------
y : same as input

Examples
--------
>>> p.transpose(2, 0, 1)
>>> p.transpose(2, 0, 1, copy=True)
"""

# construct the args
axes, kwargs = self._construct_axes_from_arguments(args, kwargs,
require_all=True)
axes, kwargs = self._construct_axes_from_arguments(valid_axes, dict())
axes_names = tuple(self._get_axis_name(axes[a])
for a in self._AXIS_ORDERS)
axes_numbers = tuple(self._get_axis_number(axes[a])
Expand All @@ -689,10 +680,9 @@ def transpose(self, *args, **kwargs):
new_axes = self._construct_axes_dict_from(self, [self._get_axis(x)
for x in axes_names])
new_values = self.values.transpose(axes_numbers)
if kwargs.pop('copy', None) or (len(args) and args[-1]):
if copy:
new_values = new_values.copy()

nv.validate_transpose_for_generic(self, kwargs)
return self._constructor(new_values, **new_axes).__finalize__(self)

def swapaxes(self, axis1, axis2, copy=True):
Expand Down
19 changes: 0 additions & 19 deletions pandas/core/panel.py
Original file line number Diff line number Diff line change
Expand Up @@ -1264,25 +1264,6 @@ def reindex_axis(self, labels, axis=0, method=None, level=None, copy=True,
copy=copy, limit=limit,
fill_value=fill_value)

@Substitution(**_shared_doc_kwargs)
@Appender(NDFrame.transpose.__doc__)
def transpose(self, *args, **kwargs):
# check if a list of axes was passed in instead as a
# single *args element
if (len(args) == 1 and hasattr(args[0], '__iter__') and
not is_string_like(args[0])):
axes = args[0]
else:
axes = args

if 'axes' in kwargs and axes:
raise TypeError("transpose() got multiple values for "
"keyword argument 'axes'")
elif not axes:
axes = kwargs.pop('axes', ())

return super(Panel, self).transpose(*axes, **kwargs)

@Substitution(**_shared_doc_kwargs)
@Appender(NDFrame.fillna.__doc__)
def fillna(self, value=None, method=None, axis=None, inplace=False,
Expand Down