From 2e71a1e5580fc75050fb2a47ef23fa54d90d943a Mon Sep 17 00:00:00 2001 From: rwijtvliet Date: Thu, 1 Feb 2024 17:49:38 +0100 Subject: [PATCH 1/2] v0.5.10 (#76) * better description of development process (#70) * Update README.rst (#71) * feat: bump version to latest release +1 (#69) * Wavgfix (#62) * initial commit * small fix * stash for the weekend * Fixed wavg to handle surplus values. * Re-instated 'Europe/Berlin' as default for tz in standardize. For now. * small fix in docs * docs and better unit handling * Kind available at project root * fixed init tests (?) * new release * fixed for pyton 3.9 too * additional tests (#74) * Portfolyo Release 0.5.10 (#75) --------- Co-authored-by: Stefan Keidel <1188614+stefankeidel@users.noreply.github.com> --- LICENCE | 2 +- README.rst | 7 +- docs/core/pfline.rst | 73 ++-- docs/savefig/fig_hedge.png | Bin 32485 -> 32520 bytes docs/savefig/fig_offtake.png | Bin 64529 -> 64560 bytes docs/specialized_topics/resampling.rst | 10 +- portfolyo/__init__.py | 7 +- portfolyo/testing/__init__.py | 1 + portfolyo/testing/testing.py | 63 +-- portfolyo/tools/leftandright.py | 12 +- portfolyo/tools/stamp.py | 42 ++ portfolyo/tools/standardize.py | 8 +- portfolyo/tools/unit.py | 104 +++-- portfolyo/tools/wavg.py | 409 ++++++++++++++++-- pyproject.toml | 4 +- tests/core/pfline/test_pfline_init.py | 16 +- tests/core/pfline/test_pfline_text.py | 13 + tests/core/pfstate/test_pfstate_text.py | 9 + tests/tools/test_intersect.py | 4 +- tests/tools/test_leftandright.py | 41 +- tests/tools/test_stamp.py | 84 ++++ tests/tools/test_standardize.py | 2 +- tests/tools/test_wavg.py | 550 +++++++++++++++--------- 23 files changed, 1084 insertions(+), 377 deletions(-) create mode 100644 portfolyo/tools/stamp.py create mode 100644 tests/core/pfline/test_pfline_text.py create mode 100644 tests/core/pfstate/test_pfstate_text.py create mode 100644 tests/tools/test_stamp.py diff --git a/LICENCE b/LICENCE index 2f5750f..d4e49a1 100644 --- a/LICENCE +++ b/LICENCE @@ -28,4 +28,4 @@ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/README.rst b/README.rst index 7734531..4d6b5c3 100644 --- a/README.rst +++ b/README.rst @@ -39,7 +39,10 @@ NB: this package is under active development and the API will change without pri .. code-block:: bash - pip install portfolyo==x.x.x + pip install portfolyo==x.y.z + + # or, in pyproject.toml + portfolyo = "x.y.z" Documentation @@ -66,7 +69,7 @@ the commit hooks. .. code-block:: bash - poetry install --with=dev,test + poetry install --with dev,test pre-commit install Feature branches are merged into the ``develop`` branch via pull request. diff --git a/docs/core/pfline.rst b/docs/core/pfline.rst index 404ad12..e3a8678 100644 --- a/docs/core/pfline.rst +++ b/docs/core/pfline.rst @@ -21,7 +21,7 @@ Kind An important characteristic of a portfolio line is its "kind". The property ``PfLine.kind`` has a value from the ``portfolyo.Kind`` enumeration and tells us the type of information it contains: -* ``Kind.VOLUME``: "volume-only" portfolio line. + * 🟨 ``Kind.VOLUME``: "volume-only" portfolio line. This is a portfolio line that only contains volume information. @@ -29,17 +29,17 @@ An important characteristic of a portfolio line is its "kind". The property ``Pf The volume in each timestamp can be retrieved by the user in units of energy (e.g., MWh) or in units of power (e.g., MW). -* ``Kind.PRICE``: "price-only" portfolio line. +* 🟩 ``Kind.PRICE``: "price-only" portfolio line. This is a portfolio line which only contains price information. For example, the forward price curve for a certain market area, or the fixed offtake price that a customer is paying for a certain delivery period. -* ``Kind.REVENUE``: "revenue-only" portfolio line. +* 🟦 ``Kind.REVENUE``: "revenue-only" portfolio line. For example, the payoff of a financially-settled put option, which has a monetary value (e.g., in Eur) without an associated volume being delivered. -* ``Kind.COMPLETE`` +* 🟫 ``Kind.COMPLETE`` This a portfolio line that contains volume, price and revenue information. @@ -72,7 +72,7 @@ To initialise a volume-only / price-only / revenue-only portfolio line, we must DataFrame or dictionary of timeseries... ======================================== -or any other ``Mapping`` from (string) key values to ``pandas.Series``. +...or any other ``Mapping`` from (string) key values to ``pandas.Series``. The keys (or dataframe column names) must each be one of the following: ``w`` (power), ``q`` (energy), ``p`` (price), ``r`` (revenue). Depending on the keys, the ``.kind`` of the portfolio line is determined. @@ -107,7 +107,7 @@ Under the condition that a valid ``pint`` unit is present, we may also provide a Dictionary of portfolio lines... ================================ -or any other ``Mapping`` from (string) key values to ``PfLine`` objects. +...or any other ``Mapping`` from (string) key values to ``PfLine`` objects. The keys are used as the children names: @@ -383,15 +383,14 @@ Addition and subtraction * Even if the both operands have the same kind, they must both be nested or both be flat. E.g., a flat price can be added to a flat price-only portfolio line, but not to a nested price-only portfolio line. Two nested price-only portfolio lines can be added. ================================================= =============== ============== ================ ================= -\ Kind of portfolio line +\ Kind of portfolio line (`pfl.Kind`) ------------------------------------------------- ----------------------------------------------------------------- -\ 🟨 🟩 🟦 🟫 -\ ``VOLUME`` ``PRICE`` ``REVENUE`` ``COMPLETE`` +\ 🟨 ``VOLUME`` 🟩 ``PRICE`` 🟦 ``REVENUE`` 🟫 ``COMPLETE`` ================================================= =============== ============== ================ ================= -``PfLine`` ± volume 🟨 e_ ❌ ❌ ❌ -``PfLine`` ± price ❌ 🟩 e_ ❌ ❌ -``PfLine`` ± revenue ❌ ❌ 🟦 e_ ❌ -``PfLine`` ± complete ❌ ❌ ❌ 🟫 e_ +``pfl`` ± volume 🟨 e_ ❌ ❌ ❌ +``pfl`` ± price ❌ 🟩 e_ ❌ ❌ +``pfl`` ± revenue ❌ ❌ 🟦 e_ ❌ +``pfl`` ± complete ❌ ❌ ❌ 🟫 e_ ================================================= =============== ============== ================ ================= Notes: @@ -495,14 +494,13 @@ We can scale a portfolio line by multiplication with / division by a dimensionle Negation is implemented as multiplication with -1. ================================================= =============== ============== ================ ================= -\ Kind of portfolio line +\ Kind of portfolio line (`pfl.Kind`) ------------------------------------------------- ----------------------------------------------------------------- -\ 🟨 🟩 🟦 🟫 -\ ``VOLUME`` ``PRICE`` ``REVENUE`` ``COMPLETE`` +\ 🟨 ``VOLUME`` 🟩 ``PRICE`` 🟦 ``REVENUE`` 🟫 ``COMPLETE`` ================================================= =============== ============== ================ ================= -``-PfLine`` (negation) 🟨 🟩 🟦 🟫 -``PfLine * dimensionless`` 🟨 🟩 🟦 🟫 -``PfLine / dimensionless`` 🟨 🟩 🟦 🟫 +``-pfl`` (negation) 🟨 🟩 🟦 🟫 +``pfl * dimensionless`` 🟨 🟩 🟦 🟫 +``pfl / dimensionless`` 🟨 🟩 🟦 🟫 ================================================= =============== ============== ================ ================= For example: @@ -534,14 +532,13 @@ We can calculate the ratio of two portfolyo lines by dividing them. ================================================= =============== ============== ================ ================= -\ Kind of portfolio line +\ Kind of portfolio line (`pfl.Kind`) ------------------------------------------------- ----------------------------------------------------------------- -\ 🟨 🟩 🟦 🟫 -\ ``VOLUME`` ``PRICE`` ``REVENUE`` ``COMPLETE`` +\ 🟨 ``VOLUME`` 🟩 ``PRICE`` 🟦 ``REVENUE`` 🟫 ``COMPLETE`` ================================================= =============== ============== ================ ================= -``PfLine / volume`` ⬜ 2f_ ❌ (❌) ❌ -``PfLine / price`` ❌ ⬜ 2f_ (❌) ❌ -``PfLine / revenue`` ❌ ❌ ⬜ 2f_ ❌ +``pfl / volume`` ⬛️ 2f_ ❌ (❌) ❌ +``pfl / price`` ❌ ⬛️ 2f_ (❌) ❌ +``pfl / revenue`` ❌ ❌ ⬛️ 2f_ ❌ ================================================= =============== ============== ================ ================= Notes: @@ -552,7 +549,7 @@ Notes: Both operands must be flat. (❌) - This operation is allowed but does not result in ratio. It is described in the section changekind_ below. + This operation is allowed but does not result in a ratio. It is described in the section changekind_ below. For example: @@ -593,15 +590,14 @@ We can turn one kind of portfolio line into another kind, by multiplying with or * To combine two portfolio lines into a complete portfolio line, see the section :ref:`union`, below. ================================================= =============== ============== ================ ================= -\ Kind of portfolio line +\ Kind of portfolio line (`pfl.Kind`) ------------------------------------------------- ----------------------------------------------------------------- -\ 🟨 🟩 🟦 🟫 -\ ``VOLUME`` ``PRICE`` ``REVENUE`` ``COMPLETE`` +\ 🟨 ``VOLUME`` 🟩 ``PRICE`` 🟦 ``REVENUE`` 🟫 ``COMPLETE`` ================================================= =============== ============== ================ ================= -``PfLine * volume`` ❌ 🟦 `≥1f`_ ❌ ❌ -``PfLine * price`` 🟦 `≥1f`_ ❌ ❌ ❌ -``PfLine / volume`` (❌) ❌ 🟩 `≥1f`_ ❌ -``PfLine / price`` ❌ (❌) 🟨 `≥1f`_ ❌ +``pfl * volume`` ❌ 🟦 `≥1f`_ ❌ ❌ +``pfl * price`` 🟦 `≥1f`_ ❌ ❌ ❌ +``pfl / volume`` (❌) ❌ 🟩 `≥1f`_ ❌ +``pfl / price`` ❌ (❌) 🟨 `≥1f`_ ❌ ================================================= =============== ============== ================ ================= Notes: @@ -642,14 +638,13 @@ We can combine portfolio lines of distinct kind into a complete portfolio line. * Both operands must be flat. If necessary, first ``.flatten()`` a nested portfolio line. ================================================= =============== ============== ================ ================= -\ Kind of portfolio line +\ Kind of portfolio line (`pfl.Kind`) ------------------------------------------------- ----------------------------------------------------------------- -\ 🟨 🟩 🟦 🟫 -\ ``VOLUME`` ``PRICE`` ``REVENUE`` ``COMPLETE`` +\ 🟨 ``VOLUME`` 🟩 ``PRICE`` 🟦 ``REVENUE`` 🟫 ``COMPLETE`` ================================================= =============== ============== ================ ================= -``PfLine | volume`` ❌ 🟫 `2f⠀`_ 🟫 `2f⠀`_ ❌ -``PfLine | price`` 🟫 `2f⠀`_ ❌ 🟫 `2f⠀`_ ❌ -``PfLine | revenue`` 🟫 `2f⠀`_ 🟫 `2f⠀`_ ❌ ❌ +``pfl | volume`` ❌ 🟫 `2f⠀`_ 🟫 `2f⠀`_ ❌ +``pfl | price`` 🟫 `2f⠀`_ ❌ 🟫 `2f⠀`_ ❌ +``pfl | revenue`` 🟫 `2f⠀`_ 🟫 `2f⠀`_ ❌ ❌ ================================================= =============== ============== ================ ================= diff --git a/docs/savefig/fig_hedge.png b/docs/savefig/fig_hedge.png index a043a943fc485a742477fb6ac6e3ad0155a058a5..a487121b74282eeee336c33dbb7494db14f1bc4e 100644 GIT binary patch literal 32520 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 T6Ia%|qUijne=h%r>-YW_*e1i% diff --git a/docs/savefig/fig_offtake.png b/docs/savefig/fig_offtake.png index 697fa865ae47b2d5e6e0b6b39dc7573c154c732f..427e2c2b06fdb16422bccc6b30dadb8e147a4eb2 100644 GIT binary patch literal 64560 zcmeFY^;cBy7e6|5hqQFVARQ7ifOHB1N=dhLk94PkbT**ZB2aEoyBbJE+myF0sy@$fkO zp9S1buGT#C_fLJmO|YC5_1r)p0@HurNZ%w&Y(b#=Y$e&(+R!Y-qn9tIj-TXH=h#T) z(ClGllexJ)@P$~QSfZHjW+ue^O2-g%l8=VlsUG+hbi36XK@{;-o`^n3q;xQ$uk{EV+`IEsnOt!C+ER&ZzzU6Vo;a{vzT*z);2dqAdhld1VH%R^0 z3vf}~U9;2Ddn}kghuTV(=0t{`lqwtzK6K1DwGhCa8YH7j6)8Z@=fv0MtFMKxZlSoj zeh7(&(JO^`&f3GVMO*63b0pA{!#MtDOCi+%-q$P)-G@Zp%C1 z`hl3mI5#?!;a#ad>%aC?p#1Nly`M)&}_4iT1=UufB=KKESN)$ zJ!qwr$;OGDoxPDa`0uNq9U;Ub<2CXo`|1A$<=tl_vF3zIESsLO&7)9O)XkKrB1^OE zc>~YKZ>HKL_CI!W5?-@_aM2%m>*ms922PT#X+0l=KkluMFw;^Y&`i7r103B6y)LQ2 zEl=BXFPG<+!kW^1ggwQvV1Z0>-pECXC$`ci_rK_$wigvlMR5_GEsuQ5K5catjGard zv|T0>$2LAM_SP?$eQTz^JWKvX%UJF7k-C@rVdP())z<rVP<0s?o+SDDXW>R#7TPOh0%p2@8cMB@rSo2I1v%kolKDP5%_&Z(h;-;6 zOUdsNPp}MsV}Y>@w%ur+>`picK;%25=jPHL4Fr8(ME+NFHV$Tit0v*5>nq3p!k&k} zll44L)?YuI(*5P*?tE}obRf=I@K(NT(+MA(Uw&fS-r#Zem?^u%sX_O>$RMj{(@Alc7F zFA~RBRzHCXEq^XsV=My^lay?0+`9WI&4Uahd5D^-!@n50<-asj+8Yx4U&-wANjc?N z@JI3ZpT_JS9*%OJ-}>Hcu}MaiSGHhZuln$GoP_bL8?4=tH8`!|gQ_`kWMpKT9

a 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 Vk=vL?7Y1JUm9_2`DL(t>zX3sh$}Io@ literal 64529 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ΝXA^gKcZYG% z_litB(5`Zx6f`?^9xZnUMsjTzN2rTp_LH$i2^Pt%KozEfq;>R#7bezHPR>7x*DO@G z)Kp2cd}wr(4ZR&*)C%r>Yrl$QZA-M;{gzG8RW#cBxF40iO6xjDW*FC{K^Z+N*d}LWF2A__<%#!!XL}{G z-WbP?P#slfs1^1L+%_Y>zFxf{0sNYn49|B8;zCubOg=l>>?7g=tI7pi2wwk>GoN=U z|Nh+&R9A(-K*(4nd-&1^a%$Uj5wox(Xw|J%99isizRr4JX=PRHakRZuV@Q4ose z%A$BsnGL{cmzXZC=b||{p>oF}^tlL_4ey}?V8AQw=_wdC%@8mF4e+Nspa1Oe)Yjft z%bo&khhkN-F;GYVi!ISQFc4%XtrGbxZi8o-0rR+RKDgyDm)%}DEXdX@1~KkW>lN^v z^~2Y~s+)3QG)({%2RSllq3v)*yHLaQQ;UR!!`?$+?UGtph#$$KqFlA6dp~7vn2tQk_asmRzEbsD&S3sD0E0?jQ0?W@w(x}f00E^M z8c58Ny*tt-!P$@Lh*1ri22y-3ho$GIAg6YD^Bh16T^z~7M+z9_Ou;6uc)e<;w1NUW zsI{>d82>ZF#fZZhGBmE5`7 zE2jEU=X?_T#bHf>%I758TY;H@TK7;M+fN6-3;(?cq>_LyT}-xwyFU|8ER>c=(Jva2 ztp=T#-|ml?VZ*>OK;r=>d=o?r*JBghkp<%%7_!``219fUD%IDWtT!Ajq6lE*VlG_3 z+TP;XP*2b66Yg)|DSO$N8Y~1`fc+8Bek%@E0U_iZE-9xz9EST*8Wf`Ac+K#E|I{P| zB{ZYYFzCk>ya1(x(}P{TfRx_EYt~Fdtwi_IT(MwJ0g<&0K55yWH6O z!Q11{sOMWCGfQEcQNAP43VAf9Nc+1&S3IwrlatevSkDDsRD>jGmXH}`N|4eK!yY-L zYyZjG%Bu9tMn>lS7_j!)Mf=mZ$#WRg>8_8Iwv>ziK0BD?ECOzTOCFgmZNMVI%)`AH z>Zy!UC5Xu)Zve&n4rpCu*D04BvKuLRten92G)3qwL)MQxaKAMqFOIrxYQL11m$w5S z2~7JOxGr-bgqT0sK%*Soi@`A{3y9+a7BqBq4r3GT*B7ZiC|B_ga20 zw!u>IU_-k+aQg6;elB>W^$5=qs2M;0`;93;%_{2jaBZzg2V=JoVQuQ>o}(%pjf7vUO`a?1dmYVhgWxH8qh=?x z1~@kmhjvh?*oCIC?fYj$sZP9Uz}p5wl1L~*0Ja?w&?P_pMOGKSEx`CUej|SOR&t%xhzfDo1 zMes|Zme$~<4*TCn@c*}=_}}`(|Nq$kr`NXrf&fo6U!q#(J=h7tU{4<_%N9z%e)k`r CciY$i diff --git a/docs/specialized_topics/resampling.rst b/docs/specialized_topics/resampling.rst index 843928e..86ae88e 100644 --- a/docs/specialized_topics/resampling.rst +++ b/docs/specialized_topics/resampling.rst @@ -55,7 +55,7 @@ Yearly resolution w q p r t 2024-01-01 00:00:00+01:00 0.113843 1000.0 30.0 30000.0 7.98 ========================= ======== ====== ======= ======= ==== -If we resample these values to a higher-frequency timeseries (e.g. quarteryearly), then the values of the summable dimensions (``q`` and ``r``) become smaller, as their values need to be "spread" over the resulting rows. If nothing more is known about how the energy is consumed, we assume that the consumption rate is constant throughout the period. This means we have to distribute the values over the new rows, **in proportion to their duration**. (Because the 3rd and 4th quarter have more days than the 1st and 2nd quarter, they get a larger fraction of the original value.) +If we resample these values to a shorter-frequency timeseries (e.g. quarteryearly), then the values of the summable dimensions (``q`` and ``r``) become smaller, as their values need to be "spread" over the resulting rows. If nothing more is known about how the energy is consumed, we assume that the consumption rate is constant throughout the period. This means we have to distribute the values over the new rows, **in proportion to their duration**. (Because the 3rd and 4th quarter have more days than the 1st and 2nd quarter, they get a larger fraction of the original value.) The values of the averagable dimensions (``w`` and ``t``) are **unchanged**, i.e., they are simply copies of the original value. Also the value of the derived quantity ``p`` turns out to be unchanged. The resulting values are therefore: @@ -87,7 +87,7 @@ Quarterly resolution w q p r t 2024-10-01 00:00:00+02:00 0.144862 320.0 30.80 9856.0 3.2 ========================= ======== ====== ======= ======= ==== -If we resample to a lower-frequency timeseries (e.g. yearly), we need to **sum** the values of the summable dimensions ``q`` and ``r`` (the duration does not need to be considered). +If we resample to a longer-frequency timeseries (e.g. yearly), we need to **sum** the values of the summable dimensions ``q`` and ``r`` (the duration does not need to be considered). For the time-averagable dimensions (``w`` and ``t``), the **average** of the individual values must be calculated, **weighted with the duration** of each row. (Alternatively, for the power ``w``: this is always ``q/duration`` and can always be calculated from these values after *they* are downsampled.) @@ -102,7 +102,7 @@ Downsampled to yearly resolution w q p r t 2024-01-01 00:00:00+01:00 0.113843 1000.0 30.0 30000.0 7.98 ================================ ======== ====== ======= ======= ==== -(Note that the 'simple row-average' of the power, temperature, and price give us incorrect values.) +Note that the 'simple row-average' of the power, temperature, and price would give us incorrect values. -------------------------------- Downsampling example, price-only @@ -131,10 +131,10 @@ Downsampled to yearly resolution p 2024-01-01 00:00:00+01:00 28.78 ==================================== ======= -The reason for the higher price in the previous example, is that, there, it is weighted with the *energy* in each period. We had more energy in the expensive quarters, and less in the cheaper ones, which results in a higher price for the entire year. +The reason for the higher price in the previous example, is that, there, the price is weighted with the *energy* in each period. We had more energy in the expensive quarters, and less in the cheaper ones, which results in a higher price for the entire year. ----------------------------- Resampling with ``portfolyo`` ----------------------------- -When changing the frequency of a ``PfLine`` or ``PfState`` object, the considerations above are automatically taken into account. If you are in the situation of having to change the frequency of a ``pandas.Series`` or ``DataFrame`` with a ``DatetimeIndex``, however, the relevant functions are also available at the ``portfolyo.tools.changefreq`` module. \ No newline at end of file +When changing the frequency of a ``PfLine`` or ``PfState`` object, the considerations above are automatically taken into account. If you are in the situation of having to change the frequency of a ``pandas.Series`` or ``DataFrame`` with a ``DatetimeIndex``, however, the relevant functions are also available at the ``portfolyo.tools.changefreq`` module. diff --git a/portfolyo/__init__.py b/portfolyo/__init__.py index e561768..a10d888 100644 --- a/portfolyo/__init__.py +++ b/portfolyo/__init__.py @@ -13,9 +13,14 @@ from .tools.freq import FREQUENCIES from .tools.standardize import frame as standardize from .tools.tzone import force_agnostic, force_aware -from .tools.unit import Q_ +from .tools.unit import Q_, ureg, Unit from .tools.wavg import general as wavg +VOLUME = Kind.VOLUME +PRICE = Kind.PRICE +REVENUE = Kind.REVENUE +COMPLETE = Kind.COMPLETE + extendpandas.apply() suppresswarnings.apply() diff --git a/portfolyo/testing/__init__.py b/portfolyo/testing/__init__.py index 987881a..98cdf23 100644 --- a/portfolyo/testing/__init__.py +++ b/portfolyo/testing/__init__.py @@ -3,4 +3,5 @@ assert_index_equal, assert_indices_compatible, assert_series_equal, + assert_value_equal, ) diff --git a/portfolyo/testing/testing.py b/portfolyo/testing/testing.py index 7d06df0..a90f901 100644 --- a/portfolyo/testing/testing.py +++ b/portfolyo/testing/testing.py @@ -1,48 +1,55 @@ """Testing of pandas objects, taking into account they may have units.""" import functools +from typing import Any import numpy as np import pandas as pd - +import pint from .. import tools from ..tools.unit import Q_ +def assert_value_equal(left: Any, right: Any): + try: + if np.isnan(left) and np.isnan(right): + return + assert np.isclose(left, right) + except Exception as e: + raise AssertionError from e + + @functools.wraps(pd.testing.assert_frame_equal) def assert_frame_equal(left: pd.DataFrame, right: pd.DataFrame, *args, **kwargs): # Dataframes equal even if *order* of columns is not the same. - left = tools.unit.drop_units(left).sort_index(axis=1) - right = tools.unit.drop_units(right).sort_index(axis=1) - left = left.replace([np.inf, -np.inf], np.nan) - right = right.replace([np.inf, -np.inf], np.nan) - # TODO: Test if units are the same - pd.testing.assert_frame_equal(left, right, *args, **kwargs) + left = left.sort_index(axis=1) + right = right.sort_index(axis=1) + assert set(left.columns) == set(right.columns) + + for (coll, sl), (colr, sr) in zip(left.items(), right.items()): + # Names must match. + assert coll == colr + # Series must match. + assert_series_equal(sl, sr, *args, **kwargs) @functools.wraps(pd.testing.assert_series_equal) def assert_series_equal(left: pd.Series, right: pd.Series, *args, **kwargs): - if hasattr(left, "pint") and hasattr(right, "pint"): # pint-series - left, right = left.pint.to_base_units(), right.pint.to_base_units() - assert left.pint.u == right.pint.u - assert_series_equal(left.pint.m, right.pint.m, *args, **kwargs) - - elif left.dtype == right.dtype == object: # maybe: series of Quantities - try: - lq = [v.to_base_units() for v in left.values] - rq = [v.to_base_units() for v in right.values] - except AttributeError as e: - raise AssertionError from e - left = pd.Series([q.m for q in lq], left.index) - right = pd.Series([q.m for q in rq], right.index) - assert_series_equal(left, right, *args, **kwargs) - for lu, ru in zip([q.u for q in lq], [q.u for q in rq]): - assert lu == ru - - else: # normal series of floats or ints - left = left.replace([np.inf, -np.inf], np.nan) - right = right.replace([np.inf, -np.inf], np.nan) - pd.testing.assert_series_equal(left, right, *args, **kwargs) + leftm, leftu = tools.unit.split_magn_unit(left) + rightm, rightu = tools.unit.split_magn_unit(right) + + # Magnitudes must be the same. + leftm = leftm.replace([np.inf, -np.inf], np.nan) + rightm = rightm.replace([np.inf, -np.inf], np.nan) + pd.testing.assert_series_equal(leftm, rightm, *args, **kwargs) + + # Units must be the same. + if leftu is None: + assert leftu is rightu + elif isinstance(leftu, pint.Unit): # all values share the same unit, leftu is Unit + assert leftu == rightu + else: # each value has its own unit; leftu is Series + pd.testing.assert_series_equal(leftu, rightu) assert_index_equal = pd.testing.assert_index_equal diff --git a/portfolyo/tools/leftandright.py b/portfolyo/tools/leftandright.py index 6fbaa1d..2049cee 100644 --- a/portfolyo/tools/leftandright.py +++ b/portfolyo/tools/leftandright.py @@ -9,6 +9,7 @@ from . import floor as tools_floor from . import isboundary as tools_isboundary +from . import stamp as tools_stamp def stamps( @@ -29,11 +30,12 @@ def stamps( If a value is given for each, they are swapped if their order is incorrect. tz : str, optional (default: None) Timezone for the returned timestamps. Only used if both ``left`` and ``right`` - are missing. + are missing, or if they are not pandas timestamps yet. start_of_day : dt.time, optional (default: midnight) Time of day at which daily-or-longer delivery periods start. E.g. if dt.time(hour=6), a delivery day is from 06:00:00 (incl) until 06:00:00 (excl). - Only used if both ``left`` and ``right`` are missing. + Only used if both ``left`` and ``right`` are missing, or if they are not pandas + timestamps yet and missing a time-component. Returns ------- @@ -41,13 +43,13 @@ def stamps( Notes ----- - - Parameters ``tz`` and ``start_of_day`` are only used if ``left`` and ``right`` are - both not specified. - If both ``left`` and ``right`` are specified, an error is raised if their timezones are not identical or if their times are not identical. """ # Convert both into timestamps, if possible. None is converted into pd.NaT - left, right = pd.Timestamp(left), pd.Timestamp(right) + # left, right = pd.Timestamp(left), pd.Timestamp(right) + left = tools_stamp.create(left, tz, start_of_day) + right = tools_stamp.create(right, tz, start_of_day) if right is pd.NaT: if left is pd.NaT: diff --git a/portfolyo/tools/stamp.py b/portfolyo/tools/stamp.py new file mode 100644 index 0000000..944de4b --- /dev/null +++ b/portfolyo/tools/stamp.py @@ -0,0 +1,42 @@ +"""Module to create a timestamp from any input.""" + + +import datetime as dt +from typing import Any + +import pandas as pd + + +def create(ts: Any, tz: str = None, start_of_day: dt.time = None) -> pd.Timestamp: + """Creates a timestamp. + + Parameters + ---------- + ts : Any + Timestamp or something that can be turned into a timestamp. + tz : str, optional + Timezone of the timestamp to create. Not used if ``ts`` is already a valid + pandas timestamp. I.e., the timezone of ``ts`` takes precedence. + start_of_day : dt.time, optional + Time of the timestamp. Not used if ``ts`` is already a valid pandas timestamp + or contains a time part. I.e., the start_of_day of ``ts`` takes precedence. + + Returns + ------- + pd.Timestamp + """ + # Already a timestamp; nothing to do. + if isinstance(ts, pd.Timestamp): + return ts + + # Try to create a timestamp with the correct timezone. + ts = pd.Timestamp(ts, tz=tz) + if ts is pd.NaT: + return ts + + # See if we need to change the time. + if ts.time() != dt.time(hour=0, minute=0, second=0) or start_of_day is None: + return ts + + ts = ts.replace(hour=start_of_day.hour, minute=start_of_day.minute) + return ts diff --git a/portfolyo/tools/standardize.py b/portfolyo/tools/standardize.py index f5df5aa..93f32db 100644 --- a/portfolyo/tools/standardize.py +++ b/portfolyo/tools/standardize.py @@ -12,6 +12,7 @@ from . import tzone as tools_tzone +# TODO: remove 'Europe/Berlin' as default for ``tz``, use None instead. def frame( fr: Union[pd.Series, pd.DataFrame], force: str = None, @@ -32,7 +33,7 @@ def frame( as-is. bound : {'left', 'right'}, optional (default: 'left') If 'left' ('right'), specifies that input timestamps are left-(right-)bound. - tz : str, optional (default: "Europe/Berlin") + tz : str, optional (default: None) The timezone in which to interpret non-localized values. If ``force`` == 'aware': also the timezone to localize to. Ignored if ``force`` is None. floating : bool, optional (default: True) @@ -97,12 +98,15 @@ def frame( # If the frequency is not found, and it is tz-naive, the index may need to be localized. if not freq_input and not tz_input and tz: # left -> tz-aware (try) + # fr is tz-agnostic. try: fr_aware = fr.tz_localize(tz, ambiguous="infer") except (AmbiguousTimeError, NonExistentTimeError): pass # fr did not need / cound not be localized. Continue with fr as-is. else: - return frame(fr_aware, force, "left", **kwargs) + # Could be localized. Again remove localization if force == 'agnostic' or None. + force_to = force or "agnostic" + return frame(fr_aware, force_to, "left", **kwargs) # All options to infer frequency have been exhausted. One may or may not have been found. # Does the user want to force a frequency? diff --git a/portfolyo/tools/unit.py b/portfolyo/tools/unit.py index 09fb3d6..b6175a7 100644 --- a/portfolyo/tools/unit.py +++ b/portfolyo/tools/unit.py @@ -3,7 +3,7 @@ """ from pathlib import Path -from typing import Union +from typing import Tuple, Union import pandas as pd import pint @@ -24,7 +24,7 @@ # Set for export. PA_ = pint_pandas.PintArray Q_ = ureg.Quantity - +Unit = ureg.Unit NAMES_AND_UNITS = { "w": ureg.MW, @@ -37,22 +37,6 @@ } -def to_compact(value: Union[pint.Quantity, pd.Series, pd.DataFrame]): - # TODO: Unused. Remove? - """Convert to more compact unit by moving absolute magnitude into readable range.""" - if isinstance(value, pint.Quantity): - return value.to_compact() - elif isinstance(value, pd.Series): - newunits = value.abs().max().to_compact().units - return value.pint.to(newunits) - elif isinstance(value, pd.DataFrame): - return pd.DataFrame({name: to_compact(s) for name, s in value.items()}) - else: - raise TypeError( - "`value` must be a Quantity, or Series or DataFrame of quantities." - ) - - def to_name(unit: pint.Unit) -> str: """Find the standard column name belonging to unit `unit`. Checks on dimensionality, not exact unit.""" @@ -69,15 +53,79 @@ def from_name(name: str) -> pint.Unit: raise ValueError(f"No standard unit found for name '{name}'.") -def drop_units(fr: Union[pd.Series, pd.DataFrame]) -> Union[pd.Series, pd.DataFrame]: - """ - Convert ``fr`` to base units and return only the magnitude. +def defaultunit( + val: Union[int, float, pint.Quantity, pd.Series, pd.DataFrame], +) -> Union[float, pint.Quantity, pd.Series, pd.DataFrame]: + """Convert ``val`` to base units. Also turns dimensionless values into floats. + + Parameters + ---------- + val : int, float, pint.Quantity, pd.Series, or pd.DataFrame + The value to convert to base units. - If ``fr`` is not unit-aware, return as-is. + Returns + ------- + float, pint.Quantity, pd.Series, or pd.DataFrame + In base units. + """ + # Do the conversion. + if isinstance(val, int): + return float(val) + elif isinstance(val, float): + return val + elif isinstance(val, pint.Quantity): + if val.units == ureg.Unit("dimensionless"): + return val.magnitude + return val.to_base_units() + elif isinstance(val, pd.Series): + if isinstance(val.dtype, pint_pandas.PintType): + if val.pint.units == ureg.Unit("dimensionless"): + return val.astype(float) + return val.pint.to_base_units() + elif pd.api.types.is_object_dtype(val.dtype) and isinstance(val.iloc[0], Q_): + try: + unit = val.iloc[0].to_base_units().units + pintseries = val.astype(f"pint[{unit}]") + return defaultunit(pintseries) + except pint.DimensionalityError: # not all have same dimension + # convert to base units instead. + magn_unit_tupls = [split_magn_unit(v) for v in val.values] + qq = [m if u is None else Q_(m, u) for m, u in magn_unit_tupls] + return pd.Series(qq, val.index) + elif pd.api.types.is_integer_dtype(val.dtype): + return val.astype(float) + else: # series of floats, bools, timestamps, ... + return val + elif isinstance(val, pd.DataFrame): + return pd.DataFrame({col: defaultunit(s) for col, s in val.items()}) + raise TypeError("``val`` must be an int, float, Quantity, Series, or DataFrame.") + + +def split_magn_unit( + val: Union[int, float, pint.Quantity, pd.Series] +) -> Union[ + Tuple[float, None], + Tuple[float, pint.Unit], + Tuple[pd.Series, None], + Tuple[pd.Series, pint.Unit], + Tuple[pd.Series, pd.Series], +]: + """Split ``val`` into magnitude and units. If ``val`` is a Series with uniform + dimension, the unit is returned as a pint Unit. If not, it is returned as a Series. """ - if isinstance(fr, pd.Series): - if hasattr(fr, "pint"): - return fr.pint.to_base_units().pint.m - return fr - else: - return pd.DataFrame({col: drop_units(s) for col, s in fr.items()}) + val = defaultunit(val) + if isinstance(val, pint.Quantity): + return val.magnitude, val.units + elif isinstance(val, pd.Series): + if isinstance(val.dtype, pint_pandas.PintType): + return val.pint.magnitude, val.pint.units + elif pd.api.types.is_object_dtype(val.dtype) and isinstance(val.iloc[0], Q_): + # series of quantities? + m = [q.magnitude for q in val.values] + u = [q.units for q in val.values] + return pd.Series(m, val.index), pd.Series(u, val.index) + return val, None + elif isinstance(val, pd.DataFrame): + raise TypeError("For dataframes, handle the series seperately.") + else: # int, float, bool, timestamp, ... + return val, None diff --git a/portfolyo/tools/wavg.py b/portfolyo/tools/wavg.py index 3d7652e..add0d43 100644 --- a/portfolyo/tools/wavg.py +++ b/portfolyo/tools/wavg.py @@ -1,11 +1,50 @@ -from typing import Iterable, Union +from typing import Iterable, Mapping, Union import numpy as np import pandas as pd -import pint from . import unit as tools_unit +# Developer notes: +# HACK: for speed: +# meaning: for series and dataframes with pint quantities, .sum() does not work, +# and .apply(np.sum) is really slow. The workaround is fast also for pint quantities. + +# Developer notes: +# The following behaviour is wanted in calculating the weighted average: + +# weights values rule | result + +# sum of weights != 0 +# 1, -1, 2 10, 20, 30 normal | (10*1 + 20*-1 + 30*2 ) / (1 + -1 + 2) +# 1, -1, 2 10, NaN, 30 NaN if values include NaN | NaN +# 1, 0, 2 10, NaN, 30 ignore NaN if weight = 0 | (10*1 + 30*2) / (1 + 2) +# --> Remove all values for which weight == 0. +# --> If remaining values conain NaN --> result is NaN. +# --> Otherwise, calculate the result normally. + +# sum of weights == 0 but not all 0 +# 1, 1, -2 10, 20, 30 Inf if values distinct | Inf +# 1, 1, -2 10, 10, 10 value if values identical | 10 +# 1, -1, 0 10, 10, 30 ignore value if weight = 0 | 10 +# 1, 1, -2 10, 10, NaN NaN if values include NaN | NaN (done) +# 1, -1, 0 10, 10, NaN ignore NaN if weight = 0 | 10 +# 1, -1, 0 NaN, NaN, NaN NaN if values are all NaN | NaN +# --> Remove all values for which weight == 0. +# --> If remaining values contain NaN --> result is NaN +# --> Otherwise, if remaining values are identical --> result is that value +# --> Otherwise, result is Inf. + +# all weights are 0 +# 0, 0, 0 10, 20, 30 Inf if values distinct | Inf +# 0, 0, 0 10, 10, 10 value if values identical | 10 +# 0, 0, 0 10, 10, NaN NaN if values include NaN | NaN +# --> If values contain NaN --> result is NaN +# --> Otherwise, if values are identical --> result is that value +# --> Otherwise, result is Inf. + +RESULT_IF_WEIGHTSUM0_VALUESNOTUNIFORM = np.nan + def general( fr: Union[pd.Series, pd.DataFrame], @@ -44,7 +83,7 @@ def general( def series( - s: pd.Series, weights: Union[Iterable, pd.Series] = None + s: pd.Series, weights: Union[Iterable, Mapping, pd.Series] = None ) -> Union[float, tools_unit.Q_]: """ Weighted average of series. @@ -53,10 +92,10 @@ def series( ---------- s : pd.Series The input values. - weights : Union[Iterable, pd.Series], optional - The weights. If provided as a Series, the weights and values are aligned along - their indices. If no weights are provided, the normal (unweighted) average is - returned instead. + weights : Union[Iterable, Mapping, pd.Series], optional + The weights. If provided as a Mapping or Series, the weights and values are + aligned along their indices/keys. If no weights are provided, the normal + (unweighted) average is returned instead. Returns ------- @@ -72,30 +111,49 @@ def series( return s.mean() # Prep: ensure weights is also a Series. - if not isinstance(weights, pd.Series): - weights = pd.Series(weights, s.index) - - # Special case: if total weight is 0, but all original values are identical, return this value. - if np.isclose(weights.sum(), 0) and s.nunique() == 1: - return s.iloc[0] - - # Prep: if a weight is 0, corresponding value is irrelevant. Even if it is NaN. - drop = weights == 0 # Replace with np.isclose? Must work with float and pint - if drop.any() and not drop.all(): - keep = weights[~drop].index - s = s.loc[keep] - weights = weights.loc[keep] - # Get multiplication factors as floats. - factors = (weights / weights.sum()).astype(float) - # Calculate the average. - result = s.mul(factors).sum(skipna=False) # float or quantity + weights = weights_as_series(weights, s.index) + # Keep only relevant section. + try: + s = s.loc[weights.index] + except KeyError as e: # more weights than values + raise ValueError("No values found for one or more weights.") from e + # Replace NaN with 0 in locations where it doesn't change the result. + replaceable = s.isna() & (weights == 0.0) + s[replaceable] = 0.0 - return result + # If we arrive here, ``s`` only has NaN on locations where weight != 0. + + # Check if ALL weights are 0. + # In that case, the result is NaN. + if (weights == 0).all(): # edge case (very uncommon) + return np.nan + + # If we arrive here, not all weights are 0. + + # Check if ``s`` contains a NaN. + # In that case, the result is NaN. + if s.isna().sum() > 0: + return np.nan + + # For the other rows, we must calculate the wavg. + + # Check if SUM of weights is 0. + # In that case, the result is NaN in case of non-uniform values. + weightsum = weights.sum() # a float or quantity + if np.isclose(weightsum, 0): # edge case (more common) + is_uniform = values_areuniform(s) + return s.iloc[0] if is_uniform else np.nan + + # If we arrive here, the sum of the weights is not zero. + + factors = weights.div(weightsum).astype(float) + scaled_values = s * factors # fast, even with quantities + return sum(scaled_values) def dataframe( df: pd.DataFrame, - weights: Union[Iterable, pd.Series, pd.DataFrame] = None, + weights: Union[Iterable, Mapping, pd.Series, pd.DataFrame] = None, axis: int = 0, ) -> pd.Series: """ @@ -105,10 +163,10 @@ def dataframe( ---------- df : pd.DataFrame The input values. - weights : Union[Iterable, pd.Series, pd.DataFrame], optional - The weights. If provided as a Series, its index are is used for alignment (with - ``df``'s index if axis==0, or its columns if axis==1). If no weights are provided, - the normal (unweighted) average is returned instead. + weights : Union[Iterable, Mapping, pd.Series, pd.DataFrame], optional + The weights. If provided as a Series or Mapping, its index are is used for + alignment (with ``df``'s index if axis==0, or its columns if axis==1). If no + weights are provided, the normal (unweighted) average is returned instead. axis : int, optional (default: 0) - if 0, calculate average over all rows (for each column); - if 1, calculate average over all columns (for each row). @@ -122,24 +180,281 @@ def dataframe( ----- Will raise error if axis == 1 and columns have distinct unit-dimensions. """ - # Prep: orient so that we can always average over rows. - if axis == 1: - df = df.T + # Developer note: it is possible to repeatedly call the `series` function in this + # same module, which results in a much shorter function. However, the speed penalty + # is enormous, which is why this elaborate function is used. - # Do averaging series-by-series. + # Unweighted average if no weights are provided. + if weights is None: + # Fix possible problems, like distinct units of same dimension + df = tools_unit.defaultunit(df) + return df.apply(np.mean, axis=axis) # can't do .mean() if pint-series + + # Prep: orient so that we can always average over columns. + if axis == 0: + df = df.T # slow, but axis==0 is uncommon + # HACK: transposing moves unit to element-level, undo here + + # Fix possible problems, also those introduced by .T + df = tools_unit.defaultunit(df) + + # Do averaging. if isinstance(weights, pd.DataFrame): - if axis == 1: - weights = weights.T - result = df.apply(lambda s: series(s, weights.loc[:, s.name])) - else: # weights == series or iterable or None - result = df.apply(lambda s: series(s, weights)) - - # Correction: turn series of pint-Quantities into pint-series, if possible. - if pd.api.types.is_object_dtype(result): - firstval = result.iloc[0] - try: - result = result.astype(f"pint[{firstval.units}]") - except (AttributeError, pint.DimensionalityError): - pass + if axis == 0: + weights = weights.T # slow, but axis==0 is uncommon + # HACK: transposing moves unit to element-level, undo here + weights = tools_unit.defaultunit(weights) + + result = dataframe_columnwavg_with_weightsdataframe(df, weights) + + else: # weights == series or iterable + weights = weights_as_series(weights, df.columns) # ensure weights is Series + result = dataframe_columnwavg_with_weightsseries(df, weights) + + return tools_unit.defaultunit(result) + + +def dataframe_columnwavg_with_weightsdataframe( + df: pd.DataFrame, weights: pd.DataFrame +) -> pd.Series: + # Keep only relevant section. + try: + df = df.loc[weights.index, weights.columns] + except KeyError as e: # more weights than values + raise ValueError("No values found for one or more weights.") from e + originalindex = df.index + + # Create masks and aggregates for weights. + # . One float/quantity for each row. + weightssum = sum(s for _, s in weights.items()) # HACK: for speed + # . One boolean for each row. + weights_sum0 = weightssum == 0.0 # TODO: use np.isclose? + # . One boolean for each weight. + weight_is0 = weights == 0.0 # TODO: use np.isclose? + # . One boolean for each row. + weights_all0 = weight_is0.all(axis=1) + + # Handle each case seperately, and combine later. + + series = [] + + # "Normal": sum of weights != 0. + + if (mask := ~weights_sum0).any(): + series.extend( + _dataframe_columnwavg_with_weightssumnot0( + df[mask], weights[mask], weightssum[mask] + ) + ) + + # Sum of weights == 0 but not all values are 0. + + if (mask := weights_sum0 & ~weights_all0).any(): + series.extend( + _dataframe_columnwavg_with_weightssum0notall0(df[mask], weights[mask]) + ) + + # Each weight has a value of 0. + + if (mask := weights_all0).any(): + series.extend(_dataframe_columnwavg_with_weightsall0(df[mask])) + + # Every index value of weights is now in exactly one series. + return concatseries(series, originalindex) + + +def dataframe_columnwavg_with_weightsseries( + df: pd.DataFrame, weights: pd.Series +) -> pd.Series: + originalindex = df.index + # Keep only relevant section. + try: + df = df.loc[:, weights.index] + except KeyError as e: # more weights than values + raise ValueError("No values found for one or more weights.") from e + + # Create masks and aggregates for weights. + # . One fleat/quantity. + weightssum = sum(w for w in weights.values) + # . One boolean. + weights_sum0 = weightssum == 0.0 + # . One boolean for each weight. + weight_is0 = weights == 0.0 + # . One boolean. + weights_all0 = weight_is0.all() + + # See which case we have and calculate. + + # "Normal": sum of weights != 0. + + if not weights_sum0: + series = _dataframe_columnwavg_with_weightssumnot0(df, weights, weightssum) + + # Sum of weights == 0 but not all values are 0. + + elif not weights_all0: + series = _dataframe_columnwavg_with_weightssum0notall0(df, weights) + + # Each weight has a value of 0. + + else: + series = _dataframe_columnwavg_with_weightsall0(df) + + # Every index value of weights is now in exactly one series. + return concatseries(series, originalindex) + + +def _dataframe_columnwavg_with_weightssumnot0( + df: pd.DataFrame, + weights: Union[pd.Series, pd.DataFrame], + weightssum: Union[float, tools_unit.Q_, pd.Series], +) -> Iterable[pd.Series]: + # Calculate the weighted average if sum of weights != 0. + weight_is0 = weights == 0.0 + value_isna = df.isna() + df = df.where(~(weight_is0 & value_isna), other=0.0) # to ignore NaN if allowed + factors = weights.div(weightssum, axis=0).astype(float) + scaled_values = df * factors # fast, even with quantities + result = sum(s for _, s in scaled_values.items()) # HACK: for speed + return [result] + + +def _dataframe_columnwavg_with_weightssum0notall0( + df: pd.DataFrame, weights: Union[pd.Series, pd.DataFrame] +) -> Iterable[pd.Series]: + # Calculate the weighted average if sum of weights == 0, but not all weights are 0. + + series = [] + + if len(df.index) == 0: + return series + + # Create masks and aggregates. + weight_is0 = weights == 0.0 # one boolean for each weight + value_isna = df.isna() # one boolean for each value + + # Rows containing NaN-values whose weight != 0 + + mask = (value_isna & ~weight_is0).any(axis=1) + series.append(pd.Series(np.nan, df.index[mask])) + + # Remaining rows only have NaN if weight == 0; these elements can be ignored. + # Ignore ALL values with weight == 0, and check if rows are uniform. + + if isinstance(weights, pd.Series): + # Keep only remaining rows and keep only columns with weight != 0. + df = df.loc[~mask, ~weight_is0] + else: + # Keep only remaining rows, and replace all values with weight == 0 with NaN. + df, weight_is0 = df[~mask], weight_is0[~mask] + df = df.where(~weight_is0, other=np.nan) + series.append(rowvalue_uniformity(df)) + return series + + +def _dataframe_columnwavg_with_weightsall0( + df: pd.DataFrame, +) -> Iterable[pd.Series]: + # Calculate the weighted average if all weights == 0. + + series = [] + + if len(df.index) == 0: + return series + + # Create masks and aggregates. + value_isna = df.isna() # one boolean for each value + + # Rows containing NaN-values + + mask = value_isna.any(axis=1) + series.append(pd.Series(np.nan, df[mask].index)) + # Keep only remaining rows. + df = df[~mask] + + # Remaining rows do not have NaN. + + # Check if rows are uniform. + series.append(rowvalue_uniformity(df)) + + return series + + +def rowvalue_uniformity(df: pd.DataFrame) -> pd.Series: + """Calculate a value for each row. First discard the NaN. Then see if remaining + values are identical. If yes, that value is the result. If not, NaN is the result. + """ + + # HACK: we should do these calculations row-by-row, but this is really slow for pint, + # because the row Series don't have a pint-unit, but are series of pint-quantities. + # So we use the following column-operations instead to get to the same result. + # - Replace values whose weight == 0 with NaN. + # We now want to verify, if all remainig values in a row are identical. + # - Initially fill buffer with NaN-values. + # - Observe first column. Ignore NaN. For not-NaN: put in buffer. + # - Observe second column. Ignore NaN. For not-NaN: if buffer is empty, put in buffer. + # If buffer is not empty, compare. If not same, put uniform-flag to False. + # - Continue for other columns. + # Uniform flag is now set to False for non-uniform rows. For rows with uniform values + # or uniform NaN, this value/NaN is found in buffer. + uniform = pd.Series(True, df.index) + buffer = pd.Series(np.nan, df.index) # define to ensure exists even if df empty + for i, (c, s) in enumerate(df.items()): + if i == 0: + # define here to ensure ``values`` has pint dtype if df does too + to_type = float if pd.api.types.is_integer_dtype(s.dtype) else s.dtype + buffer = pd.Series(np.nan, s.index).astype(to_type) + must_compare = s.notna() & buffer.notna() + if must_compare.any(): + # HACK: cannot use ``uniform & (...)`` because must_compare has partial index, and missing values are set to False + uniform = ~(~uniform | ~(s[must_compare] == buffer[must_compare])) + must_replace = s.notna() & buffer.isna() + if must_replace.any(): + buffer = buffer.fillna(s[must_replace]) + + buffer[~uniform] = RESULT_IF_WEIGHTSUM0_VALUESNOTUNIFORM + return buffer + + +def weights_as_series( + weights: Union[Iterable, Mapping], refindex: Iterable +) -> pd.Series: + if isinstance(weights, pd.Series): + return weights + if isinstance(weights, Mapping): + return pd.Series(weights) + if isinstance(weights, Iterable): + return pd.Series(weights, refindex) + raise TypeError("``weights`` must be iterable or mapping.") + + +def values_areuniform(series: pd.Series, mask: Iterable = None) -> bool: + """Return True if all values in series are same. If mask is provided, only compare + values where the mask is True. If there are no values to compare, return True.""" + values = series[mask].values if mask is not None else series.values + for i, val in enumerate(values): + if i == 0: + theval = val + elif val != theval: + return False + return True + + +def concatseries(series: Iterable[pd.Series], refindex: Iterable = None) -> pd.Series: + """Concatenate some series, and try to make it a pint-series if possible.""" + dtypes = set() + for s in series: + if s.isna().all(): + continue + dtypes.add(s.dtype) + if len(dtypes) == 1: + dtype = dtypes.pop() + series = [s.astype(dtype) for s in series] + result = pd.concat(series) + if refindex is None: + return result.sort_index() + result = result.loc[refindex] + if isinstance(refindex, pd.DatetimeIndex) and (freq := refindex.freq): + result.index.freq = freq return result diff --git a/pyproject.toml b/pyproject.toml index dde3885..974f208 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "portfolyo" -version = "0.5.7" +version = "0.5.10" description = "Analyse and manipulate timeseries related to power and gas offtake portfolios" authors = [ "Ruud Wijtvliet ", @@ -22,8 +22,8 @@ numpy = "^1.26.2" [tool.poetry.group.test.dependencies] codecov = "^2.1.13" -coverage = "^7.3.0" pytest = "^7.4.1" +coverage = "^7.3.0" pytest-cov = "^4.1.0" pyyaml = "^6.0.1" openpyxl = "^3.1.2" diff --git a/tests/core/pfline/test_pfline_init.py b/tests/core/pfline/test_pfline_init.py index 4f5fa0b..76e1f63 100644 --- a/tests/core/pfline/test_pfline_init.py +++ b/tests/core/pfline/test_pfline_init.py @@ -63,7 +63,13 @@ def get_testcase_A( """Create test case that uses ``columns`` as parameter.""" # Data. - df = dev.get_dataframe(i, columns, has_unit) + df_out = dev.get_dataframe(i, columns, True) + if has_unit: + df = df_out + else: + df = df_out.astype(float) + + # Input data into the initialisation function. if inputtype is InputTypeA.FLATDF: data_in = df elif inputtype is InputTypeA.FLATDICT: @@ -73,7 +79,7 @@ def get_testcase_A( if len(data_in) == 1: data_in = data_in[0] # ... or as single series if not has_unit: - df = Exception + df_out = Exception elif inputtype is InputTypeA.FLATPFLINE: data_in = create.flatpfline(df) elif inputtype is InputTypeA.NESTEDPFLINE: @@ -90,15 +96,15 @@ def get_testcase_A( else: raise ValueError("unknown inputtype") - # Checks. + # Kind. if columns in ["w", "q"]: kind = Kind.VOLUME - elif columns in ["p"]: + elif columns == "p": kind = Kind.PRICE else: kind = Kind.COMPLETE - return InitTestcase(data_in, df, kind) + return InitTestcase(data_in, df_out, kind) def get_testcase_B( diff --git a/tests/core/pfline/test_pfline_text.py b/tests/core/pfline/test_pfline_text.py new file mode 100644 index 0000000..5f8c980 --- /dev/null +++ b/tests/core/pfline/test_pfline_text.py @@ -0,0 +1,13 @@ +"""Test if portfolio line can be printed.""" + +import pytest +import portfolyo as pf + + +@pytest.mark.parametrize("levels", [1, 2, 3]) +@pytest.mark.parametrize("kind", pf.Kind) +@pytest.mark.parametrize("flatten", [True, False]) +def test_pfline_print(levels: int, kind: pf.Kind, flatten: bool): + """Test if portfolio line can be printed.""" + pfl = pf.dev.get_pfline(kind=kind, nlevels=levels) + pfl.print(flatten) diff --git a/tests/core/pfstate/test_pfstate_text.py b/tests/core/pfstate/test_pfstate_text.py new file mode 100644 index 0000000..7a1f9e8 --- /dev/null +++ b/tests/core/pfstate/test_pfstate_text.py @@ -0,0 +1,9 @@ +"""Test if portfolio state can be printed.""" + +import portfolyo as pf + + +def test_pfstate_print(): + """Test if portfolio state can be printed.""" + pfs = pf.dev.get_pfstate() + pfs.print() diff --git a/tests/tools/test_intersect.py b/tests/tools/test_intersect.py index 623d806..fbb83f4 100644 --- a/tests/tools/test_intersect.py +++ b/tests/tools/test_intersect.py @@ -180,7 +180,9 @@ def do_test_intersect_index( expected_freq: str = None, ): # Error case. - if type(expected_startdate) is type and issubclass(expected_startdate, Exception): + if isinstance(expected_startdate, type) and issubclass( + expected_startdate, Exception + ): with pytest.raises(expected_startdate): tools.intersect.indices(*idxs) return diff --git a/tests/tools/test_leftandright.py b/tests/tools/test_leftandright.py index 979dfb8..c63aff0 100644 --- a/tests/tools/test_leftandright.py +++ b/tests/tools/test_leftandright.py @@ -36,10 +36,11 @@ def test_leftandright_nonespecified(tz_param: str, starttime: str): ((None, "2021-10-09 06:00"), ("2021-01-01 06:00", "2021-10-09 06:00")), ], ) -def test_leftandright_onespecified( +def test_leftandright_onespecified_astimestamp( tss: tuple, expected_tss: tuple, tz_specified: str, tz_param: str, starttime: str ): - """Test if start and end of interval are correctly calculated, if one is specified.""" + """Test if start and end of interval are correctly calculated, if one is specified + as a timestamp.""" # One specified, so tz parameter and start_of_day should be ignored. # There should be no timezone errors and no swapping is necessary. tss = [pd.Timestamp(ts, tz=tz_specified) for ts in tss] # one will be NaT @@ -51,6 +52,42 @@ def test_leftandright_onespecified( assert a == b +@pytest.mark.parametrize("tz_param", [None, "Europe/Berlin", "Asia/Kolkata"]) +@pytest.mark.parametrize( + ("tss,starttime,expected_tss"), + [ + (("2020-01-01", None), None, ("2020-01-01", "2021-01-01")), + (("2020-01-01", None), "00:00", ("2020-01-01", "2021-01-01")), + (("2020-01-01", None), "06:00", ("2020-01-01 06:00", "2021-01-01 06:00")), + ((None, "2020-02-02"), None, ("2020-01-01", "2020-02-02")), + ((None, "2020-02-02"), "00:00", ("2020-01-01", "2020-02-02")), + ((None, "2020-02-02"), "06:00", ("2020-01-01 06:00", "2020-02-02 06:00")), + # starttime should be ignored, because already present in timestamp. + (("2020-03-03 06:00", None), None, ("2020-03-03 06:00", "2021-01-01 06:00")), + (("2020-03-03 06:00", None), "00:00", ("2020-03-03 06:00", "2021-01-01 06:00")), + (("2020-03-03 06:00", None), "06:00", ("2020-03-03 06:00", "2021-01-01 06:00")), + ((None, "2021-10-09 06:00"), None, ("2021-01-01 06:00", "2021-10-09 06:00")), + ((None, "2021-10-09 06:00"), "00:00", ("2021-01-01 06:00", "2021-10-09 06:00")), + ((None, "2021-10-09 06:00"), "06:00", ("2021-01-01 06:00", "2021-10-09 06:00")), + ], +) +def test_leftandright_onespecified_asstring( + tss: tuple, expected_tss: tuple, tz_param: str, starttime: str +): + """Test if start and end of interval are correctly calculated, if one is specified + as a timestamp.""" + # One specified, but as string. So tz parameter and start_of_day should be used. + # There should be no timezone errors and no swapping is necessary + start_of_day = {"06:00": dt.time(hour=6), "00:00": dt.time(hour=0), None: None}[ + starttime + ] + expected = [pd.Timestamp(ts, tz=tz_param) for ts in expected_tss] + result = tools.leftandright.stamps(*tss, tz_param, start_of_day) + + for a, b in zip(result, expected): + assert a == b + + @pytest.mark.parametrize("tz_param", [None, "Europe/Berlin", "Asia/Kolkata"]) @pytest.mark.parametrize( "tzs", diff --git a/tests/tools/test_stamp.py b/tests/tools/test_stamp.py new file mode 100644 index 0000000..40f8fda --- /dev/null +++ b/tests/tools/test_stamp.py @@ -0,0 +1,84 @@ +import datetime as dt +from typing import Any + +import pandas as pd +import pytest + +from portfolyo.tools import stamp + +ts_midnight = "2020-02-03" +ts_withtime = "2020-02-03 15:20" + + +@pytest.mark.parametrize( + "ts", + [ + pd.Timestamp(ts_withtime, tz=None), + pd.Timestamp(ts_withtime, tz="Europe/Berlin"), + pd.Timestamp(ts_midnight, tz=None), + pd.Timestamp(ts_midnight, tz="Europe/Berlin"), + ], +) +@pytest.mark.parametrize("tz", [None, "Europe/Berlin", "Asia/Kolkata"]) +@pytest.mark.parametrize("start_of_day", [None, dt.time(hour=6), dt.time(hour=0)]) +def test_create_nochange(ts: Any, tz: str, start_of_day: dt.time): + """Test if stamps that should remain unchanged, remain unchanged.""" + assert stamp.create(ts, tz, start_of_day) == ts + + +@pytest.mark.parametrize( + "ts,tz,start_of_day,expected", + [ + (ts_midnight, None, None, pd.Timestamp(ts_midnight, tz=None)), + ( + ts_withtime, + None, + None, + pd.Timestamp(ts_withtime, tz=None), + ), + ( + ts_midnight, + None, + dt.time(hour=6), + pd.Timestamp("2020-02-03 06:00", tz=None), + ), + ( + ts_withtime, + None, + dt.time(hour=6), + pd.Timestamp(ts_withtime, tz=None), + ), + ( + ts_midnight, + "Europe/Berlin", + None, + pd.Timestamp(ts_midnight, tz="Europe/Berlin"), + ), + ( + ts_withtime, + "Europe/Berlin", + None, + pd.Timestamp(ts_withtime, tz="Europe/Berlin"), + ), + ( + ts_midnight, + "Europe/Berlin", + dt.time(hour=6), + pd.Timestamp("2020-02-03 06:00", tz="Europe/Berlin"), + ), + ( + ts_withtime, + "Europe/Berlin", + dt.time(hour=6), + pd.Timestamp(ts_withtime, tz="Europe/Berlin"), + ), + ], +) +@pytest.mark.parametrize("instance", ["string", "datetime"]) +def test_create_string( + ts: Any, tz: str, start_of_day: dt.time, instance: str, expected: pd.Timestamp +): + """Test if timestamp is correctly created from a string.""" + if instance == "datetime": + ts = dt.datetime.fromisoformat(ts) + assert stamp.create(ts, tz, start_of_day) == expected diff --git a/tests/tools/test_standardize.py b/tests/tools/test_standardize.py index 14bfb2f..8e606bb 100644 --- a/tests/tools/test_standardize.py +++ b/tests/tools/test_standardize.py @@ -29,7 +29,7 @@ def test_standardize_DST( Using quarterhour and daily timeseries, without gaps.""" if not in_aware and in_tz != "Europe/Berlin": - return # cannot convert tz-naive fr to different timezone + pytest.skip("Cannot convert tz-naive fr to different timezone.") if freq == "D": in_vals_num = 200 diff --git a/tests/tools/test_wavg.py b/tests/tools/test_wavg.py index df14b60..2fe2e5d 100644 --- a/tests/tools/test_wavg.py +++ b/tests/tools/test_wavg.py @@ -1,3 +1,5 @@ +from typing import Any, Iterable, Union + import numpy as np import pandas as pd import pytest @@ -6,271 +8,372 @@ from portfolyo import tools -@pytest.mark.parametrize("weightsas", ["none", "list", "series"]) -@pytest.mark.parametrize("with_units", ["units", "nounits"]) -def test_wavg_valuesasseries1(weightsas: str, with_units: str): +def get_weights( + weights: Iterable[float], + weightsas: str, + index: Iterable = None, + units: bool = False, +): + """Get weights to test wavg with, if weightsas == 'none', 'list', 'dict', or 'series'.""" + # No weights. + if weightsas == "none": + if units: + pytest.skip("Cannot test weights == None with units.") + return None + # Weights as list, no index needed. + if weightsas == "list": + if units: + weights = [pf.Q_(w, "MWh") for w in weights] + return weights + # Weights include index value; make index if needed. + if index is None: + index = range(len(weights)) + weights = {i: w for w, i in zip(weights[::-1], index[::-1])} + if weightsas == "dict": + if units: + weights = {i: pf.Q_(w, "MWh") for i, w in weights.items()} + return weights + if weightsas == "series": + weights = pd.Series(weights) + if units: + weights = weights.astype("pint[MWh]") + return weights + + +def get_weights_df(weights: dict, index: Iterable, units: bool = False): + """Get weights to test wavg with, if weightsas == 'dataframe'.""" + weights = pd.DataFrame(weights, index) + if units: + weights = pd.DataFrame( + {c: s.astype("pint[Eur/MWh]") for c, s in weights.items()} + ) + return weights + + +def get_index(number: int, indextype: str) -> Iterable: + if indextype == "int": + return range(number) + return pd.date_range("2020", freq="D", periods=number) + + +def do_test_series( + values: Union[pd.Series, pd.DataFrame], weights: Any, expected: Any, **kwargs +): + if isinstance(expected, type) and issubclass(expected, Exception): + with pytest.raises(expected): + tools.wavg.series(values, weights) + return + pf.testing.assert_value_equal(tools.wavg.series(values, weights), expected) + + +def do_test_dataframe(values: pd.DataFrame, weights: Any, expected: Any, **kwargs): + if isinstance(expected, type) and issubclass(expected, Exception): + with pytest.raises(expected): + tools.wavg.dataframe(values, weights, **kwargs) + return + pf.testing.assert_series_equal( + tools.wavg.dataframe(values, weights, **kwargs), expected + ) + + +@pytest.mark.parametrize("weightsas", ["none", "list", "dict", "series"]) +@pytest.mark.parametrize("units", ["", "val", "wei", "val&wei"]) +@pytest.mark.parametrize("indextype", ["int", "DatetimeIndex"]) +def test_wavg_series(weightsas: str, units: str, indextype: str): """Test if weighted average of a series is correctly calculated.""" # Starting values. - values = pd.Series([100.0, 200, 300, -150]) - weights = [10, 10, 10, 20] + i = get_index(4, indextype) + values = pd.Series([100.0, 200, 300, -150], i) + weights = get_weights([10.0, 0, 10, 20], weightsas, i, "wei" in units) if weightsas == "none": - weights = None expected = 112.5 - elif weightsas == "list": - expected = 60.0 - elif weightsas == "series": - weights = pd.Series(weights, index=[3, 2, 1, 0]) # align by index - expected = 110.0 + else: + expected = 25.0 # Add units. - if with_units == "units": + if "val" in units: values = values.astype("pint[Eur/MWh]") expected = pf.Q_(expected, "Eur/MWh") # Test. - assert np.isclose(tools.wavg.series(values, weights), expected) + do_test_series(values, weights, expected) -@pytest.mark.parametrize("weightsas", ["list", "series"]) -@pytest.mark.parametrize("with_units", ["units", "nounits"]) -@pytest.mark.parametrize("indextype", [int, pd.DatetimeIndex]) -def test_wavg_valuesasseries2(weightsas: str, with_units: str, indextype: type): - """Test if weighted average of a series is correctly calculated.""" +@pytest.mark.parametrize("weightsas", ["list", "dict", "series"]) +@pytest.mark.parametrize("units", ["", "val", "wei", "val&wei"]) +@pytest.mark.parametrize("indextype", ["int", "DatetimeIndex"]) +def test_wavg_series_surplusvalues(weightsas: str, units: str, indextype: str): + """Test if weighted average of a series is correctly calculated if we have more + values and than weights.""" # Starting values. - i = range(4) if indextype is int else pd.date_range("2020", freq="D", periods=4) - values = pd.Series([100.0, 200, 300, -150], i) - weights = [10.0, 0, 10, 20] - if weightsas == "list": - expected = 25.0 - elif weightsas == "series": - weights = pd.Series(weights, [i[j] for j in [3, 2, 1, 0]]) # align by index - expected = 62.5 + i = get_index(5, indextype) + values = pd.Series([100.0, 200, 300, -150, 100], i) + weights = get_weights([10.0, 0, 10, 20], weightsas, i[:4], "wei" in units) + expected = 25.0 # Add units. - if with_units == "units": + if "val" in units: values = values.astype("pint[Eur/MWh]") expected = pf.Q_(expected, "Eur/MWh") + if weightsas == "list": + expected = ValueError # Test. - assert np.isclose(tools.wavg.series(values, weights), expected) + do_test_series(values, weights, expected) -@pytest.mark.parametrize("weightsas", ["list", "series"]) -@pytest.mark.parametrize("with_units", ["units", "nounits"]) -def test_wavg_valuesasseries_na(weightsas: str, with_units: str): +@pytest.mark.parametrize("weightsas", ["list", "dict", "series"]) +@pytest.mark.parametrize("units", ["", "val", "wei", "val&wei"]) +@pytest.mark.parametrize("indextype", ["int", "DatetimeIndex"]) +def test_wavg_series_surplusweights(weightsas: str, units: str, indextype: str): + """Test if error is correctly thrown if we have more weights than values.""" + # Starting values. + i = get_index(5, indextype) + values = pd.Series([100.0, 200, 300, -150], i[:4]) + weights = get_weights([10.0, 0, 10, 20, 10], weightsas, i, "wei" in units) + expected = ValueError + # Add units. + if "val" in units: + values = values.astype("pint[Eur/MWh]") + # Test. + do_test_series(values, weights, expected) + + +@pytest.mark.parametrize("weightsas", ["list", "dict", "series"]) +@pytest.mark.parametrize("units", ["", "val", "wei", "val&wei"]) +@pytest.mark.parametrize("indextype", ["int", "DatetimeIndex"]) +@pytest.mark.parametrize("zerovalues", ["allzero", "sumzero"]) +def test_wavg_series_0weights( + weightsas: str, units: str, indextype: str, zerovalues: str +): """Test if weighted average of a series is correctly identified as error, - when all weights are 0 but not all values are equal.""" + when sum of weights is 0 but not all values are equal.""" # Starting values. - values = pd.Series([100.0, 200, 300, -150]) - weights = [0.0, 0, 0, 0] - if weightsas == "series": - weights = pd.Series(weights, index=[3, 2, 1, 0]) # align by index + i = get_index(4, indextype) + values = pd.Series([100.0, 200, 300, -150], i) + weightvalues = [0.0, 0, 0, 0] if zerovalues == "allzero" else [-10.0, 10, 0, 0] + weights = get_weights(weightvalues, weightsas, i, "wei" in units) + expected = np.nan # Add units. - if with_units == "units": + if "val" in units: values = values.astype("pint[Eur/MWh]") - if weightsas == "series": - weights = weights.astype("pint[MWh]") # Test. - assert np.isnan(tools.wavg.series(values, weights)) + do_test_series(values, weights, expected) -@pytest.mark.parametrize("weightsas", ["list", "series"]) -@pytest.mark.parametrize("with_units", ["units", "nounits"]) -def test_wavg_0weight_navalues(weightsas: str, with_units: str): - """Test if weighted average of a series is correctly calculated, when some weights - are 0 but they have na-values.""" +@pytest.mark.parametrize("weightsas", ["list", "dict", "series"]) +@pytest.mark.parametrize("units", ["", "val", "wei", "val&wei"]) +@pytest.mark.parametrize("indextype", ["int", "DatetimeIndex"]) +@pytest.mark.parametrize("zerovalues", ["allzero", "sumzero"]) +def test_wavg_onevalseries_0weights( + weightsas: str, units: str, indextype: str, zerovalues: str +): + """Test if weighted average of a series is correctly calculated, + when sum of weights is 0 and all values are equal.""" # Starting values. - values = pd.Series([100.0, 200, np.nan, -150]) - weights = [10.0, 0, 0, 0] - if weightsas == "list": - expected = 100.0 - elif weightsas == "series": - weights = pd.Series(weights, index=[3, 2, 1, 0]) # align by index - expected = -150.0 + i = get_index(4, indextype) + values = pd.Series([100.0, 100, 100, 100], i) + weightvalues = [0.0, 0, 0, 0] if zerovalues == "allzero" else [-10.0, 10, 0, 0] + weights = get_weights(weightvalues, weightsas, i, "wei" in units) + expected = 100.0 # Add units. - if with_units == "units": + if "val" in units: values = values.astype("pint[Eur/MWh]") expected = pf.Q_(expected, "Eur/MWh") - if weightsas == "series": - weights = weights.astype("pint[MWh]") - else: - weights = [pf.Q_(w, "MWh") for w in weights] + if zerovalues == "allzero": + expected = np.nan # Test. - assert np.isclose(tools.wavg.series(values, weights), expected) + do_test_series(values, weights, expected) -@pytest.mark.parametrize("weightsas", ["list", "series"]) -@pytest.mark.parametrize("with_units", ["units", "nounits"]) -def test_wavg_valuesasseries_0weights(weightsas: str, with_units: str): - """Test if weighted average of a series is correctly calculated, - when all weights are 0 and all values are equal.""" +@pytest.mark.parametrize("weightsas", ["list", "dict", "series"]) +@pytest.mark.parametrize("units", ["", "val", "wei", "val&wei"]) +@pytest.mark.parametrize("indextype", ["int", "DatetimeIndex"]) +def test_wavg_naseries_0weights(weightsas: str, units: str, indextype: str): + """Test if weighted average of a series is correctly calculated, when some weights + are 0 but they have na-values.""" # Starting values. - values = pd.Series([100.0, 100, 100, 100]) - weights = [0.0, 0, 0, 0] + i = get_index(4, indextype) + values = pd.Series([100.0, 200, np.nan, -150], i) + weights = get_weights([10.0, 0, 0, 0], weightsas, i, "wei" in units) expected = 100.0 - if weightsas == "series": - weights = pd.Series(weights, index=[3, 2, 1, 0]) # align by index # Add units. - if with_units == "units": + if "val" in units: values = values.astype("pint[Eur/MWh]") expected = pf.Q_(expected, "Eur/MWh") - if weightsas == "series": - weights = weights.astype("pint[MWh]") # Test. - assert tools.wavg.series(values, weights) == expected + do_test_series(values, weights, expected) -@pytest.mark.parametrize("weightsas", ["none", "list", "series", "dataframe"]) +@pytest.mark.parametrize("weightsas", ["none", "list", "dict", "series", "dataframe"]) +@pytest.mark.parametrize("units", ["", "val", "wei", "val&wei"]) +@pytest.mark.parametrize("indextype", ["int", "DatetimeIndex"]) @pytest.mark.parametrize("axis", [0, 1]) -def test_wavg_valuesasdataframe1(weightsas: str, axis: int): +def test_wavg_dataframe(weightsas: str, axis: int, units: str, indextype: str): """Test if weighted average of a dataframe is correctly calculated.""" # Starting values. - series_a = pd.Series([100.0, 200, 300, -150]) - series_b = pd.Series([100.0, -200, 300, -150]) + i = get_index(4, indextype) + series_a = pd.Series([100.0, 200, 300, -150], i) + series_b = pd.Series([100.0, -200, 300, -150], i) values = pd.DataFrame({"a": series_a, "b": series_b}) - if weightsas == "none": - weights = None + + if weightsas != "dataframe": if axis == 0: - expected = pd.Series({"a": 112.5, "b": 12.5}) + weights = get_weights([10.0, 10, 10, 20], weightsas, i, "wei" in units) + if weightsas == "none": + expected = pd.Series({"a": 112.5, "b": 12.5}) + else: + expected = pd.Series({"a": 60.0, "b": -20}) else: - expected = pd.Series([100.0, 0, 300, -150]) - if weightsas == "list": + weights = get_weights([10.0, 30], weightsas, ["a", "b"], "wei" in units) + if weightsas == "none": + expected = pd.Series([100.0, 0, 300, -150], i) + else: + expected = pd.Series([100.0, -100, 300, -150], i) + else: + weights = get_weights_df( + {"a": [10.0, 10, 10, 20], "b": [10.0, 10, 30, 0]}, i, "wei" in units + ) if axis == 0: - weights = [10.0, 10, 10, 20] - expected = pd.Series({"a": 60.0, "b": -20}) + expected = pd.Series({"a": 60.0, "b": 160}) else: - weights = [10.0, 30] - expected = pd.Series([100.0, -100, 300, -150]) - if weightsas == "series": + expected = pd.Series([100.0, 0, 300, -150], i) + if "val" in units: + values = pd.DataFrame({c: s.astype("pint[Eur/MWh]") for c, s in values.items()}) + expected = expected.astype("pint[Eur/MWh]") + # Test. + do_test_dataframe(values, weights, expected, axis=axis) + + +@pytest.mark.parametrize("weightsas", ["list", "dict", "series", "dataframe"]) +@pytest.mark.parametrize("units", ["", "val", "wei", "val&wei"]) +@pytest.mark.parametrize("indextype", ["int", "DatetimeIndex"]) +@pytest.mark.parametrize("axis", [0, 1]) +def test_wavg_dataframe_surplusvalues( + weightsas: str, axis: int, units: str, indextype: str +): + """Test if weighted average of a dataframe is correctly calculated if we have more + values than weights.""" + # Starting values. + i = get_index(5, indextype) + series_a = pd.Series([100.0, 200, 300, -150, 99], i) + series_b = pd.Series([100.0, -200, 300, -150, 99], i) + series_c = pd.Series([99.0, -99, 99, -99, 99], i) + values = pd.DataFrame({"a": series_a, "b": series_b, "c": series_c}) + + if weightsas != "dataframe": if axis == 0: - weights = pd.Series([10.0, 10, 10, 20], index=[3, 2, 1, 0]) - expected = pd.Series({"a": 110.0, "b": 30}) + weights = get_weights([10.0, 10, 10, 20], weightsas, i[:4], "wei" in units) + expected = pd.Series({"a": 60.0, "b": -20, "c": -19.8}) else: - weights = pd.Series({"b": 30.0, "a": 10}) - expected = pd.Series([100.0, -100, 300, -150]) - if weightsas == "dataframe": - weights = pd.DataFrame({"a": [10.0, 10, 10, 20], "b": [10.0, 10, 30, 0]}) + weights = get_weights([10.0, 30], weightsas, ["a", "b"], "wei" in units) + expected = pd.Series([100.0, -100, 300, -150, 99], i) + else: + weights = get_weights_df( + {"a": [10.0, 10, 10, 20], "b": [10.0, 10, 30, 0]}, i[:4], "wei" in units + ) if axis == 0: expected = pd.Series({"a": 60.0, "b": 160}) else: - expected = pd.Series([100.0, 0, 300, -150]) + expected = pd.Series([100.0, 0, 300, -150], i[:4]) + if "val" in units: + values = pd.DataFrame({c: s.astype("pint[Eur/MWh]") for c, s in values.items()}) + expected = expected.astype("pint[Eur/MWh]") + if weightsas == "list": + expected = ValueError # Test. - result = tools.wavg.dataframe(values, weights, axis) - pd.testing.assert_series_equal(result, expected) + do_test_dataframe(values, weights, expected, axis=axis) -@pytest.mark.parametrize("weightsas", ["none", "list", "series", "dataframe"]) +@pytest.mark.parametrize("weightsas", ["list", "dict", "series", "dataframe"]) +@pytest.mark.parametrize("units", ["", "val", "wei", "val&wei"]) +@pytest.mark.parametrize("indextype", ["int", "DatetimeIndex"]) @pytest.mark.parametrize("axis", [0, 1]) -@pytest.mark.parametrize("same_units", [True, False]) -@pytest.mark.parametrize("weights_units", [True, False]) -def test_wavg_valuesasdataframe_units( - weightsas: str, axis: int, same_units: bool, weights_units: bool +def test_wavg_dataframe_surplusweights( + weightsas: str, axis: int, units: str, indextype: str ): - """Test if weighted average of a dataframe is correctly calculated if it has units. - Test with float weights and weights that have a unit.""" + """Test if error is correctly thrown if we have more weights than values.""" # Starting values. - series_a = pd.Series([100.0, 200, 300, -150]).astype("pint[Eur/MWh]") - unit_b = "Eur/MWh" if same_units else "MW" - series_b = pd.Series([100.0, -200, 300, -150]).astype(f"pint[{unit_b}]") + i = get_index(5, indextype) + series_a = pd.Series([100.0, 200, 300, -150], i[:4]) + series_b = pd.Series([100.0, -200, 300, -150], i[:4]) values = pd.DataFrame({"a": series_a, "b": series_b}) - # Filter non-tests. - if weights_units and weightsas in ["none", "list"]: - pytest.skip(f"If weights is {weightsas}, it cannot have a unit.") - - # Weights and exected results for 'non-error' cases (= not (axis == 1 and same_units) ). - if axis == 0: - - def exp_res(val_a, val_b): - if same_units: - return pd.Series({"a": val_a, "b": val_b}, dtype="pint[Eur/MWh]") - return pd.Series({"a": pf.Q_(val_a, "Eur/MWh"), "b": pf.Q_(val_b, unit_b)}) - - if weightsas == "none": - weights = None - expected = exp_res(112.5, 12.5) - elif weightsas == "list": - weights = [10.0, 10, 10, 20] - expected = exp_res(60.0, -20.0) - elif weightsas == "series": - weights = pd.Series([10.0, 10, 10, 20], index=[3, 2, 1, 0]) - if weights_units: - weights = weights.astype("pint[h]") # any unit will do - expected = exp_res(110.0, 30.0) - elif weightsas == "dataframe": - weights = pd.DataFrame({"a": [10.0, 10, 10, 20], "b": [10.0, 10, 30, 0]}) - if weights_units: - weights = pd.DataFrame( - {c: s.astype("pint[h]") for c, s in weights.items()} - ) - expected = exp_res(60.0, 160.0) - - else: # axis == 1 - if weightsas == "none": - weights = None - expected = pd.Series([100.0, 0, 300, -150]).astype("pint[Eur/MWh]") - elif weightsas == "list": - weights = [10.0, 30] - expected = pd.Series([100.0, -100, 300, -150]).astype("pint[Eur/MWh]") - elif weightsas == "series": - weights = pd.Series({"b": 30.0, "a": 10.0}) - if weights_units: - weights = weights.astype("pint[h]") - expected = pd.Series([100.0, -100, 300, -150]).astype("pint[Eur/MWh]") - elif weightsas == "dataframe": - weights = pd.DataFrame({"a": [10.0, 10, 10, 20], "b": [10.0, 10, 30, 0]}) - if weights_units: - weights = pd.DataFrame( - {c: s.astype("pint[h]") for c, s in weights.items()} - ) - expected = pd.Series([100.0, 0, 300, -150]).astype("pint[Eur/MWh]") - + if weightsas != "dataframe": + if axis == 0: + weights = get_weights([10.0, 10, 10, 20, 9], weightsas, i, "wei" in units) + else: + weights = get_weights( + [10.0, 30, 9], weightsas, ["a", "b", "c"], "wei" in units + ) + else: + weights = get_weights_df( + {"a": [10.0, 10, 10, 20, 9], "b": [10.0, 10, 30, 0, 9]}, i, "wei" in units + ) + if "val" in units: + values = pd.DataFrame({c: s.astype("pint[Eur/MWh]") for c, s in values.items()}) # Test. - if axis == 1 and not same_units: # error cases - with pytest.raises(Exception): - tools.wavg.dataframe(values, weights, axis) - return - result = tools.wavg.dataframe(values, weights, axis) - pd.testing.assert_series_equal(result, expected) + do_test_dataframe(values, weights, ValueError, axis=axis) -@pytest.mark.parametrize("weightsas", ["list", "series", "dataframe"]) -@pytest.mark.parametrize("indextype", [int, pd.DatetimeIndex]) +@pytest.mark.parametrize("weightsas", ["none", "list", "series", "dataframe"]) @pytest.mark.parametrize("axis", [0, 1]) -def test_wavg_valuesasdataframe2(weightsas: str, axis: int, indextype: type): - """Test if weighted average of a dataframe is correctly calculated.""" +@pytest.mark.parametrize("compatible", ["compatible", "incompatible"]) +@pytest.mark.parametrize("units", ["val", "val&wei"]) +@pytest.mark.parametrize("indextype", ["int", "DatetimeIndex"]) +def test_wavg_dataframe_distinctunits( + weightsas: str, axis: int, compatible: str, units: str, indextype: str +): + """Test if weighted average of a dataframe is correctly calculated if it has a mix + of units.""" # Starting values. - i = range(4) if indextype is int else pd.date_range("2020", freq="D", periods=4) - values = pd.DataFrame({"a": [100, 200, 200, -150], "b": [100, -200, 300, -150]}, i) - if weightsas == "list": - if axis == 0: - weights = [10, 10, 0, 20] - expected = pd.Series({"a": 0.0, "b": -100}) - else: - weights = [10, 0] - expected = pd.Series([100.0, 200, 200, -150], i) - elif weightsas == "series": + i = get_index(4, indextype) + series_a = pd.Series([100.0, 200, 300, -150], i).astype("pint[Eur/MWh]") + if compatible == "compatible": + series_b = pd.Series([10.0, -20, 30, -15], i).astype("pint[ctEur/kWh]") + else: + series_b = pd.Series([100.0, -200, 300, -150], i).astype("pint[MW]") + values = pd.DataFrame({"a": series_a, "b": series_b}) + + def exp_res(val_a, val_b): + if compatible == "compatible": + return pd.Series({"a": val_a, "b": val_b}, dtype="pint[Eur/MWh]") + return pd.Series({"a": pf.Q_(val_a, "Eur/MWh"), "b": pf.Q_(val_b, "MW")}) + + if weightsas != "dataframe": if axis == 0: - weights = pd.Series([10, 10, 0, 20], [i[j] for j in [3, 2, 1, 0]]) - expected = pd.Series({"a": 62.5, "b": 87.5}) + weights = get_weights([10.0, 10, 10, 20], weightsas, i, "wei" in units) + if weightsas == "none": + expected = exp_res(112.5, 12.5) + else: + expected = exp_res(60.0, -20.0) else: - weights = pd.Series({"b": 0, "a": 10}) - expected = pd.Series([100.0, 200, 200, -150], i) - elif weightsas == "dataframe": - weights = pd.DataFrame({"a": [10, 10, 0, 20], "b": [10, 10, 30, 0]}, i) + weights = get_weights([10.0, 30], weightsas, ["a", "b"], "wei" in units) + if weightsas == "none": + expected = pd.Series([100.0, 0, 300, -150], i).astype("pint[Eur/MWh]") + else: + expected = pd.Series([100.0, -100, 300, -150], i).astype( + "pint[Eur/MWh]" + ) + else: + weights = get_weights_df( + {"a": [10.0, 10, 10, 20], "b": [10.0, 10, 30, 0]}, i, "wei" in units + ) if axis == 0: - expected = pd.Series({"a": 0.0, "b": 160}) + expected = exp_res(60.0, 160.0) else: - expected = pd.Series([100.0, 0, 300, -150], i) + expected = pd.Series([100.0, 0, 300, -150], i).astype("pint[Eur/MWh]") + # Test. - result = tools.wavg.dataframe(values, weights, axis) - pd.testing.assert_series_equal(result, expected) + if axis == 1 and compatible != "compatible": # error cases + expected = Exception + do_test_dataframe(values, weights, expected, axis=axis) @pytest.mark.parametrize("weightsas", ["list", "series", "dataframe"]) -@pytest.mark.parametrize("indextype", [int, pd.DatetimeIndex]) +@pytest.mark.parametrize("indextype", ["int", "DatetimeIndex"]) @pytest.mark.parametrize("axis", [0, 1]) -def test_wavg_valuesasdataframe_na(weightsas: str, axis: int, indextype: type): - """Test if weighted average of a dataframe is correctly is correctly identified as error, +def test_wavg_dataframe_na(weightsas: str, axis: int, indextype: str): + """Test if weighted average of a dataframe is correctly identified as error, when all weights are 0 but not all values are equal.""" # Starting values. - i = range(4) if indextype is int else pd.date_range("2020", freq="D", periods=4) + i = get_index(4, indextype) values = pd.DataFrame({"a": [130, 200, 200, -160], "b": [100, -200, 300, -150]}, i) if axis == 0: weights = [0, 0, 0, 0] @@ -287,32 +390,63 @@ def test_wavg_valuesasdataframe_na(weightsas: str, axis: int, indextype: type): elif weightsas == "dataframe": weights = pd.DataFrame({"a": [0, 0, 0, 0], "b": [0, 0, 0, 0]}, i) # Test. - result = tools.wavg.dataframe(values, weights, axis) - pd.testing.assert_series_equal(result, expected, check_dtype=False) + do_test_dataframe(values, weights, expected, axis=axis) @pytest.mark.parametrize("weightsas", ["list", "series", "dataframe"]) @pytest.mark.parametrize("axis", [0, 1]) -def test_wavg_valuesasdataframe_0weights(weightsas: str, axis: int): - """Test if weighted average of a dataframe is correctly is correctly identified as error, - when all weights are 0. Some averages are calculated from identical values and should +@pytest.mark.parametrize("zerovalues", ["allzero", "sumzero"]) +@pytest.mark.parametrize("indextype", ["int", "DatetimeIndex"]) +@pytest.mark.parametrize("units", ["", "val", "wei", "val&wei"]) +def test_wavg_dataframe_0weights( + weightsas: str, axis: int, units: str, zerovalues: str, indextype: str +): + """Test if weighted average of a dataframe is correctly identified as error, + when sum of weights is 0. Some averages are calculated from identical values and should result in that value.""" # Starting values. - values = pd.DataFrame({"a": [100, 200, 200, -150], "b": [100, -200, 300, -150]}) - if axis == 0: - weights = [0, 0, 0, 0] - expected = pd.Series({"a": np.nan, "b": np.nan}) + i = get_index(4, indextype) + values = pd.DataFrame( + { + "a": [100.0, 200, 150, 100], + "b": [100.0, 100, 100, 100], + "c": [100.0, 100, 200, 250], + }, + i, + ) + if weightsas != "dataframe": + if axis == 0: + if zerovalues == "allzero": + weightvalues = [0.0, 0, 0, 0] + expectedvalues = [np.nan, 100.0, np.NaN] + else: + weightvalues = [-10.0, 10, 0, 0] + expectedvalues = [np.nan, 100.0, 100] + weights = get_weights(weightvalues, weightsas, i, "wei" in units) + expected = pd.Series(expectedvalues, list("abc")) + else: + if zerovalues == "allzero": + weightvalues = [0.0, 0, 0] + expectedvalues = [100.0, np.nan, np.nan, np.nan] + else: + weightvalues = [-10.0, 10, 0] + expectedvalues = [100.0, np.nan, np.nan, 100.0] + weights = get_weights(weightvalues, weightsas, list("abc"), "wei" in units) + expected = pd.Series(expectedvalues, i) else: - weights = [0, 0] - expected = pd.Series([100, np.nan, np.nan, -150]) - - if weightsas == "series": + if zerovalues == "allzero": + pytest.skip("Testing both zero cases together.") + weights = get_weights_df( + {"a": [10.0, 0, 0, -10], "b": [0.0, 0, 0, 0], "c": [-10, 0, 0, 10]}, + i, + "wei" in units, + ) if axis == 0: - weights = pd.Series(weights, [3, 2, 1, 0]) + expected = pd.Series([100.0, 100, np.nan], list("abc")) else: - weights = pd.Series(weights, ["a", "b"]) - if weightsas == "dataframe": - weights = pd.DataFrame({"a": [0, 0, 0, 0], "b": [0, 0, 0, 0]}) + expected = pd.Series([100.0, np.nan, np.nan, np.nan], i) + if "val" in units: + values = pd.DataFrame({c: s.astype("pint[Eur/MWh]") for c, s in values.items()}) + expected = expected.astype("pint[Eur/MWh]") # Test. - result = tools.wavg.dataframe(values, weights, axis) - pd.testing.assert_series_equal(result, expected, check_dtype=False) + do_test_dataframe(values, weights, expected, axis=axis) From 3ed3974f5ce10fd8130856bc5209bbcb5994c758 Mon Sep 17 00:00:00 2001 From: rwijtvliet Date: Sun, 26 May 2024 13:49:37 +0200 Subject: [PATCH 2/2] Portfolyo Release 0.6.0 --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 4b7593d..d74774d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "portfolyo" -version = "0.5.10" +version = "0.6.0" description = "Analyse and manipulate timeseries related to power and gas offtake portfolios" authors = [ "Ruud Wijtvliet ",