nested-pandas 0.3.2__tar.gz → 0.3.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {nested_pandas-0.3.2 → nested_pandas-0.3.4}/.copier-answers.yml +2 -1
- nested_pandas-0.3.4/.github/ISSUE_TEMPLATE/README.md +9 -0
- nested_pandas-0.3.4/.github/workflows/README.md +9 -0
- {nested_pandas-0.3.2 → nested_pandas-0.3.4}/.github/workflows/asv-main.yml +1 -1
- {nested_pandas-0.3.2 → nested_pandas-0.3.4}/.github/workflows/asv-nightly.yml +1 -1
- {nested_pandas-0.3.2 → nested_pandas-0.3.4}/.github/workflows/asv-pr.yml +1 -1
- {nested_pandas-0.3.2 → nested_pandas-0.3.4}/.github/workflows/build-documentation.yml +2 -2
- {nested_pandas-0.3.2 → nested_pandas-0.3.4}/.github/workflows/pre-commit-ci.yml +2 -2
- {nested_pandas-0.3.2 → nested_pandas-0.3.4}/.github/workflows/publish-benchmarks-pr.yml +1 -1
- {nested_pandas-0.3.2 → nested_pandas-0.3.4}/.github/workflows/publish-to-pypi.yml +1 -1
- {nested_pandas-0.3.2 → nested_pandas-0.3.4}/.github/workflows/smoke-test.yml +1 -1
- {nested_pandas-0.3.2 → nested_pandas-0.3.4}/.github/workflows/testing-and-coverage.yml +2 -2
- {nested_pandas-0.3.2 → nested_pandas-0.3.4}/.pre-commit-config.yaml +1 -1
- {nested_pandas-0.3.2 → nested_pandas-0.3.4}/.readthedocs.yml +1 -1
- {nested_pandas-0.3.2 → nested_pandas-0.3.4}/PKG-INFO +40 -3
- {nested_pandas-0.3.2 → nested_pandas-0.3.4}/README.md +37 -1
- {nested_pandas-0.3.2 → nested_pandas-0.3.4}/benchmarks/asv.conf.json +1 -1
- nested_pandas-0.3.4/docs/gettingstarted/quickstart.ipynb +367 -0
- {nested_pandas-0.3.2 → nested_pandas-0.3.4}/docs/index.rst +37 -3
- nested_pandas-0.3.4/docs/intro_images/loc_into_nested.png +0 -0
- nested_pandas-0.3.4/docs/intro_images/nestedframe.png +0 -0
- nested_pandas-0.3.4/docs/intro_images/pandas_dfs.png +0 -0
- nested_pandas-0.3.4/docs/intro_images/reduce.png +0 -0
- {nested_pandas-0.3.2 → nested_pandas-0.3.4}/docs/tutorials/data_loading_notebook.ipynb +151 -15
- {nested_pandas-0.3.2 → nested_pandas-0.3.4}/pyproject.toml +1 -0
- {nested_pandas-0.3.2 → nested_pandas-0.3.4}/src/nested_pandas/_version.py +2 -2
- {nested_pandas-0.3.2 → nested_pandas-0.3.4}/src/nested_pandas/nestedframe/core.py +117 -43
- {nested_pandas-0.3.2 → nested_pandas-0.3.4}/src/nested_pandas/series/packer.py +36 -5
- {nested_pandas-0.3.2 → nested_pandas-0.3.4}/src/nested_pandas.egg-info/PKG-INFO +40 -3
- {nested_pandas-0.3.2 → nested_pandas-0.3.4}/src/nested_pandas.egg-info/SOURCES.txt +6 -1
- {nested_pandas-0.3.2 → nested_pandas-0.3.4}/tests/nested_pandas/nestedframe/test_nestedframe.py +77 -0
- {nested_pandas-0.3.2 → nested_pandas-0.3.4}/tests/nested_pandas/series/test_packer.py +60 -0
- nested_pandas-0.3.2/docs/gettingstarted/quickstart.ipynb +0 -233
- nested_pandas-0.3.2/nestedframe.png +0 -0
- {nested_pandas-0.3.2 → nested_pandas-0.3.4}/.git_archival.txt +0 -0
- {nested_pandas-0.3.2 → nested_pandas-0.3.4}/.gitattributes +0 -0
- {nested_pandas-0.3.2 → nested_pandas-0.3.4}/.github/ISSUE_TEMPLATE/0-general_issue.md +0 -0
- {nested_pandas-0.3.2 → nested_pandas-0.3.4}/.github/ISSUE_TEMPLATE/1-bug_report.md +0 -0
- {nested_pandas-0.3.2 → nested_pandas-0.3.4}/.github/ISSUE_TEMPLATE/2-feature_request.md +0 -0
- {nested_pandas-0.3.2 → nested_pandas-0.3.4}/.github/dependabot.yml +0 -0
- {nested_pandas-0.3.2 → nested_pandas-0.3.4}/.github/pull_request_template.md +0 -0
- {nested_pandas-0.3.2 → nested_pandas-0.3.4}/.gitignore +0 -0
- {nested_pandas-0.3.2 → nested_pandas-0.3.4}/.setup_dev.sh +0 -0
- {nested_pandas-0.3.2 → nested_pandas-0.3.4}/LICENSE +0 -0
- {nested_pandas-0.3.2 → nested_pandas-0.3.4}/benchmarks/README.md +0 -0
- {nested_pandas-0.3.2 → nested_pandas-0.3.4}/benchmarks/__init__.py +0 -0
- {nested_pandas-0.3.2 → nested_pandas-0.3.4}/benchmarks/benchmarks.py +0 -0
- {nested_pandas-0.3.2 → nested_pandas-0.3.4}/docs/Makefile +0 -0
- {nested_pandas-0.3.2 → nested_pandas-0.3.4}/docs/_static/custom.css +0 -0
- {nested_pandas-0.3.2 → nested_pandas-0.3.4}/docs/conf.py +0 -0
- {nested_pandas-0.3.2 → nested_pandas-0.3.4}/docs/gettingstarted/contributing.rst +0 -0
- {nested_pandas-0.3.2 → nested_pandas-0.3.4}/docs/gettingstarted/installation.rst +0 -0
- {nested_pandas-0.3.2 → nested_pandas-0.3.4}/docs/gettingstarted.rst +0 -0
- {nested_pandas-0.3.2 → nested_pandas-0.3.4}/docs/requirements.txt +0 -0
- {nested_pandas-0.3.2 → nested_pandas-0.3.4}/docs/tutorials/README.md +0 -0
- {nested_pandas-0.3.2 → nested_pandas-0.3.4}/docs/tutorials/data_manipulation.ipynb +0 -0
- {nested_pandas-0.3.2 → nested_pandas-0.3.4}/docs/tutorials/low_level.ipynb +0 -0
- {nested_pandas-0.3.2 → nested_pandas-0.3.4}/docs/tutorials/nested_spectra.ipynb +0 -0
- {nested_pandas-0.3.2 → nested_pandas-0.3.4}/docs/tutorials.rst +0 -0
- {nested_pandas-0.3.2 → nested_pandas-0.3.4}/setup.cfg +0 -0
- {nested_pandas-0.3.2 → nested_pandas-0.3.4}/src/nested_pandas/__init__.py +0 -0
- {nested_pandas-0.3.2 → nested_pandas-0.3.4}/src/nested_pandas/datasets/__init__.py +0 -0
- {nested_pandas-0.3.2 → nested_pandas-0.3.4}/src/nested_pandas/datasets/generation.py +0 -0
- {nested_pandas-0.3.2 → nested_pandas-0.3.4}/src/nested_pandas/nestedframe/__init__.py +0 -0
- {nested_pandas-0.3.2 → nested_pandas-0.3.4}/src/nested_pandas/nestedframe/io.py +0 -0
- {nested_pandas-0.3.2 → nested_pandas-0.3.4}/src/nested_pandas/py.typed +0 -0
- {nested_pandas-0.3.2 → nested_pandas-0.3.4}/src/nested_pandas/series/__init__.py +0 -0
- {nested_pandas-0.3.2 → nested_pandas-0.3.4}/src/nested_pandas/series/accessor.py +0 -0
- {nested_pandas-0.3.2 → nested_pandas-0.3.4}/src/nested_pandas/series/dtype.py +0 -0
- {nested_pandas-0.3.2 → nested_pandas-0.3.4}/src/nested_pandas/series/ext_array.py +0 -0
- {nested_pandas-0.3.2 → nested_pandas-0.3.4}/src/nested_pandas/series/utils.py +0 -0
- {nested_pandas-0.3.2 → nested_pandas-0.3.4}/src/nested_pandas/utils/__init__.py +0 -0
- {nested_pandas-0.3.2 → nested_pandas-0.3.4}/src/nested_pandas/utils/utils.py +0 -0
- {nested_pandas-0.3.2 → nested_pandas-0.3.4}/src/nested_pandas.egg-info/dependency_links.txt +0 -0
- {nested_pandas-0.3.2 → nested_pandas-0.3.4}/src/nested_pandas.egg-info/requires.txt +0 -0
- {nested_pandas-0.3.2 → nested_pandas-0.3.4}/src/nested_pandas.egg-info/top_level.txt +0 -0
- {nested_pandas-0.3.2 → nested_pandas-0.3.4}/tests/nested_pandas/conftest.py +0 -0
- {nested_pandas-0.3.2 → nested_pandas-0.3.4}/tests/nested_pandas/datasets/test_generation.py +0 -0
- {nested_pandas-0.3.2 → nested_pandas-0.3.4}/tests/nested_pandas/e2e_tests/test_issue89.py +0 -0
- {nested_pandas-0.3.2 → nested_pandas-0.3.4}/tests/nested_pandas/nestedframe/test_io.py +0 -0
- {nested_pandas-0.3.2 → nested_pandas-0.3.4}/tests/nested_pandas/series/test_accessor.py +0 -0
- {nested_pandas-0.3.2 → nested_pandas-0.3.4}/tests/nested_pandas/series/test_dtype.py +0 -0
- {nested_pandas-0.3.2 → nested_pandas-0.3.4}/tests/nested_pandas/series/test_ext_array.py +0 -0
- {nested_pandas-0.3.2 → nested_pandas-0.3.4}/tests/nested_pandas/test_packaging.py +0 -0
- {nested_pandas-0.3.2 → nested_pandas-0.3.4}/tests/nested_pandas/utils/test_utils.py +0 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# Changes here will be overwritten by Copier
|
|
2
|
-
_commit: v2.0.
|
|
2
|
+
_commit: v2.0.5
|
|
3
3
|
_src_path: gh:lincc-frameworks/python-project-template
|
|
4
4
|
author_email: brantd@uw.edu
|
|
5
5
|
author_name: LINCC Frameworks
|
|
@@ -22,3 +22,4 @@ python_versions:
|
|
|
22
22
|
- '3.10'
|
|
23
23
|
- '3.11'
|
|
24
24
|
- '3.12'
|
|
25
|
+
- '3.13'
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# Configurations
|
|
2
|
+
|
|
3
|
+
Templates for various different issue types are defined in this directory
|
|
4
|
+
and a pull request template is defined as ``../pull_request_template.md``. Adding,
|
|
5
|
+
removing, and modifying these templates to suit the needs of your project is encouraged.
|
|
6
|
+
|
|
7
|
+
For more information about these templates, look here: https://lincc-ppt.readthedocs.io/en/latest/practices/issue_pr_templating.html
|
|
8
|
+
|
|
9
|
+
Or if you still have questions contact us: https://lincc-ppt.readthedocs.io/en/latest/source/contact.html
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# Workflows
|
|
2
|
+
|
|
3
|
+
The .yml files in this directory are used to define the various continuous
|
|
4
|
+
integration scripts that will be run on your behalf e.g. nightly as a smoke check,
|
|
5
|
+
or when you create a new PR.
|
|
6
|
+
|
|
7
|
+
For more information about CI and workflows, look here: https://lincc-ppt.readthedocs.io/en/latest/practices/ci.html
|
|
8
|
+
|
|
9
|
+
Or if you still have questions contact us: https://lincc-ppt.readthedocs.io/en/latest/source/contact.html
|
|
@@ -21,10 +21,10 @@ jobs:
|
|
|
21
21
|
|
|
22
22
|
steps:
|
|
23
23
|
- uses: actions/checkout@v4
|
|
24
|
-
- name: Set up Python 3.
|
|
24
|
+
- name: Set up Python 3.11
|
|
25
25
|
uses: actions/setup-python@v5
|
|
26
26
|
with:
|
|
27
|
-
python-version: '3.
|
|
27
|
+
python-version: '3.11'
|
|
28
28
|
- name: Install dependencies
|
|
29
29
|
run: |
|
|
30
30
|
sudo apt-get update
|
|
@@ -20,7 +20,7 @@ jobs:
|
|
|
20
20
|
- name: Set up Python
|
|
21
21
|
uses: actions/setup-python@v5
|
|
22
22
|
with:
|
|
23
|
-
python-version: '3.
|
|
23
|
+
python-version: '3.11'
|
|
24
24
|
- name: Install dependencies
|
|
25
25
|
run: |
|
|
26
26
|
sudo apt-get update
|
|
@@ -32,5 +32,5 @@ jobs:
|
|
|
32
32
|
extra_args: --all-files --verbose
|
|
33
33
|
env:
|
|
34
34
|
SKIP: "check-lincc-frameworks-template-version,no-commit-to-branch,check-added-large-files,validate-pyproject,sphinx-build,pytest-check"
|
|
35
|
-
- uses: pre-commit-ci/lite-action@v1.0
|
|
35
|
+
- uses: pre-commit-ci/lite-action@v1.1.0
|
|
36
36
|
if: failure() && github.event_name == 'pull_request' && github.event.pull_request.draft == false
|
|
@@ -27,7 +27,7 @@ jobs:
|
|
|
27
27
|
echo "Conclusion: ${{ github.event.workflow_run.conclusion }}"
|
|
28
28
|
echo "Event: ${{ github.event.workflow_run.event }}"
|
|
29
29
|
- name: Download artifact
|
|
30
|
-
uses: dawidd6/action-download-artifact@
|
|
30
|
+
uses: dawidd6/action-download-artifact@v7
|
|
31
31
|
with:
|
|
32
32
|
name: benchmark-artifacts
|
|
33
33
|
run_id: ${{ github.event.workflow_run.id }}
|
|
@@ -15,7 +15,7 @@ jobs:
|
|
|
15
15
|
runs-on: ubuntu-latest
|
|
16
16
|
strategy:
|
|
17
17
|
matrix:
|
|
18
|
-
python-version: ['3.9', '3.10', '3.11', '3.12']
|
|
18
|
+
python-version: ['3.9', '3.10', '3.11', '3.12', '3.13']
|
|
19
19
|
|
|
20
20
|
steps:
|
|
21
21
|
- uses: actions/checkout@v4
|
|
@@ -33,6 +33,6 @@ jobs:
|
|
|
33
33
|
run: |
|
|
34
34
|
python -m pytest --cov=nested_pandas --cov-report=xml
|
|
35
35
|
- name: Upload coverage report to codecov
|
|
36
|
-
uses: codecov/codecov-action@
|
|
36
|
+
uses: codecov/codecov-action@v5
|
|
37
37
|
with:
|
|
38
38
|
token: ${{ secrets.CODECOV_TOKEN }}
|
|
@@ -18,7 +18,7 @@ repos:
|
|
|
18
18
|
description: Clear output from Jupyter notebooks.
|
|
19
19
|
files: \.ipynb$
|
|
20
20
|
exclude: ^docs/pre_executed
|
|
21
|
-
stages: [commit]
|
|
21
|
+
stages: [pre-commit]
|
|
22
22
|
language: system
|
|
23
23
|
entry: jupyter nbconvert --clear-output
|
|
24
24
|
# Prevents committing directly branches named 'main' and 'master'.
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
2
|
Name: nested-pandas
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.4
|
|
4
|
+
Summary: An extension of pandas for efficient representation of nested associated datasets.
|
|
4
5
|
Author-email: LINCC Frameworks <brantd@uw.edu>
|
|
5
6
|
License: MIT License
|
|
6
7
|
|
|
@@ -50,6 +51,9 @@ Requires-Dist: ruff; extra == "dev"
|
|
|
50
51
|
|
|
51
52
|
[](https://lincc-ppt.readthedocs.io/en/latest/)
|
|
52
53
|
|
|
54
|
+
[](https://pypi.org/project/nested-pandas/)
|
|
55
|
+
[](https://anaconda.org/conda-forge/nested-pandas)
|
|
56
|
+
|
|
53
57
|
[](https://github.com/lincc-frameworks/nested-pandas/actions/workflows/smoke-test.yml)
|
|
54
58
|
[](https://codecov.io/gh/lincc-frameworks/nested-pandas)
|
|
55
59
|
[](https://nested-pandas.readthedocs.io/)
|
|
@@ -63,7 +67,40 @@ tooling and support for nested dataframes packed into values of top-level
|
|
|
63
67
|
dataframe columns. [Pyarrow](https://arrow.apache.org/docs/python/index.html)
|
|
64
68
|
is used internally to aid in scalability and performance.
|
|
65
69
|
|
|
66
|
-
|
|
70
|
+
Nested-Pandas allows data like this:
|
|
71
|
+
|
|
72
|
+
<p align="center">
|
|
73
|
+
<img src="./docs/intro_images/pandas_dfs.png" alt="pandas dataframes" width="400"/>
|
|
74
|
+
</p>
|
|
75
|
+
|
|
76
|
+
To instead be represented like this:
|
|
77
|
+
|
|
78
|
+
<p align="center">
|
|
79
|
+
<img src="./docs/intro_images/nestedframe.png" alt="nestedframe" width="400"/>
|
|
80
|
+
</p>
|
|
81
|
+
|
|
82
|
+
Where the nested data is represented as nested dataframes:
|
|
83
|
+
|
|
84
|
+
```python
|
|
85
|
+
# Each row of "object_nf" now has it's own sub-dataframe of matched rows from "source_df"
|
|
86
|
+
object_nf.loc[0]["nested_sources"]
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
<p align="center">
|
|
90
|
+
<img src="./docs/intro_images/loc_into_nested.png" alt="sub-dataframe" width="225"/>
|
|
91
|
+
</p>
|
|
92
|
+
|
|
93
|
+
Allowing powerful and straightforward operations, like:
|
|
94
|
+
|
|
95
|
+
```python
|
|
96
|
+
# Compute the mean flux for each row of "object_nf"
|
|
97
|
+
import numpy as np
|
|
98
|
+
object_nf.reduce(np.mean, "nested_sources.flux")
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
<p align="center">
|
|
102
|
+
<img src="./docs/intro_images/reduce.png" alt="using reduce" width="150"/>
|
|
103
|
+
</p>
|
|
67
104
|
|
|
68
105
|
Nested-Pandas is motivated by time-domain astronomy use cases, where we see
|
|
69
106
|
typically two levels of information, information about astronomical objects and
|
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://lincc-ppt.readthedocs.io/en/latest/)
|
|
4
4
|
|
|
5
|
+
[](https://pypi.org/project/nested-pandas/)
|
|
6
|
+
[](https://anaconda.org/conda-forge/nested-pandas)
|
|
7
|
+
|
|
5
8
|
[](https://github.com/lincc-frameworks/nested-pandas/actions/workflows/smoke-test.yml)
|
|
6
9
|
[](https://codecov.io/gh/lincc-frameworks/nested-pandas)
|
|
7
10
|
[](https://nested-pandas.readthedocs.io/)
|
|
@@ -15,7 +18,40 @@ tooling and support for nested dataframes packed into values of top-level
|
|
|
15
18
|
dataframe columns. [Pyarrow](https://arrow.apache.org/docs/python/index.html)
|
|
16
19
|
is used internally to aid in scalability and performance.
|
|
17
20
|
|
|
18
|
-
|
|
21
|
+
Nested-Pandas allows data like this:
|
|
22
|
+
|
|
23
|
+
<p align="center">
|
|
24
|
+
<img src="./docs/intro_images/pandas_dfs.png" alt="pandas dataframes" width="400"/>
|
|
25
|
+
</p>
|
|
26
|
+
|
|
27
|
+
To instead be represented like this:
|
|
28
|
+
|
|
29
|
+
<p align="center">
|
|
30
|
+
<img src="./docs/intro_images/nestedframe.png" alt="nestedframe" width="400"/>
|
|
31
|
+
</p>
|
|
32
|
+
|
|
33
|
+
Where the nested data is represented as nested dataframes:
|
|
34
|
+
|
|
35
|
+
```python
|
|
36
|
+
# Each row of "object_nf" now has it's own sub-dataframe of matched rows from "source_df"
|
|
37
|
+
object_nf.loc[0]["nested_sources"]
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
<p align="center">
|
|
41
|
+
<img src="./docs/intro_images/loc_into_nested.png" alt="sub-dataframe" width="225"/>
|
|
42
|
+
</p>
|
|
43
|
+
|
|
44
|
+
Allowing powerful and straightforward operations, like:
|
|
45
|
+
|
|
46
|
+
```python
|
|
47
|
+
# Compute the mean flux for each row of "object_nf"
|
|
48
|
+
import numpy as np
|
|
49
|
+
object_nf.reduce(np.mean, "nested_sources.flux")
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
<p align="center">
|
|
53
|
+
<img src="./docs/intro_images/reduce.png" alt="using reduce" width="150"/>
|
|
54
|
+
</p>
|
|
19
55
|
|
|
20
56
|
Nested-Pandas is motivated by time-domain astronomy use cases, where we see
|
|
21
57
|
typically two levels of information, information about astronomical objects and
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
// The Pythons you'd like to test against. If not provided, defaults
|
|
38
38
|
// to the current version of Python used to run `asv`.
|
|
39
39
|
"pythons": [
|
|
40
|
-
"3.
|
|
40
|
+
"3.11"
|
|
41
41
|
],
|
|
42
42
|
// The matrix of dependencies to test. Each key is the name of a
|
|
43
43
|
// package (in PyPI) and the values are version numbers. An empty
|
|
@@ -0,0 +1,367 @@
|
|
|
1
|
+
{
|
|
2
|
+
"cells": [
|
|
3
|
+
{
|
|
4
|
+
"cell_type": "markdown",
|
|
5
|
+
"metadata": {},
|
|
6
|
+
"source": [
|
|
7
|
+
"# Quickstart\n",
|
|
8
|
+
"\n",
|
|
9
|
+
"This notebook provides a brief introduction to nested-pandas, including the motivation and basics for working with the data structure. For more in-depth descriptions, see the other tutorial notebooks."
|
|
10
|
+
]
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"cell_type": "markdown",
|
|
14
|
+
"metadata": {},
|
|
15
|
+
"source": [
|
|
16
|
+
"## Installation\n",
|
|
17
|
+
"\n",
|
|
18
|
+
"With a valid Python environment, nested-pandas and it's dependencies are easy to install using the `pip` package manager. The following command can be used to install it:"
|
|
19
|
+
]
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"cell_type": "code",
|
|
23
|
+
"execution_count": null,
|
|
24
|
+
"metadata": {},
|
|
25
|
+
"outputs": [],
|
|
26
|
+
"source": [
|
|
27
|
+
"# % pip install nested-pandas"
|
|
28
|
+
]
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
"cell_type": "markdown",
|
|
32
|
+
"metadata": {},
|
|
33
|
+
"source": [
|
|
34
|
+
"## Overview\n",
|
|
35
|
+
"\n",
|
|
36
|
+
"Nested-Pandas is tailored towards efficient analysis of nested data sets. This includes data that would normally be represented in a Pandas DataFrames with multiple rows needed to represent a single \"thing\" and therefor columns whose values will be identical for that item.\n",
|
|
37
|
+
"\n",
|
|
38
|
+
"As a concrete example, consider an astronomical data set storing information about observations of physical objects, such as stars and galaxies. One way to represent this in Pandas is to create one row per observation with an ID column indicating to which physical object the observation corresponds. However this approach ends up repeating a lot of data over each observation of the same object such as its location on the sky (RA, dec), its classification, etc. Further, any operations processing the data as time series requires the user to first perform a (potentially expensive) group-by operation to aggregate all of the data for each object.\n",
|
|
39
|
+
"\n",
|
|
40
|
+
"Let's create a flat pandas dataframe with three objects: object 0 has three observations, object 1 has three observations, and object 2 has 4 observations."
|
|
41
|
+
]
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
"cell_type": "code",
|
|
45
|
+
"execution_count": null,
|
|
46
|
+
"metadata": {},
|
|
47
|
+
"outputs": [],
|
|
48
|
+
"source": [
|
|
49
|
+
"import pandas as pd\n",
|
|
50
|
+
"\n",
|
|
51
|
+
"# Represent nested time series information as a classic pandas dataframe.\n",
|
|
52
|
+
"my_data_frame = pd.DataFrame(\n",
|
|
53
|
+
" {\n",
|
|
54
|
+
" \"id\": [0, 0, 0, 1, 1, 1, 2, 2, 2, 2],\n",
|
|
55
|
+
" \"ra\": [10.0, 10.0, 10.0, 15.0, 15.0, 15.0, 12.1, 12.1, 12.1, 12.1],\n",
|
|
56
|
+
" \"dec\": [0.0, 0.0, 0.0, -1.0, -1.0, -1.0, 0.5, 0.5, 0.5, 0.5],\n",
|
|
57
|
+
" \"time\": [60676.0, 60677.0, 60678.0, 60675.0, 60676.5, 60677.0, 60676.6, 60676.7, 60676.8, 60676.9],\n",
|
|
58
|
+
" \"brightness\": [100.0, 101.0, 99.8, 5.0, 5.01, 4.98, 20.1, 20.5, 20.3, 20.2],\n",
|
|
59
|
+
" }\n",
|
|
60
|
+
")\n",
|
|
61
|
+
"my_data_frame"
|
|
62
|
+
]
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
"cell_type": "markdown",
|
|
66
|
+
"metadata": {},
|
|
67
|
+
"source": [
|
|
68
|
+
"Note that we cannot cleanly compress this by adding more columns (such as such as t0, t1, and so forth), because the number of observations is not bounded and may vary from object to object.\n",
|
|
69
|
+
"\n",
|
|
70
|
+
"Beyond astronomical data we might be interested in tracking patients blood pressure over time, the measure of intensities of emitted light at different wavelengths, or storing a list of the type of rock found at different depths of core samples. In each case it is possible to represent this data with multiple rows (such as one row for each patient + measurement pair) and associate them together by ids.\n",
|
|
71
|
+
"\n",
|
|
72
|
+
"Nested-pandas is designed for exactly this type of data by allowing columns to contain nested data. We can have regular columns with the (single) value for the objects’ unvarying characteristics (location on the sky, patentient birth date, location of the core sample) and nested columns for the values of each observation.\n",
|
|
73
|
+
"\n",
|
|
74
|
+
"Let's see an example:"
|
|
75
|
+
]
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
"cell_type": "code",
|
|
79
|
+
"execution_count": null,
|
|
80
|
+
"metadata": {},
|
|
81
|
+
"outputs": [],
|
|
82
|
+
"source": [
|
|
83
|
+
"from nested_pandas.nestedframe import NestedFrame\n",
|
|
84
|
+
"\n",
|
|
85
|
+
"# Create a nested data set\n",
|
|
86
|
+
"nf = NestedFrame.from_flat(\n",
|
|
87
|
+
" my_data_frame,\n",
|
|
88
|
+
" base_columns=[\"ra\", \"dec\"], # the columns not to nest\n",
|
|
89
|
+
" nested_columns=[\"time\", \"brightness\"], # the columns to nest\n",
|
|
90
|
+
" on=\"id\", # column used to associate rows\n",
|
|
91
|
+
" name=\"lightcurve\", # name of the nested column\n",
|
|
92
|
+
")\n",
|
|
93
|
+
"nf"
|
|
94
|
+
]
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
"cell_type": "markdown",
|
|
98
|
+
"metadata": {},
|
|
99
|
+
"source": [
|
|
100
|
+
"The above dataframe is a `NestedFrame`, which extends the capabilities of the Pandas `DataFrame` to support columns with nested information. \n",
|
|
101
|
+
"\n",
|
|
102
|
+
"We now have the top level dataframe with 3 rows, each of which corresponds to a single object. The table has three columns beyond \"id\". Two columns, \"ra\" and \"dec\", have a single value for the object (in this case the position on the sky). The last column \"lightcurve\" contains a nested table with a series of observation times and observation brightnesses for the object. As we will see below, this nested table allows the user to easily access to the all of the observations for a given object.\n",
|
|
103
|
+
"\n",
|
|
104
|
+
"## Accessing Nested Data\n",
|
|
105
|
+
"\n",
|
|
106
|
+
"We can inspect the contents of the \"lightcurve\" column using pandas API tooling like `loc`."
|
|
107
|
+
]
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
"cell_type": "code",
|
|
111
|
+
"execution_count": null,
|
|
112
|
+
"metadata": {},
|
|
113
|
+
"outputs": [],
|
|
114
|
+
"source": [
|
|
115
|
+
"nf.loc[0][\"lightcurve\"]"
|
|
116
|
+
]
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
"cell_type": "markdown",
|
|
120
|
+
"metadata": {},
|
|
121
|
+
"source": [
|
|
122
|
+
"Here we see that within the \"lightcurve\" column there are tables with their own data. In this case we have 2 columns (\"time\" and \"brightness\") that represent a time series of observations. \n",
|
|
123
|
+
"\n",
|
|
124
|
+
"Note that `loc` itself accesses the row, so the combination of `nf.loc[0][\"lightcurve\"]` means we are looking at value in the \"lightcurve\" column for a single row (row 0). If we just use `nf.loc[0]` we would retrieve the entire row, including the nested \"lightcurve\" column and all other columns. Similarly if we use `nf[\"lightcurve]` we retrieve the nested column for all rows. What makes the nesting useful is that once we access the nested entry for a specific row, we can treat the value as a table in its own right.\n",
|
|
125
|
+
"\n",
|
|
126
|
+
"As in Pandas, we can still access individual entries from a column based on the row index. Thus we can access the values (in a table) in row 0 of the nested column as `nf[\"lightcurve\"][0]` as well."
|
|
127
|
+
]
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
"cell_type": "code",
|
|
131
|
+
"execution_count": null,
|
|
132
|
+
"metadata": {},
|
|
133
|
+
"outputs": [],
|
|
134
|
+
"source": [
|
|
135
|
+
"nf[\"lightcurve\"][0]"
|
|
136
|
+
]
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
"cell_type": "markdown",
|
|
140
|
+
"metadata": {},
|
|
141
|
+
"source": [
|
|
142
|
+
"We can also use dot notation to access all the values in a nested sub column:"
|
|
143
|
+
]
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
"cell_type": "code",
|
|
147
|
+
"execution_count": null,
|
|
148
|
+
"metadata": {},
|
|
149
|
+
"outputs": [],
|
|
150
|
+
"source": [
|
|
151
|
+
"nf[\"lightcurve.time\"]"
|
|
152
|
+
]
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
"cell_type": "markdown",
|
|
156
|
+
"metadata": {},
|
|
157
|
+
"source": [
|
|
158
|
+
"Note that \"lightcurve.time\" contains the time values for all rows, but also preserves the nesting information. The id column of the returned data maps the top-level row (in `nf`) to where this value resides.\n",
|
|
159
|
+
"\n",
|
|
160
|
+
"Similarly, we can access the values for a given top-level row by index. To get all the `time` values for row 0 we could specify:"
|
|
161
|
+
]
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
"cell_type": "code",
|
|
165
|
+
"execution_count": null,
|
|
166
|
+
"metadata": {},
|
|
167
|
+
"outputs": [],
|
|
168
|
+
"source": [
|
|
169
|
+
"nf[\"lightcurve.time\"][0]"
|
|
170
|
+
]
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
"cell_type": "markdown",
|
|
174
|
+
"metadata": {},
|
|
175
|
+
"source": [
|
|
176
|
+
"Here the `[0]` is telling our nested frame to access the values of the series `nf[\"lightcurve.time\"]` where the id = 0. If we try `nf[\"lightcurve.time\"][0][0]` we again match id = 0 and return the same frame. \n",
|
|
177
|
+
"\n",
|
|
178
|
+
"To access a single element within the series, we need to use its location:"
|
|
179
|
+
]
|
|
180
|
+
},
|
|
181
|
+
{
|
|
182
|
+
"cell_type": "code",
|
|
183
|
+
"execution_count": null,
|
|
184
|
+
"metadata": {},
|
|
185
|
+
"outputs": [],
|
|
186
|
+
"source": [
|
|
187
|
+
"nf[\"lightcurve.time\"][0].iloc[0]"
|
|
188
|
+
]
|
|
189
|
+
},
|
|
190
|
+
{
|
|
191
|
+
"cell_type": "markdown",
|
|
192
|
+
"metadata": {},
|
|
193
|
+
"source": [
|
|
194
|
+
"## Inspecting Nested Frames\n",
|
|
195
|
+
"\n",
|
|
196
|
+
"We can inspect the available columns using some custom properties of the `NestedFrame`."
|
|
197
|
+
]
|
|
198
|
+
},
|
|
199
|
+
{
|
|
200
|
+
"cell_type": "code",
|
|
201
|
+
"execution_count": null,
|
|
202
|
+
"metadata": {},
|
|
203
|
+
"outputs": [],
|
|
204
|
+
"source": [
|
|
205
|
+
"# Shows which columns have nested data\n",
|
|
206
|
+
"nf.nested_columns"
|
|
207
|
+
]
|
|
208
|
+
},
|
|
209
|
+
{
|
|
210
|
+
"cell_type": "code",
|
|
211
|
+
"execution_count": null,
|
|
212
|
+
"metadata": {},
|
|
213
|
+
"outputs": [],
|
|
214
|
+
"source": [
|
|
215
|
+
"# Provides a dictionary of \"base\" (top-level) and nested column labels\n",
|
|
216
|
+
"nf.all_columns"
|
|
217
|
+
]
|
|
218
|
+
},
|
|
219
|
+
{
|
|
220
|
+
"cell_type": "markdown",
|
|
221
|
+
"metadata": {},
|
|
222
|
+
"source": [
|
|
223
|
+
"## Pandas Operations\n",
|
|
224
|
+
"\n",
|
|
225
|
+
"Nested-pandas extends the Pandas API, meaning any operation you could do in Pandas is available within nested-pandas. However, nested-pandas has additional functionality and tooling to better support working with nested datasets. For example, let's look at `query`:"
|
|
226
|
+
]
|
|
227
|
+
},
|
|
228
|
+
{
|
|
229
|
+
"cell_type": "code",
|
|
230
|
+
"execution_count": null,
|
|
231
|
+
"metadata": {},
|
|
232
|
+
"outputs": [],
|
|
233
|
+
"source": [
|
|
234
|
+
"# Normal queries work as expected, rejecting rows from the dataframe that don't meet the criteria\n",
|
|
235
|
+
"nf.query(\"ra > 11.2\")"
|
|
236
|
+
]
|
|
237
|
+
},
|
|
238
|
+
{
|
|
239
|
+
"cell_type": "markdown",
|
|
240
|
+
"metadata": {},
|
|
241
|
+
"source": [
|
|
242
|
+
"The above query is native Pandas, however with nested-pandas we can use hierarchical column names to extend `query` to nested layers."
|
|
243
|
+
]
|
|
244
|
+
},
|
|
245
|
+
{
|
|
246
|
+
"cell_type": "code",
|
|
247
|
+
"execution_count": null,
|
|
248
|
+
"metadata": {},
|
|
249
|
+
"outputs": [],
|
|
250
|
+
"source": [
|
|
251
|
+
"# Applies the query to \"nested\", filtering based on \"time > 60676.0\"\n",
|
|
252
|
+
"nf_g = nf.query(\"lightcurve.time > 60676.0\")\n",
|
|
253
|
+
"nf_g"
|
|
254
|
+
]
|
|
255
|
+
},
|
|
256
|
+
{
|
|
257
|
+
"cell_type": "markdown",
|
|
258
|
+
"metadata": {},
|
|
259
|
+
"source": [
|
|
260
|
+
"This query does not affect the rows of the top-level dataframe, but rather applies the query to the \"nested\" dataframes. If we look at one of them, we can see the effect of the query."
|
|
261
|
+
]
|
|
262
|
+
},
|
|
263
|
+
{
|
|
264
|
+
"cell_type": "code",
|
|
265
|
+
"execution_count": null,
|
|
266
|
+
"metadata": {},
|
|
267
|
+
"outputs": [],
|
|
268
|
+
"source": [
|
|
269
|
+
"# All t <= 60676.0 have been removed\n",
|
|
270
|
+
"nf_g.loc[0][\"lightcurve\"]"
|
|
271
|
+
]
|
|
272
|
+
},
|
|
273
|
+
{
|
|
274
|
+
"cell_type": "markdown",
|
|
275
|
+
"metadata": {},
|
|
276
|
+
"source": [
|
|
277
|
+
"A limited set of functions have been extended in this way so far, with the aim being to fully support this hierarchical access where applicable in the Pandas API."
|
|
278
|
+
]
|
|
279
|
+
},
|
|
280
|
+
{
|
|
281
|
+
"cell_type": "markdown",
|
|
282
|
+
"metadata": {},
|
|
283
|
+
"source": [
|
|
284
|
+
"## Reduce Function\n",
|
|
285
|
+
"\n",
|
|
286
|
+
"Finally, we'll end with the flexible `reduce` function. `reduce` functions similarly to Pandas' `apply` but flattens (reduces) the inputs from nested layers into array inputs to the given apply function. For example, let's find the mean flux for each dataframe in \"nested\":"
|
|
287
|
+
]
|
|
288
|
+
},
|
|
289
|
+
{
|
|
290
|
+
"cell_type": "code",
|
|
291
|
+
"execution_count": null,
|
|
292
|
+
"metadata": {},
|
|
293
|
+
"outputs": [],
|
|
294
|
+
"source": [
|
|
295
|
+
"import numpy as np\n",
|
|
296
|
+
"\n",
|
|
297
|
+
"# use hierarchical column names to access the flux column\n",
|
|
298
|
+
"# passed as an array to np.mean\n",
|
|
299
|
+
"nf.reduce(np.mean, \"lightcurve.brightness\")"
|
|
300
|
+
]
|
|
301
|
+
},
|
|
302
|
+
{
|
|
303
|
+
"cell_type": "markdown",
|
|
304
|
+
"metadata": {},
|
|
305
|
+
"source": [
|
|
306
|
+
"This can be used to apply any custom functions you need for your analysis, and just to illustrate that point further let's define a custom function that just returns it's inputs."
|
|
307
|
+
]
|
|
308
|
+
},
|
|
309
|
+
{
|
|
310
|
+
"cell_type": "code",
|
|
311
|
+
"execution_count": null,
|
|
312
|
+
"metadata": {},
|
|
313
|
+
"outputs": [],
|
|
314
|
+
"source": [
|
|
315
|
+
"def show_inputs(*args):\n",
|
|
316
|
+
" return args"
|
|
317
|
+
]
|
|
318
|
+
},
|
|
319
|
+
{
|
|
320
|
+
"cell_type": "markdown",
|
|
321
|
+
"metadata": {},
|
|
322
|
+
"source": [
|
|
323
|
+
"Applying some inputs via reduce, we see how it sends inputs to a given function. The output frame `nf_inputs` consists of two columns containing the output of the “ra” column and the “lightcurve.time” column."
|
|
324
|
+
]
|
|
325
|
+
},
|
|
326
|
+
{
|
|
327
|
+
"cell_type": "code",
|
|
328
|
+
"execution_count": null,
|
|
329
|
+
"metadata": {},
|
|
330
|
+
"outputs": [],
|
|
331
|
+
"source": [
|
|
332
|
+
"nf_inputs = nf.reduce(show_inputs, \"ra\", \"lightcurve.time\")\n",
|
|
333
|
+
"nf_inputs"
|
|
334
|
+
]
|
|
335
|
+
},
|
|
336
|
+
{
|
|
337
|
+
"cell_type": "code",
|
|
338
|
+
"execution_count": null,
|
|
339
|
+
"metadata": {},
|
|
340
|
+
"outputs": [],
|
|
341
|
+
"source": [
|
|
342
|
+
"nf_inputs.loc[0]"
|
|
343
|
+
]
|
|
344
|
+
}
|
|
345
|
+
],
|
|
346
|
+
"metadata": {
|
|
347
|
+
"kernelspec": {
|
|
348
|
+
"display_name": "nested",
|
|
349
|
+
"language": "python",
|
|
350
|
+
"name": "python3"
|
|
351
|
+
},
|
|
352
|
+
"language_info": {
|
|
353
|
+
"codemirror_mode": {
|
|
354
|
+
"name": "ipython",
|
|
355
|
+
"version": 3
|
|
356
|
+
},
|
|
357
|
+
"file_extension": ".py",
|
|
358
|
+
"mimetype": "text/x-python",
|
|
359
|
+
"name": "python",
|
|
360
|
+
"nbconvert_exporter": "python",
|
|
361
|
+
"pygments_lexer": "ipython3",
|
|
362
|
+
"version": "3.10.4"
|
|
363
|
+
}
|
|
364
|
+
},
|
|
365
|
+
"nbformat": 4,
|
|
366
|
+
"nbformat_minor": 2
|
|
367
|
+
}
|