A series broadcast along a frame's columns needs text labels, so s + df raises
- Dominant language
- Mojo
- Stars
- 1
- Forks
- 0
- PR merge metrics
- PR metrics pending
Description
Measured against pandas 3.0.5 and firepanda at the head of the Python arithmetic work.
```python
pd.Series([1, 2]) + pd.DataFrame({"x": [1, 2]}) # a frame, columns ['x', 0, 1], every cell NaN
fp.Series([1, 2]) + fp.DataFrame({"x": [1, 2]}) # TypeError: a series broadcast along the
# columns is matched up by name, so its row
# labels have to be text, and these are int64
```
An operator between a frame and a series broadcasts along the columns, because an operator has no argument to choose an axis with and the columns are the axis pandas picks. Broadcasting along the columns means matching the series' row labels against the frame's column names. firepanda's column names are text, so the core requires the series' labels to be text too and refuses when they are not.
pandas does not refuse. It takes the union of the frame's column names and the series' labels, which here is `['x', 0, 1]`, and answers a frame in which every cell is missing because no name is in both. That is a useless answer to a question nobody meant to ask, and it is the answer pandas gives.
### Why this is worth fixing rather than defending
The refusal is the better behaviour in isolation and it is the wrong one to have. `s + df` is a normal expression and the Python layer already does the right thing with it, which is to return `NotImplemented` from the series so Python turns the expression round and asks `DataFrame.__radd__`. Everything up to the core is correct and then the core declines.
It also cannot be worked around from Python today, because `Series` refuses an `index=` argument, so there is no way to build a series with text labels from Python at all. Every `s + df` and every `df.add(s)` without `axis=0` raises, whatever the caller does.
### What it needs
An index of text labels and an index of integer labels have no labels in common, which is a true statement and is all the operation needs. The union of the two is the frame's columns followed by the series' labels, and every column of the answer is null because every name is in exactly one side. That is the same code path an ordinary disjoint union already takes, so the fix is to let the axes be different types rather than to write a new case.
The obstacle is that a frame's column names are `String` and a row label is a `Value`, and the union of the two has to be spelled somewhere. That is the same question #154 has to answer for the `Index` type generally, so this may be cheaper after that lands than before it.
Found while writing `python/tests/test_arith.py`, which asserts the current refusal so that fixing this shows up as a failing test rather than as nothing.
Contributor guide
Assessment
This issue has not been assessed yet.