-
Notifications
You must be signed in to change notification settings - Fork 130
Extend set_meta_from_data() to apply on different column
#986
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
97f14e8
eb6655b
9a5c848
0c3d991
f962de8
633b63c
e1fb12e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -946,31 +946,91 @@ def set_meta(self, meta, name=None, index=None): # noqa: C901 | |
| self._new_meta_column(name) | ||
| self.meta[name] = meta[name].combine_first(self.meta[name]) | ||
|
|
||
| def set_meta_from_data(self, name, method=None, column="value", **kwargs): | ||
| def set_meta_from_data(self, name, method=None, column="value", on=None, **kwargs): | ||
| """Add meta indicators from downselected timeseries data | ||
|
|
||
| Parameters | ||
| ---------- | ||
| name : str | ||
| Column name of the 'meta' table | ||
| method : function, optional | ||
| Resulting column name in the 'meta' table. | ||
| method : function or str, optional | ||
| Method for aggregation | ||
| (e.g., :func:`numpy.max <numpy.ndarray.max>`); | ||
| required if downselected data do not yield unique values | ||
| required if downselected data do not yield unique values. | ||
| column : str, optional | ||
| The column from `data` to be used to derive the indicator | ||
| The column from `data` to be used to derive the indicator. | ||
| on : str, optional | ||
| If given, apply the `method` on this column and use corresponding value from | ||
| `column` as meta indicator. | ||
| **kwargs | ||
| Passed to :meth:`slice` for downselected data | ||
| Passed to :meth:`slice` for downselection of data. | ||
|
|
||
| Raises | ||
| ------ | ||
| ValueError | ||
| If the resulting meta-indicators are not unique for each element | ||
| of the :attr:`index`. | ||
|
|
||
| Examples | ||
| -------- | ||
| A simple use case for this method is to compute a meta-indicator for the peak | ||
| (maximum) temperature from annual temperature timeseries data for each scenario: | ||
|
|
||
| .. code:: python | ||
|
|
||
| df.set_meta_from_data( | ||
| name="Climate Assessment|Peak Warming [°C]", | ||
| method="max", | ||
| variable="Climate Assessment|Surface Temperature", | ||
| ) | ||
|
|
||
| Alternatively, the *method* can be applied on a column *on* and the | ||
| corresponding value from the *column* is set as meta indicator. This can be | ||
| used to set the year when peak-temperature is reached as meta-indicator. | ||
|
|
||
| .. code:: python | ||
|
|
||
| df.set_meta_from_data( | ||
| name="Climate Assessment|Year of Peak Warming", | ||
| method="max", | ||
| column="value", | ||
| on="year", | ||
| variable="Climate Assessment|Surface Temperature", | ||
| ) | ||
|
|
||
| """ | ||
| values = self._data[self.slice(**kwargs)] | ||
| if method is None and column != "value": | ||
| values = values.reset_index(column)[column] | ||
| elif method is not None: | ||
| if column == "value": | ||
| values = values.groupby(self.index.names) | ||
| else: | ||
| values = values.reset_index(column).groupby(self.index.names)[column] | ||
| values = values.apply(method) | ||
| if on is not None: | ||
|
|
||
| @staticmethod | ||
| def apply_method(x): | ||
| if callable(method): | ||
| value = x[x[on] == method(x[on])][column].unique() | ||
| else: | ||
| value = x[x[on] == x[on].apply(method)][column].unique() | ||
|
|
||
| if len(value) > 1: | ||
| logger.warning(f"Non-unique result from {method} on column {on}.") | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should this just be a warning? I'd imagine that producing a non-unique value for a meta value can only be ill-conceived. We might want to raise an actual error here.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In my original use case, it could be that the temperature stabilises at (for example) 1.7°,, in particular if we round the output from the climate assessment. So there could be multiple years where peak temperature is reached, without this being necessarily incorrect. The truly correct solution would be to also provide an on_method argument that makes this unique? |
||
|
|
||
| return value[0] | ||
|
|
||
| values = ( | ||
| self._data[self.slice(**kwargs)] | ||
| .reset_index([col for col in [column, on] if col != "value"]) | ||
| .groupby(self.index.names) | ||
| .apply(apply_method) | ||
| ) | ||
| else: | ||
| values = self._data[self.slice(**kwargs)] | ||
| if method is None and column != "value": | ||
| values = values.reset_index(column)[column] | ||
| elif method is not None: | ||
| if column == "value": | ||
| values = values.groupby(self.index.names) | ||
| else: | ||
| values = values.reset_index(column).groupby(self.index.names)[ | ||
| column | ||
| ] | ||
| values = values.apply(method) | ||
| self.set_meta(values, name) | ||
|
|
||
| def categorize( | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.