add to_frame method to DataFrame
State: closed

Add convenience method which makes sure that we can safely call `to_frame` on any method returning both `Series` and `DataFrame` instances, such as `groupby` etc.

- [ ] ~~closes #11292 xxx~~ (there is no issue, should I open one?)
- [x] tests added / passed
- [x] passes `git diff upstream/master -u -- "*.py" | flake8 --diff`
- [x] whatsnew entry


Labels:
name: Enhancement
name: Needs Discussion
description: Requires discussion from core team before further action
name: DataFrame
description: DataFrame data structure

Comments:
Hello @letalvoj! Thanks for submitting the PR.

 - There are no PEP8 issues in the file [`pandas/core/frame.py`](https://github.com/letalvoj/pandas/blob/7038a7931784bc9a3607b2a0adbd6f0908509aa7/pandas/core/frame.py) !

 - There are no PEP8 issues in the file [`pandas/tests/sparse/frame/test_frame.py`](https://github.com/letalvoj/pandas/blob/7038a7931784bc9a3607b2a0adbd6f0908509aa7/pandas/tests/sparse/frame/test_frame.py) !


-0 on this. just cluttering the API. semantically this is alway wrong, it *should* copy.
Sometimes I find people struggling to use `groupby` + `apply` / `loc`. As these methods can easily return both `DataFrame` / `Series` given not only the params but the instance on which you call it as well. IMO this is more elegant then `isinstance`ing.

_ad. api_
I get the argument regarding the API. yet in a sense all the other classes have the method
 * Series.to_frame
 * Panel.to_frame

even some indices
 * Index.to_frame
 * MultiIndex.to_frame
 * DatetimeIndex.to_frame
 * TimedeltaIndex.to_frame

Therefore I feel like it's not _just some other random method_. Or is it?

_ad. copying_
Oh, right. The implementation is copy-on-write, right? Is it going to be a great overhead then?
What is the idiomatic way to copy the frame in this case?
# [Codecov](https://codecov.io/gh/pandas-dev/pandas/pull/24336?src=pr&el=h1) Report
> Merging [#24336](https://codecov.io/gh/pandas-dev/pandas/pull/24336?src=pr&el=desc) into [master](https://codecov.io/gh/pandas-dev/pandas/commit/6c8aabc0a076fd3597a708f81b4aad192b19822b?src=pr&el=desc) will **increase** coverage by `<.01%`.
> The diff coverage is `100%`.

[![Impacted file tree graph](https://codecov.io/gh/pandas-dev/pandas/pull/24336/graphs/tree.svg?width=650&token=eZ4WkYLtcO&height=150&src=pr)](https://codecov.io/gh/pandas-dev/pandas/pull/24336?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           master   #24336      +/-   ##
==========================================
+ Coverage   92.28%   92.28%   +<.01%     
==========================================
  Files         162      162              
  Lines       51833    51835       +2     
==========================================
+ Hits        47833    47835       +2     
  Misses       4000     4000
```

| Flag | Coverage Δ | |
|---|---|---|
| #multiple | `90.68% <100%> (ø)` | :arrow_up: |
| #single | `42.99% <50%> (-0.01%)` | :arrow_down: |

| [Impacted Files](https://codecov.io/gh/pandas-dev/pandas/pull/24336?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [pandas/core/frame.py](https://codecov.io/gh/pandas-dev/pandas/pull/24336/diff?src=pr&el=tree#diff-cGFuZGFzL2NvcmUvZnJhbWUucHk=) | `96.91% <100%> (ø)` | :arrow_up: |
| [pandas/core/indexes/period.py](https://codecov.io/gh/pandas-dev/pandas/pull/24336/diff?src=pr&el=tree#diff-cGFuZGFzL2NvcmUvaW5kZXhlcy9wZXJpb2QucHk=) | `93.06% <0%> (-0.04%)` | :arrow_down: |
| [pandas/core/reshape/tile.py](https://codecov.io/gh/pandas-dev/pandas/pull/24336/diff?src=pr&el=tree#diff-cGFuZGFzL2NvcmUvcmVzaGFwZS90aWxlLnB5) | `94.82% <0%> (+0.06%)` | :arrow_up: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/pandas-dev/pandas/pull/24336?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/pandas-dev/pandas/pull/24336?src=pr&el=footer). Last update [6c8aabc...7038a79](https://codecov.io/gh/pandas-dev/pandas/pull/24336?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

# [Codecov](https://codecov.io/gh/pandas-dev/pandas/pull/24336?src=pr&el=h1) Report
> Merging [#24336](https://codecov.io/gh/pandas-dev/pandas/pull/24336?src=pr&el=desc) into [master](https://codecov.io/gh/pandas-dev/pandas/commit/6c8aabc0a076fd3597a708f81b4aad192b19822b?src=pr&el=desc) will **increase** coverage by `<.01%`.
> The diff coverage is `100%`.

[![Impacted file tree graph](https://codecov.io/gh/pandas-dev/pandas/pull/24336/graphs/tree.svg?width=650&token=eZ4WkYLtcO&height=150&src=pr)](https://codecov.io/gh/pandas-dev/pandas/pull/24336?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           master   #24336      +/-   ##
==========================================
+ Coverage   92.28%   92.28%   +<.01%     
==========================================
  Files         162      162              
  Lines       51833    51835       +2     
==========================================
+ Hits        47833    47835       +2     
  Misses       4000     4000
```

| Flag | Coverage Δ | |
|---|---|---|
| #multiple | `90.68% <100%> (ø)` | :arrow_up: |
| #single | `42.99% <50%> (-0.01%)` | :arrow_down: |

| [Impacted Files](https://codecov.io/gh/pandas-dev/pandas/pull/24336?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [pandas/core/frame.py](https://codecov.io/gh/pandas-dev/pandas/pull/24336/diff?src=pr&el=tree#diff-cGFuZGFzL2NvcmUvZnJhbWUucHk=) | `96.91% <100%> (ø)` | :arrow_up: |
| [pandas/core/indexes/period.py](https://codecov.io/gh/pandas-dev/pandas/pull/24336/diff?src=pr&el=tree#diff-cGFuZGFzL2NvcmUvaW5kZXhlcy9wZXJpb2QucHk=) | `93.06% <0%> (-0.04%)` | :arrow_down: |
| [pandas/core/reshape/tile.py](https://codecov.io/gh/pandas-dev/pandas/pull/24336/diff?src=pr&el=tree#diff-cGFuZGFzL2NvcmUvcmVzaGFwZS90aWxlLnB5) | `94.82% <0%> (+0.06%)` | :arrow_up: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/pandas-dev/pandas/pull/24336?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/pandas-dev/pandas/pull/24336?src=pr&el=footer). Last update [6c8aabc...7038a79](https://codecov.io/gh/pandas-dev/pandas/pull/24336?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

I don't have a strong preference here. Probably +0.5 since it makes writing generic code for Series / Frame easier (although, you won't be able to use the `name` keyword).

FWIW, Series.to_frame doesn't copy.


```python
In [6]: s = pd.Series([1, 2])

In [7]: r = s.to_frame()

In [8]: s[0] = 10

In [9]: r
Out[9]:
    0
0  10
1   2
```

though it arguably should (as an option).
@letalvoj do you mind writing a real case example on when this would be useful. I understand your point, but would be useful for the discussion to see how a real example would look with and without `DataFrame.to_frame()`
@letalvoj I think this needs an issue for discussion. If you'd like to open one with a realistic usecase we can see if there is appetite. closing this for now.