From 79fd502f44ea90a4ee6c8e6c3d3d94042f58d571 Mon Sep 17 00:00:00 2001 From: Doug Branton Date: Wed, 13 Dec 2023 15:46:16 -0800 Subject: [PATCH 01/14] WIP; adding batch by band functionality --- src/tape/ensemble.py | 107 +++++++++++++++++++++++++----- src/tape/ensemble_frame.py | 5 ++ tests/tape_tests/test_ensemble.py | 17 ++--- 3 files changed, 104 insertions(+), 25 deletions(-) diff --git a/src/tape/ensemble.py b/src/tape/ensemble.py index 3c2bb2c6..56be0596 100644 --- a/src/tape/ensemble.py +++ b/src/tape/ensemble.py @@ -1008,7 +1008,7 @@ def bin_sources( self.source.set_dirty(True) return self - def batch(self, func, *args, meta=None, use_map=True, compute=True, on=None, label="", **kwargs): + def batch(self, func, *args, meta=None, by_band=False, use_map=True, on=None, label="", **kwargs): """Run a function from tape.TimeSeries on the available ids Parameters @@ -1032,6 +1032,15 @@ def batch(self, func, *args, meta=None, use_map=True, compute=True, on=None, lab the results. Overridden by TAPE for TAPE and `light-curve` functions. If none, attempts to coerce the result to a pandas.Series. + by_band: `boolean` + If true, the lightcurves are split into separate inputs for each + band and passed along to the function individually. If the band + column is already specified in `on` then `batch` will check to make + sure the band column is the final element in `on` (if not this will + error out). Each band function result will be returned as a column + of the result dataframe. If False, the full lightcurve is passed + along to the function (again, assuming the band column in not + already part of `on`). use_map : `boolean` Determines whether `dask.dataframe.DataFrame.map_partitions` is used (True). Using map_partitions is generally more efficient, but @@ -1039,13 +1048,11 @@ def batch(self, func, *args, meta=None, use_map=True, compute=True, on=None, lab partition. This can be checked using `Ensemble.check_lightcurve_cohesion`. If False, a groupby will be performed instead. - compute: `boolean` - Determines whether to compute the result immediately or hold for a - later compute call. - on: 'str' or 'list' + on: 'str' or 'list', optional Designates which column(s) to groupby. Columns may be from the - source or object tables. For TAPE and `light-curve` functions - this is populated automatically. + source or object tables. If not specified, then the id column is + used by default. For TAPE and `light-curve` functions this is + populated automatically. label: 'str', optional If provided the ensemble will use this label to track the result dataframe. If not provided, a label of the from "result_{x}" where x @@ -1110,6 +1117,16 @@ def s2n_inter_quartile_range(flux, err): if isinstance(on, str): on = [on] # Convert to list if only one column is passed + if by_band: + if self._band_col not in on: + on += [self._band_col] + elif ( + on[-1] != self._band_col + ): # Unsure if this is neccesary but it seems likely to produce wrong behavior + raise ValueError( + "If `by_band` is true, the band column must be the last column specified in `on`" + ) + # Handle object columns to group on source_cols = list(self.source.columns) object_cols = list(self.object.columns) @@ -1126,11 +1143,11 @@ def s2n_inter_quartile_range(flux, err): if use_map: # use map_partitions id_col = self._id_col # need to grab this before mapping batch = source_to_batch.map_partitions( - lambda x: x.groupby(on, group_keys=False).apply( + lambda x: x.groupby(on, group_keys=True).apply( lambda y: func( *[y[arg].to_numpy() if arg != id_col else y.index.to_numpy() for arg in args], **kwargs, - ) + ), ), meta=meta, ) @@ -1142,6 +1159,66 @@ def s2n_inter_quartile_range(flux, err): meta=meta, ) + # Output standardization + if isinstance(batch, EnsembleSeries): + batch = batch.rename("result").to_frame() + print(type(batch)) + if len(on) > 1: + batch = batch.reset_index() + # Need to overwrite the meta manually as the multiindex will be + # interpretted by dask as a single "index" column + batch._meta = TapeFrame(columns=on + ["result"]) + if by_band: + batch = batch.categorize("band").pivot_table( + index=on[0], columns=self._band_col, aggfunc="sum" + ) + + # Need to once again reestablish meta for the pivot + band_labels = batch.columns.values + + out_cols = [] + for col in ["result"]: + for band in band_labels: + out_cols += [(str(col), str(band))] + batch._meta = TapeFrame(columns=out_cols) + + # Flatten the columns to a new column per band + batch.columns = ["_".join(col).strip() for col in batch.columns.values] + else: + batch = batch.set_index(on[0], sort=False) + + elif isinstance(batch, EnsembleFrame): + print("EnsembleFrame") + if len(on) > 1: + res_cols = list(batch._meta.columns) + print(isinstance(batch, EnsembleFrame)) + batch = batch.reset_index() + batch._meta = TapeFrame(columns=on + res_cols) + print(isinstance(batch, EnsembleFrame)) + if by_band: + batch = batch.categorize("band") + print(isinstance(batch, EnsembleFrame)) + batch = batch.pivot_table(index=on[0], columns=self._band_col, aggfunc="sum") + print(isinstance(batch, EnsembleFrame)) + + # Need to once again reestablish meta for the pivot + band_labels = batch.columns.values + + out_cols = [] + for col in res_cols[::-1]: + for band in band_labels: + out_cols += [(str(col), str(band))] + batch._meta = TapeFrame(columns=out_cols) + print(isinstance(batch, EnsembleFrame)) + + # Flatten the columns to a new column per band + batch.columns = ["_".join(col).strip() for col in batch.columns.values] + print(isinstance(batch, EnsembleFrame)) + + else: + batch = batch.set_index(on[0], sort=False) + print(isinstance(batch, EnsembleFrame)) + # Inherit divisions if known from source and the resulting index is the id # Groupby on index should always return a subset that adheres to the same divisions criteria if self.source.known_divisions and batch.index.name == self._id_col: @@ -1154,10 +1231,8 @@ def s2n_inter_quartile_range(flux, err): # Track the result frame under the provided label self.add_frame(batch, label) - if compute: - return batch.compute() - else: - return batch + print(isinstance(batch, EnsembleFrame)) + return batch def from_pandas( self, @@ -1859,7 +1934,7 @@ def _build_index(self, obj_id, band): index = pd.MultiIndex.from_tuples(tuples, names=["object_id", "band", "index"]) return index - def sf2(self, sf_method="basic", argument_container=None, use_map=True, compute=True): + def sf2(self, sf_method="basic", argument_container=None, use_map=True): """Wrapper interface for calling structurefunction2 on the ensemble Parameters @@ -1903,9 +1978,7 @@ def sf2(self, sf_method="basic", argument_container=None, use_map=True, compute= ) else: - result = self.batch( - calc_sf2, use_map=use_map, argument_container=argument_container, compute=compute - ) + result = self.batch(calc_sf2, use_map=use_map, argument_container=argument_container) # Inherit divisions information if known if self.source.known_divisions and self.object.known_divisions: diff --git a/src/tape/ensemble_frame.py b/src/tape/ensemble_frame.py index 7a910f51..2a68c672 100644 --- a/src/tape/ensemble_frame.py +++ b/src/tape/ensemble_frame.py @@ -433,6 +433,11 @@ def dropna(self, **kwargs): result.set_dirty(True) return result + def pivot_table(self, **kwargs): + """""" + result = self._propagate_metadata(super().pivot_table(**kwargs)) + return result + def persist(self, **kwargs): """Persist this dask collection into memory diff --git a/tests/tape_tests/test_ensemble.py b/tests/tape_tests/test_ensemble.py index 4e580fdc..ca708189 100644 --- a/tests/tape_tests/test_ensemble.py +++ b/tests/tape_tests/test_ensemble.py @@ -1624,13 +1624,15 @@ def test_batch(data_fixture, request, use_map, on): result = ( parquet_ensemble.prune(10) .dropna(table="source") - .batch(calc_stetson_J, use_map=use_map, on=on, band_to_calc=None, compute=False, label="stetson_j") + .batch(calc_stetson_J, use_map=use_map, on=on, band_to_calc=None, label="stetson_j") ) # Validate that the ensemble is now tracking a new result frame. assert len(parquet_ensemble.frames) == frame_cnt + 1 tracked_result = parquet_ensemble.select_frame("stetson_j") - assert isinstance(tracked_result, EnsembleSeries) + + print(tracked_result) + assert isinstance(tracked_result, EnsembleFrame) assert result is tracked_result # Make sure that divisions information is propagated if known @@ -1811,7 +1813,7 @@ def test_sf2(data_fixture, request, method, combine, sthresh, use_map=False): arg_container.bin_count_target = sthresh if not combine: - res_sf2 = parquet_ensemble.sf2(argument_container=arg_container, use_map=use_map, compute=False) + res_sf2 = parquet_ensemble.sf2(argument_container=arg_container, use_map=use_map) else: res_sf2 = parquet_ensemble.sf2(argument_container=arg_container, use_map=use_map) res_batch = parquet_ensemble.batch(calc_sf2, use_map=use_map, argument_container=arg_container) @@ -1821,10 +1823,9 @@ def test_sf2(data_fixture, request, method, combine, sthresh, use_map=False): assert res_sf2.known_divisions if combine: - assert not res_sf2.equals(res_batch) # output should be different + assert not res_sf2.equals(res_batch.compute()) # output should be different else: - res_sf2 = res_sf2.compute() - assert res_sf2.equals(res_batch) # output should be identical + assert res_sf2.compute().equals(res_batch.compute()) # output should be identical @pytest.mark.parametrize("sf_method", ["basic", "macleod_2012", "bauer_2009a", "bauer_2009b", "schmidt_2010"]) @@ -1839,7 +1840,7 @@ def test_sf2_methods(parquet_ensemble, sf_method, use_map=False): arg_container.bin_count_target = 50 arg_container.sf_method = sf_method - res_sf2 = parquet_ensemble.sf2(argument_container=arg_container, use_map=use_map) - res_batch = parquet_ensemble.batch(calc_sf2, use_map=use_map, argument_container=arg_container) + res_sf2 = parquet_ensemble.sf2(argument_container=arg_container, use_map=use_map).compute() + res_batch = parquet_ensemble.batch(calc_sf2, use_map=use_map, argument_container=arg_container).compute() assert res_sf2.equals(res_batch) # output should be identical From b16aab71159b4593c231881cb99549b1900ac62d Mon Sep 17 00:00:00 2001 From: Doug Branton Date: Wed, 13 Dec 2023 17:47:41 -0800 Subject: [PATCH 02/14] WIP: unit tests passing --- src/tape/ensemble.py | 13 +++-- src/tape/ensemble_frame.py | 5 -- tests/tape_tests/test_ensemble.py | 65 +++++++++++---------- tests/tape_tests/test_feature_extraction.py | 2 +- 4 files changed, 44 insertions(+), 41 deletions(-) diff --git a/src/tape/ensemble.py b/src/tape/ensemble.py index 56be0596..4abe9915 100644 --- a/src/tape/ensemble.py +++ b/src/tape/ensemble.py @@ -1094,6 +1094,8 @@ def s2n_inter_quartile_range(flux, err): amplitudes = ens.batch(np.ptp, ens._flux_col) ``` """ + + print("In Batch") self._lazy_sync_tables(table="all") # Convert light-curve package feature into analysis function @@ -1161,7 +1163,10 @@ def s2n_inter_quartile_range(flux, err): # Output standardization if isinstance(batch, EnsembleSeries): - batch = batch.rename("result").to_frame() + print("EnsembleSeries") + if batch.name == self._id_col: + batch = batch.rename("result") + batch = EnsembleFrame.from_dask_dataframe(batch.to_frame()) print(type(batch)) if len(on) > 1: batch = batch.reset_index() @@ -1169,9 +1174,9 @@ def s2n_inter_quartile_range(flux, err): # interpretted by dask as a single "index" column batch._meta = TapeFrame(columns=on + ["result"]) if by_band: - batch = batch.categorize("band").pivot_table( + batch = EnsembleFrame.from_dask_dataframe(batch.categorize("band").pivot_table( index=on[0], columns=self._band_col, aggfunc="sum" - ) + )) # Need to once again reestablish meta for the pivot band_labels = batch.columns.values @@ -1198,7 +1203,7 @@ def s2n_inter_quartile_range(flux, err): if by_band: batch = batch.categorize("band") print(isinstance(batch, EnsembleFrame)) - batch = batch.pivot_table(index=on[0], columns=self._band_col, aggfunc="sum") + batch = EnsembleFrame.from_dask_dataframe(batch.pivot_table(index=on[0], columns=self._band_col, aggfunc="sum")) print(isinstance(batch, EnsembleFrame)) # Need to once again reestablish meta for the pivot diff --git a/src/tape/ensemble_frame.py b/src/tape/ensemble_frame.py index 2a68c672..7a910f51 100644 --- a/src/tape/ensemble_frame.py +++ b/src/tape/ensemble_frame.py @@ -433,11 +433,6 @@ def dropna(self, **kwargs): result.set_dirty(True) return result - def pivot_table(self, **kwargs): - """""" - result = self._propagate_metadata(super().pivot_table(**kwargs)) - return result - def persist(self, **kwargs): """Persist this dask collection into memory diff --git a/tests/tape_tests/test_ensemble.py b/tests/tape_tests/test_ensemble.py index ca708189..93110030 100644 --- a/tests/tape_tests/test_ensemble.py +++ b/tests/tape_tests/test_ensemble.py @@ -318,16 +318,16 @@ def test_from_rrl_dataset(dask_client): # larger dataset, let's just use a subset ens.prune(350) - res = ens.batch(calc_stetson_J) + res = ens.batch(calc_stetson_J).compute() - assert 377927 in res.index # find a specific object + assert 377927 in res.index.values # find a specific object # Check Stetson J results for a specific object - assert res[377927]["g"] == pytest.approx(9.676014, rel=0.001) - assert res[377927]["i"] == pytest.approx(14.22723, rel=0.001) - assert res[377927]["r"] == pytest.approx(6.958200, rel=0.001) - assert res[377927]["u"] == pytest.approx(9.499280, rel=0.001) - assert res[377927]["z"] == pytest.approx(14.03794, rel=0.001) + assert res.loc[377927][0]["g"] == pytest.approx(9.676014, rel=0.001) + assert res.loc[377927][0]["i"] == pytest.approx(14.22723, rel=0.001) + assert res.loc[377927][0]["r"] == pytest.approx(6.958200, rel=0.001) + assert res.loc[377927][0]["u"] == pytest.approx(9.499280, rel=0.001) + assert res.loc[377927][0]["z"] == pytest.approx(14.03794, rel=0.001) def test_from_qso_dataset(dask_client): @@ -341,16 +341,16 @@ def test_from_qso_dataset(dask_client): # larger dataset, let's just use a subset ens.prune(650) - res = ens.batch(calc_stetson_J) + res = ens.batch(calc_stetson_J).compute() - assert 1257836 in res # find a specific object + assert 1257836 in res.index.values # find a specific object # Check Stetson J results for a specific object - assert res.loc[1257836]["g"] == pytest.approx(411.19885, rel=0.001) - assert res.loc[1257836]["i"] == pytest.approx(86.371310, rel=0.001) - assert res.loc[1257836]["r"] == pytest.approx(133.56796, rel=0.001) - assert res.loc[1257836]["u"] == pytest.approx(231.93229, rel=0.001) - assert res.loc[1257836]["z"] == pytest.approx(53.013018, rel=0.001) + assert res.loc[1257836][0]["g"] == pytest.approx(411.19885, rel=0.001) + assert res.loc[1257836][0]["i"] == pytest.approx(86.371310, rel=0.001) + assert res.loc[1257836][0]["r"] == pytest.approx(133.56796, rel=0.001) + assert res.loc[1257836][0]["u"] == pytest.approx(231.93229, rel=0.001) + assert res.loc[1257836][0]["z"] == pytest.approx(53.013018, rel=0.001) def test_read_rrl_dataset(dask_client): @@ -363,16 +363,16 @@ def test_read_rrl_dataset(dask_client): # larger dataset, let's just use a subset ens.prune(350) - res = ens.batch(calc_stetson_J) + res = ens.batch(calc_stetson_J).compute() - assert 377927 in res.index # find a specific object + assert 377927 in res.index.values # find a specific object # Check Stetson J results for a specific object - assert res[377927]["g"] == pytest.approx(9.676014, rel=0.001) - assert res[377927]["i"] == pytest.approx(14.22723, rel=0.001) - assert res[377927]["r"] == pytest.approx(6.958200, rel=0.001) - assert res[377927]["u"] == pytest.approx(9.499280, rel=0.001) - assert res[377927]["z"] == pytest.approx(14.03794, rel=0.001) + assert res.loc[377927][0]["g"] == pytest.approx(9.676014, rel=0.001) + assert res.loc[377927][0]["i"] == pytest.approx(14.22723, rel=0.001) + assert res.loc[377927][0]["r"] == pytest.approx(6.958200, rel=0.001) + assert res.loc[377927][0]["u"] == pytest.approx(9.499280, rel=0.001) + assert res.loc[377927][0]["z"] == pytest.approx(14.03794, rel=0.001) def test_read_qso_dataset(dask_client): @@ -385,16 +385,16 @@ def test_read_qso_dataset(dask_client): # larger dataset, let's just use a subset ens.prune(650) - res = ens.batch(calc_stetson_J) + res = ens.batch(calc_stetson_J).compute() - assert 1257836 in res # find a specific object + assert 1257836 in res.index.values # find a specific object # Check Stetson J results for a specific object - assert res.loc[1257836]["g"] == pytest.approx(411.19885, rel=0.001) - assert res.loc[1257836]["i"] == pytest.approx(86.371310, rel=0.001) - assert res.loc[1257836]["r"] == pytest.approx(133.56796, rel=0.001) - assert res.loc[1257836]["u"] == pytest.approx(231.93229, rel=0.001) - assert res.loc[1257836]["z"] == pytest.approx(53.013018, rel=0.001) + assert res.loc[1257836][0]["g"] == pytest.approx(411.19885, rel=0.001) + assert res.loc[1257836][0]["i"] == pytest.approx(86.371310, rel=0.001) + assert res.loc[1257836][0]["r"] == pytest.approx(133.56796, rel=0.001) + assert res.loc[1257836][0]["u"] == pytest.approx(231.93229, rel=0.001) + assert res.loc[1257836][0]["z"] == pytest.approx(53.013018, rel=0.001) def test_from_source_dict(dask_client): @@ -1642,8 +1642,9 @@ def test_batch(data_fixture, request, use_map, on): result = result.compute() if on is None: - assert pytest.approx(result.values[0]["g"], 0.001) == -0.04174282 - assert pytest.approx(result.values[0]["r"], 0.001) == 0.6075282 + print(result.values[0]) + assert pytest.approx(result.values[0][0]["g"], 0.001) == -0.04174282 + assert pytest.approx(result.values[0][0]["r"], 0.001) == 0.6075282 elif on is ["ps1_objid", "filterName"]: # In case where we group on id and band, the structure changes assert pytest.approx(result.values[1]["r"], 0.001) == 0.6075282 assert pytest.approx(result.values[0]["g"], 0.001) == -0.04174282 @@ -1701,6 +1702,7 @@ def test_batch_with_custom_func(parquet_ensemble): @pytest.mark.parametrize( "custom_meta", [ + ("flux_mean", float), # A tuple representing a series ("flux_mean", float), # A tuple representing a series pd.Series(name="flux_mean_pandas", dtype="float64"), TapeSeries(name="flux_mean_tape", dtype="float64"), @@ -1716,12 +1718,13 @@ def test_batch_with_custom_series_meta(parquet_ensemble, custom_meta): assert len(parquet_ensemble.frames) == num_frames + 1 assert len(parquet_ensemble.select_frame("flux_mean")) > 0 - assert isinstance(parquet_ensemble.select_frame("flux_mean"), EnsembleSeries) + assert isinstance(parquet_ensemble.select_frame("flux_mean"), EnsembleFrame) @pytest.mark.parametrize( "custom_meta", [ + {"lc_id": int, "band": str, "dt": float, "sf2": float, "1_sigma": float}, {"lc_id": int, "band": str, "dt": float, "sf2": float, "1_sigma": float}, [("lc_id", int), ("band", str), ("dt", float), ("sf2", float), ("1_sigma", float)], pd.DataFrame( diff --git a/tests/tape_tests/test_feature_extraction.py b/tests/tape_tests/test_feature_extraction.py index 6fdd394b..9cf70d18 100644 --- a/tests/tape_tests/test_feature_extraction.py +++ b/tests/tape_tests/test_feature_extraction.py @@ -51,7 +51,7 @@ def test_multiple_features_with_ensemble(dask_client): result = ens.batch( extractor, band_to_calc="g", - ) + ).compute() assert result.shape == (2, 3) assert_array_equal(result.columns, ["anderson_darling_normal", "inter_percentile_range_25", "stetson_K"]) From 2f6159b2e9aa434e15ce74701cfaef2e6cd3a398 Mon Sep 17 00:00:00 2001 From: Doug Branton Date: Thu, 14 Dec 2023 10:32:03 -0800 Subject: [PATCH 03/14] doc updates --- docs/examples/rrlyr-period.ipynb | 195 +++++++++++++++++- docs/gettingstarted/quickstart.ipynb | 2 +- docs/tutorials/scaling_to_large_data.ipynb | 2 +- .../using_ray_with_the_ensemble.ipynb | 4 +- .../tutorials/working_with_the_ensemble.ipynb | 8 +- 5 files changed, 193 insertions(+), 18 deletions(-) diff --git a/docs/examples/rrlyr-period.ipynb b/docs/examples/rrlyr-period.ipynb index 2dfa0089..2bba9002 100644 --- a/docs/examples/rrlyr-period.ipynb +++ b/docs/examples/rrlyr-period.ipynb @@ -14,7 +14,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 1, "id": "initial_id", "metadata": { "ExecuteTime": { @@ -31,7 +31,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 2, "id": "fecf2313f49ad1ac", "metadata": { "ExecuteTime": { @@ -39,7 +39,22 @@ "start_time": "2023-09-20T13:16:49.340873Z" } }, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/Users/dbranton/lincc/timeseries/tape/src/tape/ensemble.py:1816: UserWarning: Divisions are not known, syncing using a non-lazy method.\n", + " warnings.warn(\"Divisions are not known, syncing using a non-lazy method.\")\n", + "/Users/dbranton/lincc/timeseries/tape/src/tape/ensemble.py:1838: UserWarning: Divisions are not known, syncing using a non-lazy method.\n", + " warnings.warn(\"Divisions are not known, syncing using a non-lazy method.\")\n", + "/Users/dbranton/lincc/timeseries/tape/src/tape/ensemble.py:1366: UserWarning: Divisions for object are not set, certain downstream dask operations may fail as a result. We recommend setting the `sort` or `sorted` flags when loading data to establish division information.\n", + " warnings.warn(\n", + "/Users/dbranton/lincc/timeseries/tape/src/tape/ensemble.py:1366: UserWarning: Divisions for source are not set, certain downstream dask operations may fail as a result. We recommend setting the `sort` or `sorted` flags when loading data to establish division information.\n", + " warnings.warn(\n" + ] + } + ], "source": [ "# Load SDSS Stripe 82 RR Lyrae catalog\n", "ens = Ensemble(client=False).from_dataset('s82_rrlyrae')" @@ -47,7 +62,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 4, "id": "5c2dd5a5fd58ce00", "metadata": { "ExecuteTime": { @@ -55,7 +70,146 @@ "start_time": "2023-09-20T13:16:53.706738Z" } }, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "In Batch\n", + "EnsembleFrame\n", + "Using generated label, result_2, for a batch result.\n", + "True\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/Users/dbranton/lincc/timeseries/tape/src/tape/ensemble.py:1838: UserWarning: Divisions are not known, syncing using a non-lazy method.\n", + " warnings.warn(\"Divisions are not known, syncing using a non-lazy method.\")\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
period_0period_s_to_n_0
#id
40990.64175119.061786
133500.54798318.542068
159270.61227517.760715
204060.63185818.430296
219920.62586720.105611
.........
49566810.49953114.800598
49830750.64670721.350409
49846620.63687619.130252
49924180.58037820.278448
50116340.55723119.749291
\n", + "

483 rows × 2 columns

\n", + "
" + ], + "text/plain": [ + " period_0 period_s_to_n_0\n", + "#id \n", + "4099 0.641751 19.061786\n", + "13350 0.547983 18.542068\n", + "15927 0.612275 17.760715\n", + "20406 0.631858 18.430296\n", + "21992 0.625867 20.105611\n", + "... ... ...\n", + "4956681 0.499531 14.800598\n", + "4983075 0.646707 21.350409\n", + "4984662 0.636876 19.130252\n", + "4992418 0.580378 20.278448\n", + "5011634 0.557231 19.749291\n", + "\n", + "[483 rows x 2 columns]" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 7.21 s, sys: 76.3 ms, total: 7.29 s\n", + "Wall time: 7.3 s\n" + ] + } + ], "source": [ "%%time\n", "\n", @@ -66,7 +220,7 @@ "periodogram = Periodogram(peaks=1, nyquist=0.1, max_freq_factor=10, fast=False)\n", "\n", "# Use r band only\n", - "df = ens.batch(periodogram, band_to_calc='r')\n", + "df = ens.batch(periodogram, band_to_calc='r').compute()\n", "display(df)\n", "\n", "# Find RR Lyr with the most confient period\n", @@ -76,7 +230,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 5, "id": "f79ad1eb83d0d125", "metadata": { "ExecuteTime": { @@ -84,7 +238,28 @@ "start_time": "2023-09-20T13:17:00.548017Z" } }, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "Text(0, 0.5, 'Magnitude')" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], "source": [ "# Plot folded light curve\n", "ts = ens.to_timeseries(id)\n", @@ -121,13 +296,13 @@ "language_info": { "codemirror_mode": { "name": "ipython", - "version": 2 + "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", - "pygments_lexer": "ipython2", + "pygments_lexer": "ipython3", "version": "3.10.11" }, "vscode": { diff --git a/docs/gettingstarted/quickstart.ipynb b/docs/gettingstarted/quickstart.ipynb index 110442df..580dc39c 100644 --- a/docs/gettingstarted/quickstart.ipynb +++ b/docs/gettingstarted/quickstart.ipynb @@ -108,7 +108,7 @@ "source": [ "from tape.analysis import calc_sf2\n", "result = ens.batch(calc_sf2, sf_method=\"macleod_2012\") # The batch function applies the provided function to all individual lightcurves within the Ensemble\n", - "result" + "result.compute()" ] }, { diff --git a/docs/tutorials/scaling_to_large_data.ipynb b/docs/tutorials/scaling_to_large_data.ipynb index 9e38f6d2..6624b7e2 100644 --- a/docs/tutorials/scaling_to_large_data.ipynb +++ b/docs/tutorials/scaling_to_large_data.ipynb @@ -263,7 +263,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.13" + "version": "3.10.6" }, "vscode": { "interpreter": { diff --git a/docs/tutorials/using_ray_with_the_ensemble.ipynb b/docs/tutorials/using_ray_with_the_ensemble.ipynb index b19ca28f..93f1bf8f 100644 --- a/docs/tutorials/using_ray_with_the_ensemble.ipynb +++ b/docs/tutorials/using_ray_with_the_ensemble.ipynb @@ -151,7 +151,7 @@ "ens = Ensemble()\n", "ens.from_dataset(\"s82_qso\")\n", "ens.source = ens.source.repartition(npartitions=10)\n", - "ens.batch(calc_sf2, use_map=False)" + "ens.batch(calc_sf2, use_map=False).compute()" ] } ], @@ -171,7 +171,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.13" + "version": "3.10.11" }, "vscode": { "interpreter": { diff --git a/docs/tutorials/working_with_the_ensemble.ipynb b/docs/tutorials/working_with_the_ensemble.ipynb index 5908fa58..47eeeced 100644 --- a/docs/tutorials/working_with_the_ensemble.ipynb +++ b/docs/tutorials/working_with_the_ensemble.ipynb @@ -814,7 +814,7 @@ "outputs": [], "source": [ "# Applying the function to the ensemble\n", - "res = ens.batch(my_flux_average, \"flux\", \"band\", compute=True, meta=None, method=\"median\")\n", + "res = ens.batch(my_flux_average, \"flux\", \"band\", meta=None, method=\"median\").compute()\n", "res" ] }, @@ -849,7 +849,7 @@ ], "metadata": { "kernelspec": { - "display_name": "py310", + "display_name": "Python 3", "language": "python", "name": "python3" }, @@ -863,11 +863,11 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.13" + "version": "3.10.11" }, "vscode": { "interpreter": { - "hash": "08968836a6367873274ed1d5e98a07391f42fc3a62bd5aba54afbd7b11ba8673" + "hash": "83afbb17b435d9bf8b0d0042367da76f26510da1c5781f0ff6e6c518eab621ec" } } }, From a16a19b00191fa6495a73cf086bacab631e32f53 Mon Sep 17 00:00:00 2001 From: Doug Branton Date: Thu, 14 Dec 2023 10:32:29 -0800 Subject: [PATCH 04/14] doc updates --- docs/examples/rrlyr-period.ipynb | 189 ++----------------------------- 1 file changed, 7 insertions(+), 182 deletions(-) diff --git a/docs/examples/rrlyr-period.ipynb b/docs/examples/rrlyr-period.ipynb index 2bba9002..d55fa80b 100644 --- a/docs/examples/rrlyr-period.ipynb +++ b/docs/examples/rrlyr-period.ipynb @@ -14,7 +14,7 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": null, "id": "initial_id", "metadata": { "ExecuteTime": { @@ -31,7 +31,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, "id": "fecf2313f49ad1ac", "metadata": { "ExecuteTime": { @@ -39,22 +39,7 @@ "start_time": "2023-09-20T13:16:49.340873Z" } }, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/Users/dbranton/lincc/timeseries/tape/src/tape/ensemble.py:1816: UserWarning: Divisions are not known, syncing using a non-lazy method.\n", - " warnings.warn(\"Divisions are not known, syncing using a non-lazy method.\")\n", - "/Users/dbranton/lincc/timeseries/tape/src/tape/ensemble.py:1838: UserWarning: Divisions are not known, syncing using a non-lazy method.\n", - " warnings.warn(\"Divisions are not known, syncing using a non-lazy method.\")\n", - "/Users/dbranton/lincc/timeseries/tape/src/tape/ensemble.py:1366: UserWarning: Divisions for object are not set, certain downstream dask operations may fail as a result. We recommend setting the `sort` or `sorted` flags when loading data to establish division information.\n", - " warnings.warn(\n", - "/Users/dbranton/lincc/timeseries/tape/src/tape/ensemble.py:1366: UserWarning: Divisions for source are not set, certain downstream dask operations may fail as a result. We recommend setting the `sort` or `sorted` flags when loading data to establish division information.\n", - " warnings.warn(\n" - ] - } - ], + "outputs": [], "source": [ "# Load SDSS Stripe 82 RR Lyrae catalog\n", "ens = Ensemble(client=False).from_dataset('s82_rrlyrae')" @@ -62,7 +47,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": null, "id": "5c2dd5a5fd58ce00", "metadata": { "ExecuteTime": { @@ -70,146 +55,7 @@ "start_time": "2023-09-20T13:16:53.706738Z" } }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "In Batch\n", - "EnsembleFrame\n", - "Using generated label, result_2, for a batch result.\n", - "True\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/Users/dbranton/lincc/timeseries/tape/src/tape/ensemble.py:1838: UserWarning: Divisions are not known, syncing using a non-lazy method.\n", - " warnings.warn(\"Divisions are not known, syncing using a non-lazy method.\")\n" - ] - }, - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
period_0period_s_to_n_0
#id
40990.64175119.061786
133500.54798318.542068
159270.61227517.760715
204060.63185818.430296
219920.62586720.105611
.........
49566810.49953114.800598
49830750.64670721.350409
49846620.63687619.130252
49924180.58037820.278448
50116340.55723119.749291
\n", - "

483 rows × 2 columns

\n", - "
" - ], - "text/plain": [ - " period_0 period_s_to_n_0\n", - "#id \n", - "4099 0.641751 19.061786\n", - "13350 0.547983 18.542068\n", - "15927 0.612275 17.760715\n", - "20406 0.631858 18.430296\n", - "21992 0.625867 20.105611\n", - "... ... ...\n", - "4956681 0.499531 14.800598\n", - "4983075 0.646707 21.350409\n", - "4984662 0.636876 19.130252\n", - "4992418 0.580378 20.278448\n", - "5011634 0.557231 19.749291\n", - "\n", - "[483 rows x 2 columns]" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "CPU times: user 7.21 s, sys: 76.3 ms, total: 7.29 s\n", - "Wall time: 7.3 s\n" - ] - } - ], + "outputs": [], "source": [ "%%time\n", "\n", @@ -230,7 +76,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": null, "id": "f79ad1eb83d0d125", "metadata": { "ExecuteTime": { @@ -238,28 +84,7 @@ "start_time": "2023-09-20T13:17:00.548017Z" } }, - "outputs": [ - { - "data": { - "text/plain": [ - "Text(0, 0.5, 'Magnitude')" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "# Plot folded light curve\n", "ts = ens.to_timeseries(id)\n", From 236390d151dd5a289417b8a309b52959c4ed2373 Mon Sep 17 00:00:00 2001 From: Doug Branton Date: Thu, 14 Dec 2023 10:32:59 -0800 Subject: [PATCH 05/14] test updates --- tests/tape_tests/test_ensemble.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/tape_tests/test_ensemble.py b/tests/tape_tests/test_ensemble.py index 93110030..ef151271 100644 --- a/tests/tape_tests/test_ensemble.py +++ b/tests/tape_tests/test_ensemble.py @@ -1702,7 +1702,6 @@ def test_batch_with_custom_func(parquet_ensemble): @pytest.mark.parametrize( "custom_meta", [ - ("flux_mean", float), # A tuple representing a series ("flux_mean", float), # A tuple representing a series pd.Series(name="flux_mean_pandas", dtype="float64"), TapeSeries(name="flux_mean_tape", dtype="float64"), @@ -1724,7 +1723,6 @@ def test_batch_with_custom_series_meta(parquet_ensemble, custom_meta): @pytest.mark.parametrize( "custom_meta", [ - {"lc_id": int, "band": str, "dt": float, "sf2": float, "1_sigma": float}, {"lc_id": int, "band": str, "dt": float, "sf2": float, "1_sigma": float}, [("lc_id", int), ("band", str), ("dt", float), ("sf2", float), ("1_sigma", float)], pd.DataFrame( From 0efba3d2847992003c35c82c55c2772ac90fe7e3 Mon Sep 17 00:00:00 2001 From: Doug Branton Date: Thu, 14 Dec 2023 10:50:26 -0800 Subject: [PATCH 06/14] black run --- src/tape/ensemble.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/tape/ensemble.py b/src/tape/ensemble.py index 4abe9915..0bf83b91 100644 --- a/src/tape/ensemble.py +++ b/src/tape/ensemble.py @@ -1174,9 +1174,11 @@ def s2n_inter_quartile_range(flux, err): # interpretted by dask as a single "index" column batch._meta = TapeFrame(columns=on + ["result"]) if by_band: - batch = EnsembleFrame.from_dask_dataframe(batch.categorize("band").pivot_table( - index=on[0], columns=self._band_col, aggfunc="sum" - )) + batch = EnsembleFrame.from_dask_dataframe( + batch.categorize("band").pivot_table( + index=on[0], columns=self._band_col, aggfunc="sum" + ) + ) # Need to once again reestablish meta for the pivot band_labels = batch.columns.values @@ -1203,7 +1205,9 @@ def s2n_inter_quartile_range(flux, err): if by_band: batch = batch.categorize("band") print(isinstance(batch, EnsembleFrame)) - batch = EnsembleFrame.from_dask_dataframe(batch.pivot_table(index=on[0], columns=self._band_col, aggfunc="sum")) + batch = EnsembleFrame.from_dask_dataframe( + batch.pivot_table(index=on[0], columns=self._band_col, aggfunc="sum") + ) print(isinstance(batch, EnsembleFrame)) # Need to once again reestablish meta for the pivot From f13e3cdd7f82893e15548d04074e7ee250198778 Mon Sep 17 00:00:00 2001 From: Doug Branton Date: Fri, 15 Dec 2023 09:30:07 -0800 Subject: [PATCH 07/14] update with compute --- tests/tape_tests/test_feature_extraction.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/tape_tests/test_feature_extraction.py b/tests/tape_tests/test_feature_extraction.py index 9cf70d18..73aaa3b5 100644 --- a/tests/tape_tests/test_feature_extraction.py +++ b/tests/tape_tests/test_feature_extraction.py @@ -84,7 +84,7 @@ def test_otsu_with_ensemble_all_bands(dask_client): result = ens.batch( licu.OtsuSplit(), band_to_calc=None, - ) + ).compute() assert result.shape == (2, 4) assert_array_equal( From 35fc80fb66c78bff31fc461677adf8cd46fcc57e Mon Sep 17 00:00:00 2001 From: Doug Branton Date: Fri, 15 Dec 2023 12:17:18 -0800 Subject: [PATCH 08/14] update compute calls --- docs/tutorials/working_with_the_ensemble.ipynb | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/tutorials/working_with_the_ensemble.ipynb b/docs/tutorials/working_with_the_ensemble.ipynb index 47eeeced..1e43d3de 100644 --- a/docs/tutorials/working_with_the_ensemble.ipynb +++ b/docs/tutorials/working_with_the_ensemble.ipynb @@ -552,7 +552,7 @@ "# using tape analysis functions\n", "from tape.analysis import calc_stetson_J\n", "\n", - "res = ens.batch(calc_stetson_J, compute=True) # compute is set to true to execute immediately (non-lazily)\n", + "res = ens.batch(calc_stetson_J)\n", "res" ] }, @@ -598,7 +598,7 @@ "metadata": {}, "outputs": [], "source": [ - "res = ens.batch(calc_stetson_J, compute=True, label=\"stetson_j\")\n", + "res = ens.batch(calc_stetson_J, label=\"stetson_j\")\n", "\n", "ens.select_frame(\"stetson_j\").compute()" ] @@ -708,7 +708,7 @@ "print(\"Updated object table is now dirty: \" + str(ens.object.is_dirty()))\n", "\n", "print(\"Length of the Source table before the batch operation: \" + str(len(ens.source)))\n", - "res = ens.batch(calc_stetson_J, compute=True)\n", + "res = ens.batch(calc_stetson_J).compute()\n", "print(\"Post-computation object table is now dirty: \" + str(ens.object.is_dirty()))\n", "print(\"Length of the Source table after the batch operation: \" + str(len(ens.source)))\n", "res" @@ -751,8 +751,8 @@ "\n", "extractor = licu.Extractor(licu.Amplitude(), licu.AndersonDarlingNormal(), licu.StetsonK())\n", "# band_to_calc=None will ignore the band column and use all sources for each object\n", - "res = ens.batch(extractor, compute=True, band_to_calc=\"g\")\n", - "res" + "res = ens.batch(extractor, band_to_calc=\"g\")\n", + "res.compute()" ] }, { @@ -814,8 +814,8 @@ "outputs": [], "source": [ "# Applying the function to the ensemble\n", - "res = ens.batch(my_flux_average, \"flux\", \"band\", meta=None, method=\"median\").compute()\n", - "res" + "res = ens.batch(my_flux_average, \"flux\", \"band\", meta=None, method=\"median\")\n", + "res.compute()" ] }, { From 1a56e64c33eb08721f8b10ea3d13860427be1856 Mon Sep 17 00:00:00 2001 From: Doug Branton Date: Fri, 15 Dec 2023 15:21:02 -0800 Subject: [PATCH 09/14] add unit tests --- src/tape/ensemble.py | 34 ++++++--------- tests/tape_tests/test_ensemble.py | 69 +++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+), 22 deletions(-) diff --git a/src/tape/ensemble.py b/src/tape/ensemble.py index 0bf83b91..5506e676 100644 --- a/src/tape/ensemble.py +++ b/src/tape/ensemble.py @@ -1095,7 +1095,6 @@ def s2n_inter_quartile_range(flux, err): ``` """ - print("In Batch") self._lazy_sync_tables(table="all") # Convert light-curve package feature into analysis function @@ -1163,52 +1162,44 @@ def s2n_inter_quartile_range(flux, err): # Output standardization if isinstance(batch, EnsembleSeries): - print("EnsembleSeries") if batch.name == self._id_col: batch = batch.rename("result") batch = EnsembleFrame.from_dask_dataframe(batch.to_frame()) - print(type(batch)) if len(on) > 1: batch = batch.reset_index() # Need to overwrite the meta manually as the multiindex will be # interpretted by dask as a single "index" column batch._meta = TapeFrame(columns=on + ["result"]) + if by_band: - batch = EnsembleFrame.from_dask_dataframe( - batch.categorize("band").pivot_table( - index=on[0], columns=self._band_col, aggfunc="sum" - ) + batch = batch.categorize(self._band_col).pivot_table( + index=on[0], columns=self._band_col, aggfunc="sum" ) # Need to once again reestablish meta for the pivot band_labels = batch.columns.values - out_cols = [] for col in ["result"]: for band in band_labels: out_cols += [(str(col), str(band))] batch._meta = TapeFrame(columns=out_cols) - # Flatten the columns to a new column per band batch.columns = ["_".join(col).strip() for col in batch.columns.values] + + # The pivot returns a dask dataframe, need to convert back + batch = EnsembleFrame.from_dask_dataframe(batch) + else: batch = batch.set_index(on[0], sort=False) elif isinstance(batch, EnsembleFrame): - print("EnsembleFrame") if len(on) > 1: res_cols = list(batch._meta.columns) - print(isinstance(batch, EnsembleFrame)) batch = batch.reset_index() batch._meta = TapeFrame(columns=on + res_cols) - print(isinstance(batch, EnsembleFrame)) if by_band: - batch = batch.categorize("band") - print(isinstance(batch, EnsembleFrame)) - batch = EnsembleFrame.from_dask_dataframe( - batch.pivot_table(index=on[0], columns=self._band_col, aggfunc="sum") - ) - print(isinstance(batch, EnsembleFrame)) + batch = batch.categorize(self._band_col) + batch = batch.pivot_table(index=on[0], columns=self._band_col, aggfunc="sum") # Need to once again reestablish meta for the pivot band_labels = batch.columns.values @@ -1218,15 +1209,15 @@ def s2n_inter_quartile_range(flux, err): for band in band_labels: out_cols += [(str(col), str(band))] batch._meta = TapeFrame(columns=out_cols) - print(isinstance(batch, EnsembleFrame)) # Flatten the columns to a new column per band batch.columns = ["_".join(col).strip() for col in batch.columns.values] - print(isinstance(batch, EnsembleFrame)) + + # The pivot returns a dask dataframe, need to convert back + batch = EnsembleFrame.from_dask_dataframe(batch) else: batch = batch.set_index(on[0], sort=False) - print(isinstance(batch, EnsembleFrame)) # Inherit divisions if known from source and the resulting index is the id # Groupby on index should always return a subset that adheres to the same divisions criteria @@ -1240,7 +1231,6 @@ def s2n_inter_quartile_range(flux, err): # Track the result frame under the provided label self.add_frame(batch, label) - print(isinstance(batch, EnsembleFrame)) return batch def from_pandas( diff --git a/tests/tape_tests/test_ensemble.py b/tests/tape_tests/test_ensemble.py index ef151271..a576828f 100644 --- a/tests/tape_tests/test_ensemble.py +++ b/tests/tape_tests/test_ensemble.py @@ -1653,6 +1653,75 @@ def test_batch(data_fixture, request, use_map, on): assert pytest.approx(result.values[1]["r"], 0.001) == -0.49639028 +@pytest.mark.parametrize("on", [None, ["ps1_objid", "filterName"]]) +@pytest.mark.parametrize("func_label", ["mean", "bounds"]) +def test_batch_by_band(parquet_ensemble, func_label, on): + """ + Test that ensemble.batch(by_band=True) works as intended. + """ + + if func_label == "mean": + + def my_mean(flux): + """returns a single value""" + return np.mean(flux) + + res = parquet_ensemble.batch(my_mean, parquet_ensemble._flux_col, on=on, by_band=True) + + parquet_ensemble.source.query(f"{parquet_ensemble._band_col}=='g'").update_ensemble() + filter_res = parquet_ensemble.batch(my_mean, parquet_ensemble._flux_col, on=on, by_band=False) + + # An EnsembleFrame should be returned + assert isinstance(res, EnsembleFrame) + + # Make sure we get all the expected columns + assert all([col in res.columns for col in ["result_g", "result_r"]]) + + # These should be equivalent + assert ( + res.loc[88472935274829959]["result_g"] + .compute() + .equals(filter_res.loc[88472935274829959]["result"].compute()) + ) + + elif func_label == "bounds": + + def my_bounds(flux): + """returns a series""" + return pd.Series({"min": np.min(flux), "max": np.max(flux)}) + + res = parquet_ensemble.batch( + my_bounds, "psFlux", on=on, by_band=True, meta={"min": float, "max": float} + ) + + parquet_ensemble.source.query(f"{parquet_ensemble._band_col}=='g'").update_ensemble() + filter_res = parquet_ensemble.batch( + my_bounds, "psFlux", on=on, by_band=False, meta={"min": float, "max": float} + ) + + # An EnsembleFrame should be returned + assert isinstance(res, EnsembleFrame) + + # Make sure we get all the expected columns + assert all([col in res.columns for col in ["max_g", "max_r", "min_g", "min_r"]]) + + # These should be equivalent + assert ( + res.loc[88472935274829959]["max_g"] + .compute() + .equals(filter_res.loc[88472935274829959]["max"].compute()) + ) + assert ( + res.loc[88472935274829959]["min_g"] + .compute() + .equals(filter_res.loc[88472935274829959]["min"].compute()) + ) + + # Meta should reflect the actual columns, this can get out of sync + # whenever multi-indexes are involved, which batch tries to handle + assert all([col in res.columns for col in res.compute().columns]) + + def test_batch_labels(parquet_ensemble): """ Test that ensemble.batch() generates unique labels for result frames when none are provided. From 2c9175e52add09150f342e245f2f5140691b928b Mon Sep 17 00:00:00 2001 From: Doug Branton Date: Fri, 15 Dec 2023 15:43:39 -0800 Subject: [PATCH 10/14] add unit tests --- tests/tape_tests/test_ensemble.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tests/tape_tests/test_ensemble.py b/tests/tape_tests/test_ensemble.py index a576828f..efd64610 100644 --- a/tests/tape_tests/test_ensemble.py +++ b/tests/tape_tests/test_ensemble.py @@ -1722,6 +1722,21 @@ def my_bounds(flux): assert all([col in res.columns for col in res.compute().columns]) +def test_batch_by_band_ordering_error(parquet_ensemble): + """ + check that batch appropriately raises an error with `by_band` and incorrect `on` ordering + """ + + def my_mean(flux): + """returns a single value""" + return np.mean(flux) + + with pytest.raises(ValueError): + parquet_ensemble.batch( + my_mean, parquet_ensemble._flux_col, on=["filterName", "ps1_objid"], by_band=True + ) + + def test_batch_labels(parquet_ensemble): """ Test that ensemble.batch() generates unique labels for result frames when none are provided. From 7cac7372e33314bf26a9e98d732049cf2c269405 Mon Sep 17 00:00:00 2001 From: Doug Branton Date: Mon, 18 Dec 2023 13:40:55 -0800 Subject: [PATCH 11/14] WIP: starting the batch showcase tutorial --- docs/tutorials.rst | 1 + docs/tutorials/batch_showcase.ipynb | 546 ++++++++++++++++++++++++++++ 2 files changed, 547 insertions(+) create mode 100644 docs/tutorials/batch_showcase.ipynb diff --git a/docs/tutorials.rst b/docs/tutorials.rst index 8cb1c6cf..d97a276a 100644 --- a/docs/tutorials.rst +++ b/docs/tutorials.rst @@ -11,6 +11,7 @@ functionality. Scaling to Large Data Volume Working with Structure Function Binning Sources in the Ensemble + Batch Function Showcase Structure Function Showcase Loading Data into the Ensemble Using Ray with the Ensemble diff --git a/docs/tutorials/batch_showcase.ipynb b/docs/tutorials/batch_showcase.ipynb new file mode 100644 index 00000000..9eb50cbd --- /dev/null +++ b/docs/tutorials/batch_showcase.ipynb @@ -0,0 +1,546 @@ +{ + "cells": [ + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Ensemble Batch Showcase\n", + "\n", + "`Ensemble.batch` is a versatile function that allows users to pass in external functions that operate on groupings of `Ensemble` data, most commonly these are functions that calculate something per lightcurve. Because external functions can have a huge variety of inputs and outputs, this notebook serves as a collection of example functions and how `batch` can be used with them. The hope is that there is a function here similar to a function that you are trying to apply via `batch` so that example can be used as a template for getting your function to work." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Generate some toy data and create an Ensemble" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from tape import Ensemble, ColumnMapper, TapeFrame\n", + "import numpy as np\n", + "import pandas as pd\n", + "import sys" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Generate some fake data\n", + "\n", + "np.random.seed(1)\n", + "\n", + "obj_ids = np.array([])\n", + "mjds = np.array([])\n", + "for i in range(10,110):\n", + " obj_ids = np.append(obj_ids,np.array([i]*1250))\n", + " mjds = np.append(mjds,np.arange(0.,1250.,1.))\n", + "obj_ids = np.array(obj_ids)\n", + "\n", + "flux = 10*np.random.random(125000)\n", + "err = flux/10\n", + "band = np.random.choice(['g','r'], 125000)\n", + "\n", + "source_dict = {\"id\":obj_ids, \"mjd\":mjds,\"flux\":flux,\"err\":err,\"band\":band}" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Load the data into an Ensemble\n", + "ens = Ensemble()\n", + "\n", + "ens.from_source_dict(source_dict, column_mapper = ColumnMapper(id_col=\"id\",\n", + " time_col=\"mjd\",\n", + " flux_col=\"flux\",\n", + " err_col=\"err\",\n", + " band_col=\"band\"))" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Case 1: A Simple Mean" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We define a simple function that takes in an array-like argument, `flux`, and returns it's mean." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Case 1: Simple\n", + "def my_mean(flux):\n", + " return np.mean(flux)\n", + "\n", + "my_mean([1,2,3,4,5])" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To run the `my_mean` function with `Ensemble.batch`, we simply pass the function, and the argument(s) as separate function arguments. In this case, we pass \"flux\" as a string, as batch will grab the data at that column label to evaluate on." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Default batch\n", + "res1 = ens.batch(my_mean, \"flux\") # \"flux\" is provided to have TAPE pass the \"flux\" column data along to my_mean\n", + "res1.compute() # Compute to see the result" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "By default, `Ensemble.batch` groups each lightcurve together (grouping on the specified id column). However, batch also support custom grouping assignments, as below we instead pass `on=[\"band\"]`, letting batch know to calculate the mean for all data from each band." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Batch with custom grouping\n", + "\n", + "res2 = ens.batch(my_mean, \"flux\", on=[\"band\"])\n", + "res2.compute()" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This can be extended to more than just a single column, as below we group by id and then sub-group by band. In `Pandas`, an operation like this would return a multi-index, but due to `Dask` not supporting multi-indexes we return sub-groupings as columns." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Multi-level groupbys\n", + "\n", + "res3 = ens.batch(my_mean, \"flux\", on=[\"id\", \"band\"])\n", + "res3.compute()" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Sub-grouping by photometric band is a use case we expect to be common in TAPE workflows, and so there is the `by_band` kwarg available within batch. This will ensure that the last sub-grouping level is on band and will return independent columns for each band result." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Batch with the by_band flag\n", + "res4 = ens.batch(my_mean, \"flux\", by_band=True)\n", + "res4.compute()" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Case 2: Functions That Return a Series" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In case 2, we write a function that returns a `Pandas.Series` object. This object has the min and max of the flux array stored at different indices of the output series." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def my_bounds(flux):\n", + " return pd.Series({\"min\":np.min(flux), \"max\":np.max(flux)})\n", + "\n", + "# Function output\n", + "my_bounds([1,2,3,4,5])" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As in case 1, we're able to pass this function and the \"flux\" column along to run the function. However, this time we need the `meta` to be set. The `meta` is a needed component of `Dask's` lazy evaluation. As `Dask` does not actually compute results until requested to, `meta` serves as the expected form of the output. In this case, we just need to let `Dask` know that a min and max column will be present in a dataframe (TAPE will always return a dataframe) and that both will be float values.\n", + "\n", + "For more information on the `Dask` meta argument, read their [documentation](https://blog.dask.org/2022/08/09/understanding-meta-keyword-argument)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Default Batch\n", + "\n", + "res1 = ens.batch(my_bounds, \"flux\", meta={\"min\":float, \"max\":float}) # Requires meta to be set\n", + "res1.compute()" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The same flexibility with grouping extends to case 2, with again needing to specify the `meta`. Note that the meta given to `Ensemble.batch` remains the same, only depending on the function output, it handles the meta for any columns generated by the grouping on it's own." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Multi-level groupbys, note that meta does not need to change\n", + "res2 = ens.batch(my_bounds, \"flux\", on=[\"id\", \"band\"], meta={\"min\":float, \"max\":float}) # Requires meta to be set\n", + "res2.compute()" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Using the `by_band` kwarg extends the output columns to be per-band." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Using by_band\n", + "\n", + "res3 = ens.batch(my_bounds, \"flux\", by_band=True, meta={\"min\":float, \"max\":float}) # Requires meta to be set\n", + "res3.compute()" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Case 3: Functions That Return a DataFrame" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Here we define a function, `my_bounds_df` that computes the same quantities as `my_bounds` above, but in this case we return a dataframe of the results." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def my_bounds_df(flux):\n", + " return pd.DataFrame({'min':[np.min(flux)], 'max':[np.max(flux)]})\n", + "\n", + "my_bounds_df([1,2,3,4,5])" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This is perfectly reasonable, but when passing a function like this through `batch` there's an issue currently to watch out for." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Default Batch, some things to watch out for\n", + "\n", + "res1 = ens.batch(my_bounds_df, \"flux\", meta={'min':float, 'max':float})\n", + "res1.compute()\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As with the series, we needed to pass the `meta` kwarg letting TAPE know which output columns to expect from the function. However,\n", + "we see that our result is carrying over the index generated by the dataframe in addition to the batch index, represented as a multi-index. At the time of this notebooks creation, `Dask` does not have explicit support for multi-indexes. We can see this problem in the following cells." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Pandas resolves these indexes as a multi-index\n", + "res1.reset_index().compute()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Dask assumes there's just a single index column being sent to the dataframe columns\n", + "res1.reset_index()" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "When `Dask` and the underlying `Pandas` disagree on what the dataframe looks like, this causes issues with you as the user being able to work with the dataframe. As `Dask` won't recognize any calls to \"id\" or \"level_1\" here, and instead will only accept a call to \"index\" which in turn `Pandas` won't understand. If this is the issue you run into, we recommend trying to modify your function into a non-dataframe output format. However, in the case that this isn't possible, here's a somewhat hacky way to move around it.\n", + "\n", + "We can resolve this by updating the `Dask` meta manually, to re-align `Dask` and `Pandas`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# If it's not too compute intensive, grabbing the actual dataframe is the easiest way forward\n", + "real_meta_from_result = res1.reset_index().head(0)\n", + "real_meta_from_result" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "\n", + "# otherwise, can generate this ourselves\n", + "real_meta_from_dataframe = TapeFrame(columns=[\"id\",\"level_1\",\"min\",\"max\"])\n", + "real_meta_from_dataframe" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Overwrite the _meta property\n", + "\n", + "res1_noindex = res1.reset_index()\n", + "res1_noindex._meta = real_meta_from_dataframe\n", + "res1_noindex" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Note that in the above, we've reset the index as `Dask` will not support meta that tracks a multi-index. In the case of this function, we gain no information from the \"level_1\" column, and it would be nice to restablish \"id\" as the index, so we close the loop by executing the commands in the next cell." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "res1 = res1_noindex.drop(columns=[\"level_1\"]).set_index(\"id\")\n", + "res1.compute()" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Case 4: Functions that Require Non-Array Inputs" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's return to case 1, but this time instead of the list-like `flux` argument, let's say that the function needs to take in a dataframe with a column titled `my_flux`" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Case 4: DataFrame input\n", + "def my_mean_from_df(df):\n", + " return np.mean(df['my_flux'])\n", + "\n", + "df = pd.DataFrame({'my_flux':[1, 2, 3, 4, 5]})\n", + "my_mean_from_df(df)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In this case, batch won't be able to directly provide inputs to this function, as batch passes along the column data as arrays to the function. However, we can make this function able to be used by batch by wrapping it with another function." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def mean_wrapper(flux):\n", + " df = pd.DataFrame({'my_flux': flux})\n", + " return my_mean_from_df(df)\n", + "\n", + "# Can pass the wrapper function along to batch\n", + "res1 = ens.batch(mean_wrapper, \"flux\")\n", + "res1.compute()" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This is a really simple case, but highlights that in some cases a wrapper function can be written to serve as a middle man between your function and `batch`, even doing work to sort or filter your data on a per function call basis if not done as a pre-filter step for your Ensemble." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Case 5: TAPE Analysis Functions" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from tape.analysis import calc_stetson_J, calc_sf2" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "res_sf2 = ens.batch(calc_sf2)\n", + "res_sf2.compute()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.11" + }, + "orig_nbformat": 4, + "vscode": { + "interpreter": { + "hash": "83afbb17b435d9bf8b0d0042367da76f26510da1c5781f0ff6e6c518eab621ec" + } + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} From 9834748add7f4d2a6010183e7cf3edc5f74832ec Mon Sep 17 00:00:00 2001 From: Doug Branton Date: Tue, 19 Dec 2023 10:13:21 -0800 Subject: [PATCH 12/14] finished batch showcase --- docs/tutorials/batch_showcase.ipynb | 40 ++++++++++++++++++++++++++--- 1 file changed, 36 insertions(+), 4 deletions(-) diff --git a/docs/tutorials/batch_showcase.ipynb b/docs/tutorials/batch_showcase.ipynb index 9eb50cbd..8d3c53b2 100644 --- a/docs/tutorials/batch_showcase.ipynb +++ b/docs/tutorials/batch_showcase.ipynb @@ -482,13 +482,30 @@ "## Case 5: TAPE Analysis Functions" ] }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "TAPE analysis functions are a special case of input function to `Ensemble.batch`, where normally required information such as the specified column labels to pass to the function and the `meta` are passed along from the function to `Ensemble.batch` internally, meaning you just need to specify the function and any additional kwargs. For this case, let's leverage the [light-curve](https://github.com/light-curve/light-curve-python) package, which implements the extraction of many light curve [features](https://github.com/light-curve/light-curve-python?tab=readme-ov-file#available-features) used in astrophysics. Feature extraction from this package is also supported within TAPE as an analysis function." + ] + }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ - "from tape.analysis import calc_stetson_J, calc_sf2" + "# Grab two features extraction methods from light-curve\n", + "from light_curve import Periodogram, OtsuSplit" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In the below example, we apply the Lomb-Scargle Periodogram to our `Ensemble` light curves. Again, noting that in this case the `meta` we had to configure above is already handled by TAPE, and the needed timeseries columns are already passed along internally as well." ] }, { @@ -496,7 +513,22 @@ "execution_count": null, "metadata": {}, "outputs": [], - "source": [] + "source": [ + "# Find periods using Lomb-Scargle periodogram\n", + "periodogram = Periodogram(peaks=1, nyquist=0.1, max_freq_factor=10, fast=False)\n", + "\n", + "# Use r band only\n", + "res_per = ens.batch(periodogram, band_to_calc='r') # band_to_calc is a kwarg of Periodogram\n", + "res_per.compute()" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Next, we use the `OtsuSplit` function, used to perform automatic thresholding. In this case, we also supply the `by_band` kwarg to get a result per photometric band." + ] }, { "cell_type": "code", @@ -504,8 +536,8 @@ "metadata": {}, "outputs": [], "source": [ - "res_sf2 = ens.batch(calc_sf2)\n", - "res_sf2.compute()" + "res_otsu = ens.batch(OtsuSplit(), band_to_calc=None, by_band=True)\n", + "res_otsu.compute()" ] }, { From 4f5dd26c2bed50b5030d52927e9ebea77eb58c72 Mon Sep 17 00:00:00 2001 From: Doug Branton Date: Tue, 19 Dec 2023 15:54:30 -0800 Subject: [PATCH 13/14] address review comments --- src/tape/ensemble.py | 68 ++++++++++++++++++------------- tests/tape_tests/test_ensemble.py | 17 +------- 2 files changed, 41 insertions(+), 44 deletions(-) diff --git a/src/tape/ensemble.py b/src/tape/ensemble.py index 5506e676..fd6960e2 100644 --- a/src/tape/ensemble.py +++ b/src/tape/ensemble.py @@ -1035,12 +1035,11 @@ def batch(self, func, *args, meta=None, by_band=False, use_map=True, on=None, la by_band: `boolean` If true, the lightcurves are split into separate inputs for each band and passed along to the function individually. If the band - column is already specified in `on` then `batch` will check to make - sure the band column is the final element in `on` (if not this will - error out). Each band function result will be returned as a column - of the result dataframe. If False, the full lightcurve is passed - along to the function (again, assuming the band column in not - already part of `on`). + column is already specified in `on` then `batch` will ensure the + band column is the final element in `on`. Each band function result + will be returned as a column of the result dataframe. If False, the + full lightcurve is passed along to the function (assuming the band + column in not already part of `on`). use_map : `boolean` Determines whether `dask.dataframe.DataFrame.map_partitions` is used (True). Using map_partitions is generally more efficient, but @@ -1121,12 +1120,10 @@ def s2n_inter_quartile_range(flux, err): if by_band: if self._band_col not in on: on += [self._band_col] - elif ( - on[-1] != self._band_col - ): # Unsure if this is neccesary but it seems likely to produce wrong behavior - raise ValueError( - "If `by_band` is true, the band column must be the last column specified in `on`" - ) + elif on[-1] != self._band_col: + # Ensure band is the final column in the `on` list + on[on.index(self._band_col)] = on[-1] + on[-1] = self._band_col # Handle object columns to group on source_cols = list(self.source.columns) @@ -1161,15 +1158,37 @@ def s2n_inter_quartile_range(flux, err): ) # Output standardization + batch = self._standardize_batch(batch, on, by_band) + + # Inherit divisions if known from source and the resulting index is the id + # Groupby on index should always return a subset that adheres to the same divisions criteria + if self.source.known_divisions and batch.index.name == self._id_col: + batch.divisions = self.source.divisions + + if label is not None: + if label == "": + label = self._generate_frame_label() + print(f"Using generated label, {label}, for a batch result.") + # Track the result frame under the provided label + self.add_frame(batch, label) + + return batch + + def _standardize_batch(self, batch, on, by_band): + """standardizes the output of a batch result""" + if isinstance(batch, EnsembleSeries): if batch.name == self._id_col: batch = batch.rename("result") + + col_name = batch.name # grab the series name to use as a column label + batch = EnsembleFrame.from_dask_dataframe(batch.to_frame()) if len(on) > 1: batch = batch.reset_index() # Need to overwrite the meta manually as the multiindex will be # interpretted by dask as a single "index" column - batch._meta = TapeFrame(columns=on + ["result"]) + batch._meta = TapeFrame(columns=on + [col_name]) if by_band: batch = batch.categorize(self._band_col).pivot_table( @@ -1179,10 +1198,10 @@ def s2n_inter_quartile_range(flux, err): # Need to once again reestablish meta for the pivot band_labels = batch.columns.values out_cols = [] - for col in ["result"]: - for band in band_labels: - out_cols += [(str(col), str(band))] + for band in band_labels: + out_cols += [(str(col_name), str(band))] batch._meta = TapeFrame(columns=out_cols) + # Flatten the columns to a new column per band batch.columns = ["_".join(col).strip() for col in batch.columns.values] @@ -1203,7 +1222,6 @@ def s2n_inter_quartile_range(flux, err): # Need to once again reestablish meta for the pivot band_labels = batch.columns.values - out_cols = [] for col in res_cols[::-1]: for band in band_labels: @@ -1219,17 +1237,11 @@ def s2n_inter_quartile_range(flux, err): else: batch = batch.set_index(on[0], sort=False) - # Inherit divisions if known from source and the resulting index is the id - # Groupby on index should always return a subset that adheres to the same divisions criteria - if self.source.known_divisions and batch.index.name == self._id_col: - batch.divisions = self.source.divisions - - if label is not None: - if label == "": - label = self._generate_frame_label() - print(f"Using generated label, {label}, for a batch result.") - # Track the result frame under the provided label - self.add_frame(batch, label) + else: + # unclear if there's really a pathway to trigger this, but added for completeness + raise TypeError( + f"The output type of batch ({type(batch)}) does not match any of the expected types: (EnsembleFrame, EnsembleSeries)" + ) return batch diff --git a/tests/tape_tests/test_ensemble.py b/tests/tape_tests/test_ensemble.py index efd64610..0765b1db 100644 --- a/tests/tape_tests/test_ensemble.py +++ b/tests/tape_tests/test_ensemble.py @@ -1653,7 +1653,7 @@ def test_batch(data_fixture, request, use_map, on): assert pytest.approx(result.values[1]["r"], 0.001) == -0.49639028 -@pytest.mark.parametrize("on", [None, ["ps1_objid", "filterName"]]) +@pytest.mark.parametrize("on", [None, ["ps1_objid", "filterName"], ["filterName", "ps1_objid"]]) @pytest.mark.parametrize("func_label", ["mean", "bounds"]) def test_batch_by_band(parquet_ensemble, func_label, on): """ @@ -1722,21 +1722,6 @@ def my_bounds(flux): assert all([col in res.columns for col in res.compute().columns]) -def test_batch_by_band_ordering_error(parquet_ensemble): - """ - check that batch appropriately raises an error with `by_band` and incorrect `on` ordering - """ - - def my_mean(flux): - """returns a single value""" - return np.mean(flux) - - with pytest.raises(ValueError): - parquet_ensemble.batch( - my_mean, parquet_ensemble._flux_col, on=["filterName", "ps1_objid"], by_band=True - ) - - def test_batch_labels(parquet_ensemble): """ Test that ensemble.batch() generates unique labels for result frames when none are provided. From f9f202f8e9d4a1dd668cbd9e803a32cce38d1ab1 Mon Sep 17 00:00:00 2001 From: Doug Branton Date: Wed, 20 Dec 2023 12:11:52 -0800 Subject: [PATCH 14/14] address review 2 --- docs/tutorials/batch_showcase.ipynb | 12 ++-- src/tape/ensemble.py | 103 +++++++++++++--------------- 2 files changed, 52 insertions(+), 63 deletions(-) diff --git a/docs/tutorials/batch_showcase.ipynb b/docs/tutorials/batch_showcase.ipynb index 8d3c53b2..a76631d4 100644 --- a/docs/tutorials/batch_showcase.ipynb +++ b/docs/tutorials/batch_showcase.ipynb @@ -45,12 +45,13 @@ "\n", "np.random.seed(1)\n", "\n", - "obj_ids = np.array([])\n", - "mjds = np.array([])\n", + "obj_ids = []\n", + "mjds = []\n", "for i in range(10,110):\n", - " obj_ids = np.append(obj_ids,np.array([i]*1250))\n", - " mjds = np.append(mjds,np.arange(0.,1250.,1.))\n", - "obj_ids = np.array(obj_ids)\n", + " obj_ids.append(np.array([i]*1250))\n", + " mjds.append(np.arange(0.,1250.,1.))\n", + "obj_ids = np.concatenate(obj_ids)\n", + "mjds = np.concatenate(mjds)\n", "\n", "flux = 10*np.random.random(125000)\n", "err = flux/10\n", @@ -566,7 +567,6 @@ "pygments_lexer": "ipython3", "version": "3.10.11" }, - "orig_nbformat": 4, "vscode": { "interpreter": { "hash": "83afbb17b435d9bf8b0d0042367da76f26510da1c5781f0ff6e6c518eab621ec" diff --git a/src/tape/ensemble.py b/src/tape/ensemble.py index fd6960e2..bc31ac7f 100644 --- a/src/tape/ensemble.py +++ b/src/tape/ensemble.py @@ -1032,14 +1032,17 @@ def batch(self, func, *args, meta=None, by_band=False, use_map=True, on=None, la the results. Overridden by TAPE for TAPE and `light-curve` functions. If none, attempts to coerce the result to a pandas.Series. - by_band: `boolean` + by_band: `boolean`, optional If true, the lightcurves are split into separate inputs for each band and passed along to the function individually. If the band column is already specified in `on` then `batch` will ensure the - band column is the final element in `on`. Each band function result - will be returned as a column of the result dataframe. If False, the - full lightcurve is passed along to the function (assuming the band - column in not already part of `on`). + band column is the final element in `on`. For all original columns + outputted by `func`, by_band will generate a set of new columns per + band (for example, a function with output column "result" will + instead have "result_g" and "result_r" as columns if the data had g + and r band data) If False (default), the full lightcurve is passed + along to the function (assuming the band column in not already part + of `on`) use_map : `boolean` Determines whether `dask.dataframe.DataFrame.map_partitions` is used (True). Using map_partitions is generally more efficient, but @@ -1177,65 +1180,19 @@ def s2n_inter_quartile_range(flux, err): def _standardize_batch(self, batch, on, by_band): """standardizes the output of a batch result""" + # Do some up front type checking if isinstance(batch, EnsembleSeries): + # make sure the output is separated from the id column if batch.name == self._id_col: batch = batch.rename("result") + res_cols = [batch.name] # grab the series name to use as a column label - col_name = batch.name # grab the series name to use as a column label - + # convert the series to an EnsembleFrame object batch = EnsembleFrame.from_dask_dataframe(batch.to_frame()) - if len(on) > 1: - batch = batch.reset_index() - # Need to overwrite the meta manually as the multiindex will be - # interpretted by dask as a single "index" column - batch._meta = TapeFrame(columns=on + [col_name]) - - if by_band: - batch = batch.categorize(self._band_col).pivot_table( - index=on[0], columns=self._band_col, aggfunc="sum" - ) - - # Need to once again reestablish meta for the pivot - band_labels = batch.columns.values - out_cols = [] - for band in band_labels: - out_cols += [(str(col_name), str(band))] - batch._meta = TapeFrame(columns=out_cols) - - # Flatten the columns to a new column per band - batch.columns = ["_".join(col).strip() for col in batch.columns.values] - - # The pivot returns a dask dataframe, need to convert back - batch = EnsembleFrame.from_dask_dataframe(batch) - - else: - batch = batch.set_index(on[0], sort=False) elif isinstance(batch, EnsembleFrame): - if len(on) > 1: - res_cols = list(batch._meta.columns) - batch = batch.reset_index() - batch._meta = TapeFrame(columns=on + res_cols) - if by_band: - batch = batch.categorize(self._band_col) - batch = batch.pivot_table(index=on[0], columns=self._band_col, aggfunc="sum") - - # Need to once again reestablish meta for the pivot - band_labels = batch.columns.values - out_cols = [] - for col in res_cols[::-1]: - for band in band_labels: - out_cols += [(str(col), str(band))] - batch._meta = TapeFrame(columns=out_cols) - - # Flatten the columns to a new column per band - batch.columns = ["_".join(col).strip() for col in batch.columns.values] - - # The pivot returns a dask dataframe, need to convert back - batch = EnsembleFrame.from_dask_dataframe(batch) - - else: - batch = batch.set_index(on[0], sort=False) + # collect output columns + res_cols = list(batch._meta.columns) else: # unclear if there's really a pathway to trigger this, but added for completeness @@ -1243,6 +1200,38 @@ def _standardize_batch(self, batch, on, by_band): f"The output type of batch ({type(batch)}) does not match any of the expected types: (EnsembleFrame, EnsembleSeries)" ) + # Handle formatting for multi-index results + if len(on) > 1: + batch = batch.reset_index() + + # Need to overwrite the meta manually as the multiindex will be + # interpretted by dask as a single "index" column + batch._meta = TapeFrame(columns=on + res_cols) + + # Further reformatting for per-band results + # Pivots on the band column to generate a result column for each + # photometric band. + if by_band: + batch = batch.categorize(self._band_col) + batch = batch.pivot_table(index=on[0], columns=self._band_col, aggfunc="sum") + + # Need to once again reestablish meta for the pivot + band_labels = batch.columns.values + out_cols = [] + # To align with pandas pivot_table results, the columns should be generated in reverse order + for col in res_cols[::-1]: + for band in band_labels: + out_cols += [(str(col), str(band))] + batch._meta = TapeFrame(columns=out_cols) # apply new meta + + # Flatten the columns to a new column per band + batch.columns = ["_".join(col) for col in batch.columns.values] + + # The pivot returns a dask dataframe, need to convert back + batch = EnsembleFrame.from_dask_dataframe(batch) + else: + batch = batch.set_index(on[0], sort=False) + return batch def from_pandas(