From f810894dcc6015b5af06acd3f23ecd8262524579 Mon Sep 17 00:00:00 2001 From: Bert Palm <bert.palm@ufz.de> Date: Sun, 16 Feb 2020 03:37:39 +0100 Subject: [PATCH] getitem fine --- dios/dios.py | 160 +++++++++++++++++++++++---------------------------- 1 file changed, 72 insertions(+), 88 deletions(-) diff --git a/dios/dios.py b/dios/dios.py index 10a1873..a3fb535 100644 --- a/dios/dios.py +++ b/dios/dios.py @@ -5,6 +5,7 @@ from dios.errors import * import pandas as pd import numpy as np import operator as op +from functools import partialmethod from functools import wraps from collections import OrderedDict @@ -186,45 +187,27 @@ class DictOfSeries: - ``dios['a']`` -> return a pd.Series - ``dios[iterable]`` -> return a DictOfSeries of all given columns [1] - ``dios[slice]`` -> return a sliced DictOfSeries of all(!) columns in the dios - Notes: - [1] If ``iterable`` contains any(!) label that does not exist, a KeyError is raised. """ - - # prepare - if is_iterator(key): - key = list(key) - + # special case single label if isinstance(key, str): - self._check_keys([key]) - return self._get_item(key) - - if isinstance(key, slice): - return self._slice(self.columns, key) - - if is_list_like(key) and not is_nested_list_like(key): - self._check_keys(key) - return self._getitem_listlike(key) - - raise KeyError(f"{key}") + if key in self.columns: + new = self._get_item(key) + else: + raise KeyError(key) + else: + keys, ixs = self._get_keys_and_indexer(key) + new = self.copy_empty() + for i, _ in enumerate(keys): + key, ix = keys[i], ixs[i] + new._data[key] = self._get_item(key)[ix] + return new def _get_item(self, key): # return always a pd.Series return self._data[key] - def _getitem_listlike(self, keys): - new = self.copy_empty() - for k in keys: - new._data[k] = self._get_item(k) - return new - - def _slice(self, keys, slicer): - """ Return a slice of self""" - new = self.copy_empty() - for k in keys: - new._data[k] = self._get_item(k)[slicer] - return new - def __setitem__(self, key, value): """ Set items: @@ -253,6 +236,52 @@ class DictOfSeries: for tup in gen: self._set_item(*tup) + def _setitem(self, keys, ixs, val): + """Return a generator that yield (key, indexer, value) for all keys""" + if is_iterator(val): + val = list(val) + + diosl, dfl, nlistl = is_dios_like(val), is_dataframe_like(val), is_nested_list_like(val) + if diosl or dfl or nlistl and len(val) != len(keys): + raise ValueError(f"could not broadcast input array with length {len(val)}" + f" into dios of length {len(keys)}") + + # now we have everything we need: key, indexer, value + # so we just pack it nice and cosy and let setitem + # do the dirty work. + for i, _ in enumerate(keys): + key, ix = keys[i], ixs[i] + if dfl or diosl: + yield key, ix, val[val.columns[i]] + elif nlistl: + yield key, ix, val[i] + else: + yield key, ix, val + + def _set_item(self, key, ix, val): + "Set a value (scalar or list or series)" + ser = self._data[key] + if is_series_like(val): + left = ser[ix] + index = left.index.intersection(val.index) + if not index.empty: + left.loc[index] = val.loc[index].copy() + else: + ser[ix] = val + + def _insert(self, key, val): + """""" + if isinstance(val, DictOfSeries): + val = val.squeeze() + elif is_list_like(val) and not is_nested_list_like(val): + val = pd.Series(val) + + if not isinstance(val, pd.Series): + raise ValueError(f"Only pd.Series can be inserted directly") + + val = cast_to_itype(val, self._itype, policy=self._policy) + self._data[key] = val.copy(deep=True) + def _get_keys_and_indexer(self, key): """ Determine keys and indexer Notes: @@ -330,52 +359,6 @@ class DictOfSeries: # now we have a valid indexer (a slice or a bool array) for every series return keys, indexers - def _setitem(self, keys, ixs, val): - """Return a generator that yield (key, indexer, value) for all keys""" - if is_iterator(val): - val = list(val) - - diosl, dfl, nlistl = is_dios_like(val), is_dataframe_like(val), is_nested_list_like(val) - if diosl or dfl or nlistl and len(val) != len(keys): - raise ValueError(f"could not broadcast input array with length {len(val)}" - f" into dios of length {len(keys)}") - - # now we have everything we need: key, indexer, value - # so we just pack it nice and cosy and let setitem - # do the dirty work. - for i, _ in enumerate(keys): - key, ix = keys[i], ixs[i] - if dfl or diosl: - yield key, ix, val[val.columns[i]] - elif nlistl: - yield key, ix, val[i] - else: - yield key, ix, val - - def _insert(self, key, val): - """""" - if isinstance(val, DictOfSeries): - val = val.squeeze() - elif is_list_like(val) and not is_nested_list_like(val): - val = pd.Series(val) - - if not isinstance(val, pd.Series): - raise ValueError(f"Only pd.Series can be inserted directly") - - val = cast_to_itype(val, self._itype, policy=self._policy) - self._data[key] = val.copy(deep=True) - - def _set_item(self, key, ix, val): - "Set a value (scalar or list or series)" - ser = self._data[key] - if is_series_like(val): - left = ser[ix] - index = left.index.intersection(val.index) - if not index.empty: - left.loc[index] = val.loc[index].copy() - else: - ser[ix] = val - @property def loc(self): return _LocIndexer(self) @@ -411,7 +394,7 @@ class DictOfSeries: @property def empty(self): - return all(self._data[c].empty for c in self._data) + return len(self) == 0 or all(self._data[c].empty for c in self._data) def all(self): return pd.Series([self._data[c].any() for c in self._data]) @@ -462,19 +445,20 @@ class DictOfSeries: new._itype = self.itype return new - def _op1_wrap(op): - def anyop(self): - with reraise(f"'{OP_MAP[op]}dios' failed: "): - new = self.copy_empty() - for k in self: - new[k] = op(self._data[k]) - return new + def anyop(self, op, ): + new = self.copy_empty() + with reraise(f"'{OP_MAP[op]} dios' failed: "): + for k in self: + new[k] = op(self._data[k]) + return new - return anyop + def foo(self, x): + raise ValueError('dnsjkncsncj') - __neg__ = _op1_wrap(op.neg) - __abs__ = _op1_wrap(op.abs) - __invert__ = _op1_wrap(op.inv) + __neg__ = partialmethod(anyop, op.neg) + __abs__ = partialmethod(anyop, op.abs) + # __invert__ = partialmethod(anyop, op.inv) + __invert__ = partialmethod(anyop, foo) def _op2(self, other, op, inplace=False): new = self.copy_empty() -- GitLab