|
11 | 11 |
|
12 | 12 | from pandas_openscm.exceptions import MissingOptionalDependencyError |
13 | 13 | from pandas_openscm.index_manipulation import set_index_levels_func |
14 | | -from pandas_openscm.indexing import multi_index_match |
| 14 | +from pandas_openscm.indexing import multi_index_lookup, multi_index_match |
15 | 15 |
|
16 | 16 | if TYPE_CHECKING: |
17 | 17 | import pint |
@@ -50,35 +50,51 @@ def convert_unit( |
50 | 50 | ).T |
51 | 51 |
|
52 | 52 | elif isinstance(desired_unit, pd.Series): |
| 53 | + # Don't do this, |
| 54 | + # just split out a function which takes in a Series of target_units |
| 55 | + # (and do direct passthrough if the user supplies a Series) |
53 | 56 | raise NotImplementedError |
54 | 57 | # Assume that desired_unit is already the target units |
55 | 58 | unit_map = pd.DataFrame([*desired_unit.align(df_units_s)]).T |
56 | 59 |
|
57 | 60 | else: |
58 | 61 | raise NotImplementedError(type(desired_unit)) |
59 | 62 |
|
60 | | - if (unit_map["df_unit"] == unit_map["target_unit"]).all(): |
61 | | - # Already in matching units |
| 63 | + unit_map_no_change = unit_map["df_unit"] == unit_map["target_unit"] |
| 64 | + if unit_map_no_change.all(): |
| 65 | + # Already all in desired unit |
62 | 66 | return df |
63 | 67 |
|
64 | | - df_converted = df.reset_index(unit_level, drop=True) |
65 | | - for (df_unit, target_unit), conversion_df in unit_map.groupby( |
| 68 | + df_no_unit = df.reset_index(unit_level, drop=True) |
| 69 | + |
| 70 | + for (df_unit, target_unit), conversion_df in unit_map[~unit_map_no_change].groupby( |
66 | 71 | ["df_unit", "target_unit"] |
67 | 72 | ): |
68 | | - to_alter_loc = multi_index_match(df_converted.index, conversion_df.index) # type: ignore |
69 | | - df_converted.loc[to_alter_loc, :] = ( |
70 | | - ur.Quantity(df_converted.loc[to_alter_loc, :].values, df_unit) |
| 73 | + to_alter_loc = multi_index_match(df_no_unit.index, conversion_df.index) # type: ignore |
| 74 | + df_no_unit.loc[to_alter_loc, :] = ( |
| 75 | + ur.Quantity(df_no_unit.loc[to_alter_loc, :].values, df_unit) |
71 | 76 | .to(target_unit) |
72 | 77 | .m |
73 | 78 | ) |
74 | 79 |
|
75 | | - # All conversions done so can simply assign the unit column. |
76 | | - unit_map_reordered = unit_map.reorder_levels(df_converted.index.names) |
77 | | - res = set_index_levels_func( |
78 | | - df_converted, |
79 | | - # use `.loc` to ensure that the values line up with the converted result |
80 | | - {unit_level: unit_map_reordered["target_unit"].loc[df_converted.index]}, |
81 | | - ).reorder_levels(df.index.names) |
| 80 | + missing_from_unit_map = df_no_unit.index.difference(unit_map.index) |
| 81 | + if not missing_from_unit_map.empty: |
| 82 | + missing_from_unit_map_df = ( |
| 83 | + multi_index_lookup(df, missing_from_unit_map) |
| 84 | + .index.to_frame()[[unit_level]] |
| 85 | + .rename({unit_level: "df_unit"}, axis="columns") |
| 86 | + ) |
| 87 | + missing_from_unit_map_df["target_unit"] = missing_from_unit_map_df["df_unit"] |
| 88 | + |
| 89 | + unit_map = pd.concat([unit_map, missing_from_unit_map_df]) |
| 90 | + |
| 91 | + new_units = (unit_map.reorder_levels(df_no_unit.index.names).loc[df_no_unit.index])[ |
| 92 | + "target_unit" |
| 93 | + ] |
| 94 | + |
| 95 | + res = set_index_levels_func(df_no_unit, {unit_level: new_units}).reorder_levels( |
| 96 | + df.index.names |
| 97 | + ) |
82 | 98 |
|
83 | 99 | return res |
84 | 100 |
|
|
0 commit comments