`pd.DataFrame.to_xarray()` and `xr.Dataset(<pd.DataFrame>)` are not equivalent
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 4.2k
- Forks
- 1.4k
- Avg merge
- 2d 15h
- Merged PRs (30d)
- 14
Description
What is your issue?
Suppose we have a pandas DataFrame named df. df.to_xarray() and xr.Dataset(df) both cast the DataFrame to an xarray Dataset object, but they are not equivalent.
They handle multi-indexed DataFrames differently. Specifically:
df.to_xarray()
- Converts each level of the DataFrame MultIndex into a separate dimension for the resulting Dataset.
- Errors if the
DataFramehas more than one row for any unique set ofMultiIndexlevels - The resulting
Datasetsmoothly coverts back to the original pandasdfvia.to_dataframe()
xr.Dataset(df)
- Produces a dataset with a single, multi-indexed dimension whose coordinates are the levels of the pandas MultiIndex.
- Does not error if the
DataFramehas for than one row for any unique set ofMultiIndexlevels. - Converting back to pandas via
to_dataframe()does not yield the original dataframe, because of #10538
Reprex
import xarray as xr
import pandas as pd
df_unique_idx = (
pd.DataFrame(
dict(
x=[1, 2, 3, 1, 2, 3],
y=["a", "a", "a", "b", "b", "b"],
z=[5, 10, 15, 20, 25, 30],
)
)
.set_index(["x", "y"])
.sort_index()
)
ds_via_constructor = xr.Dataset(df_unique_idx)
print(ds_via_constructor) # single dim_0 with coordinates x and y
# <xarray.Dataset> Size: 192B
# Dimensions: (dim_0: 6)
# Coordinates:
# * dim_0 (dim_0) object 48B MultiIndex
# * x (dim_0) int64 48B 1 2 3 1 2 3
# * y (dim_0) object 48B 'a' 'a' 'a' 'b' 'b' 'b'
# Data variables:
# z (dim_0) int64 48B 5 10 15 20 25 30
ds_via_to_xarray = df_unique_idx.to_xarray()
print(ds_via_to_xarray) # x and y are dims
# <xarray.Dataset> Size: 88B
# Dimensions: (x: 3, y: 2)
# Coordinates:
# * x (x) int64 24B 1 2 3
# * y (y) object 16B 'a' 'b'
# Data variables:
# z (x, y) int64 48B 5 20 10 25 15 30
round_trip_via_constructor = ds_via_constructor.to_dataframe()
print(
round_trip_via_constructor.equals(df_unique_idx)
) # False because of duplicated columns, see issue #10538
print(round_trip_via_constructor)
# False
# x y z
# x y
# 1 a 1 a 5
# b 1 b 20
# 2 a 2 a 10
# b 2 b 25
# 3 a 3 a 15
# b 3 b 30
round_trip_via_to_xarray = ds_via_to_xarray.to_dataframe()
print(round_trip_via_to_xarray.equals(df_unique_idx)) # True
# True
# create a multi-indexed pandas dataframe
# with a non-unique MultiIndex
df_non_unique_idx = pd.DataFrame(
dict(
x=[1, 2, 3, 1, 2, 3, 1],
y=["a", "a", "a", "b", "b", "b", "a"],
z=[5, 10, 15, 20, 25, 30, 35],
)
).set_index(["x", "y"])
ds_via_constructor = xr.Dataset(df_non_unique_idx) # succeeds
try:
ds_via_to_xarray = df_non_unique_idx.to_xarray() # errors
except ValueError as e:
print(e)
# cannot convert a DataFrame with a non-unique MultiIndex into xarray
Thoughts
I don't think this is a bug per se, but it seems potentially surprising for the user that these two methods for converting DataFrame to Dataset behave so differently.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by running the pandas DataFrame and xarray Dataset conversion examples in the issue, including both unique and non-unique MultiIndexes. Compare the behavior of df.to_xarray(), xr.Dataset(df), and Dataset.to_dataframe(); the work is complete when the intended behavior is decided and the relevant round-trip inconsistency is resolved or clearly documented.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- data
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Needs clarification
- Newbie friendliness
- 30/100