From d2fde27046c14920791088d285d12f4ce5443e74 Mon Sep 17 00:00:00 2001 From: jernejfrank Date: Sun, 24 Nov 2024 10:56:56 +0800 Subject: [PATCH 1/6] Enable extract_columns for Polar LazyFrame Adds column type to be pl.Expr and allows using extract_columns with Polars LazyFrame. The collect() is left to the user. --- hamilton/plugins/polars_extensions.py | 2 +- .../plugins/polars_lazyframe_extensions.py | 23 +++++++++++++++++-- .../plugins/polars_pre_1_0_0_extension.py | 2 +- 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/hamilton/plugins/polars_extensions.py b/hamilton/plugins/polars_extensions.py index 7fe500c7d..2c8b9d5c7 100644 --- a/hamilton/plugins/polars_extensions.py +++ b/hamilton/plugins/polars_extensions.py @@ -48,7 +48,7 @@ def get_column_polars(df: pl.DataFrame, column_name: str) -> pl.Series: def fill_with_scalar_polars(df: pl.DataFrame, column_name: str, scalar_value: Any) -> pl.DataFrame: if not isinstance(scalar_value, pl.Series): scalar_value = [scalar_value] - return df.with_column(pl.Series(name=column_name, values=scalar_value)) + return df.with_columns(pl.Series(name=column_name, values=scalar_value)) register_types() diff --git a/hamilton/plugins/polars_lazyframe_extensions.py b/hamilton/plugins/polars_lazyframe_extensions.py index 6130dfce8..29a82396a 100644 --- a/hamilton/plugins/polars_lazyframe_extensions.py +++ b/hamilton/plugins/polars_lazyframe_extensions.py @@ -41,8 +41,8 @@ from hamilton.io.data_adapters import DataLoader DATAFRAME_TYPE = pl.LazyFrame -COLUMN_TYPE = None -COLUMN_FRIENDLY_DF_TYPE = False +COLUMN_TYPE = pl.Expr +# COLUMN_FRIENDLY_DF_TYPE = False def register_types(): @@ -50,6 +50,25 @@ def register_types(): registry.register_types("polars_lazyframe", DATAFRAME_TYPE, COLUMN_TYPE) +@registry.get_column.register(pl.LazyFrame) +def get_column_polars_lazyframe(df: pl.LazyFrame, column_name: str) -> pl.Expr: + # TODO: figure out if we can validate this here already or need to wait to the end + # when query.collect() resolves the lazy frame + # df.collect_schema().names() gives a list of names but it can be expensive + # https://docs.pola.rs/api/python/stable/reference/lazyframe/api/polars.LazyFrame.columns.html + # https://docs.pola.rs/api/python/stable/reference/lazyframe/api/polars.LazyFrame.collect_schema.html#polars.LazyFrame.collect_schema + return pl.col(column_name) + + +@registry.fill_with_scalar.register(pl.LazyFrame) +def fill_with_scalar_polars_lazyframe( + df: pl.LazyFrame, column_name: str, scalar_value: Any +) -> pl.LazyFrame: + if not isinstance(scalar_value, pl.Expr): + scalar_value = pl.lit(scalar_value) + return df.with_columns(scalar_value.alias(column_name)) + + register_types() diff --git a/hamilton/plugins/polars_pre_1_0_0_extension.py b/hamilton/plugins/polars_pre_1_0_0_extension.py index 39b75c262..3814f0fe1 100644 --- a/hamilton/plugins/polars_pre_1_0_0_extension.py +++ b/hamilton/plugins/polars_pre_1_0_0_extension.py @@ -64,7 +64,7 @@ def get_column_polars(df: pl.DataFrame, column_name: str) -> pl.Series: def fill_with_scalar_polars(df: pl.DataFrame, column_name: str, scalar_value: Any) -> pl.DataFrame: if not isinstance(scalar_value, pl.Series): scalar_value = [scalar_value] - return df.with_column(pl.Series(name=column_name, values=scalar_value)) + return df.with_columns(pl.Series(name=column_name, values=scalar_value)) @dataclasses.dataclass From 6dd4ac191f1646afca40e02e74b5872d578f3a0f Mon Sep 17 00:00:00 2001 From: jernejfrank Date: Sun, 24 Nov 2024 11:02:20 +0800 Subject: [PATCH 2/6] Add with_columns_base Adds base class to use for implementing with_columns that si dataframe library specific. See README for design choices. --- hamilton/function_modifiers/README | 19 ++ hamilton/function_modifiers/recursive.py | 227 ++++++++++++++++++++- tests/function_modifiers/test_recursive.py | 16 +- 3 files changed, 259 insertions(+), 3 deletions(-) create mode 100644 hamilton/function_modifiers/README diff --git a/hamilton/function_modifiers/README b/hamilton/function_modifiers/README new file mode 100644 index 000000000..30cb9607b --- /dev/null +++ b/hamilton/function_modifiers/README @@ -0,0 +1,19 @@ +# with_columns_base + +Documenting the current design flow for the `with_columns` decorator. It belongs to the `NodeInjector` lifecycle. + +The `with_columns` consists of three parts that are represented in the corresponding three abstract methods in `with_columns_base`: + +1. `get_initial_nodes` -- Input node(s): Either a dataframe if `pass_datafame_as` is used or extracted columns into nodes if `columns_to_pass` and is library specific. +2. `get_subdag_nodes` -- Subdag nodes: Creating the `subdag` is outsourced to `recursive.subdag`, left flexibility to pre- and post-process since some libraries need that (see h_spark). +3. `chain_subdag_nodes` -- Merge node: The append functionality between dataframe and selected columns is library specific. + +Each plugin library that can implement `with_columns` should subclass from this base class and implement the three abstract methods (four since `validate()` is also abstract). The child +classes need to override the `init` where they call out to the parent `init` and pass in `dataframe_type` which is registered in the corresponding `extensions` and has information of what +columns types are permitted for the given dataframe type. + +Keeping it for now loosely coupled to the `registry` and detached from `ResultBuilder`. The API is private, should we want to switch to `registry`, the refactoring is straightforward and shouldn't get us into trouble down the road. + +## NOTE +The handling of scalars and dataframe types varies between library to library. We made the decision that such a thing should not be permissible, so all the selected columns that want to be +appended to the original dataframe need to have the matching column type that is registered in the `registry` and set in the library extension modules. diff --git a/hamilton/function_modifiers/recursive.py b/hamilton/function_modifiers/recursive.py index 744d222e2..a330714a9 100644 --- a/hamilton/function_modifiers/recursive.py +++ b/hamilton/function_modifiers/recursive.py @@ -1,5 +1,8 @@ +import abc import inspect import sys +import typing +from collections import defaultdict from types import ModuleType from typing import Any, Callable, Collection, Dict, List, Optional, Tuple, Type, TypedDict, Union @@ -11,7 +14,6 @@ else: from typing import NotRequired - # Copied this over from function_graph # TODO -- determine the best place to put this code from hamilton import graph_utils, node @@ -624,5 +626,226 @@ def prune_nodes(nodes: List[node.Node], select: Optional[List[str]] = None) -> L if dep not in seen_nodes and dep in node_name_map: dep_node = node_name_map[dep] stack.append(dep_node) - seen_nodes.add(dep) + seen_nodes.add(dep) + + if not set(select) <= set([node_.name for node_ in output]): + raise ValueError( + "At least one of the selected nodes is not not in the DAG. " + f"You selected: {select}, but we only found nodes: {nodes}." + ) return output + + +def _default_inject_parameter(fn: Callable, target_dataframe: str = None) -> str: + if target_dataframe is not None: + inject_parameter = target_dataframe + else: + # If we don't have a specified dataframe we assume it's the first argument + function_parameters = list(inspect.signature(fn).parameters.values()) + if function_parameters: + inject_parameter = function_parameters[0].name + else: + raise ValueError( + f"Function {fn.__qualname__} has no parameters, but was " + f"decorated with with_columns. with_columns requires the first " + f"parameter to be a dataframe or using the on_input argument." + ) + return inject_parameter + + +class with_columns_base(base.NodeInjector, abc.ABC): + """Factory for with_columns operation on a dataframe. This is used when you want to extract some + columns out of the dataframe, perform operations on them and then append to the original dataframe. + + This is an internal class that is meant to be extended by each individual dataframe library implementing + the following abstract methods: + + - get_initial_nodes + - get_subdag_nodes + - chain_subdag_nodes + - validate + """ + + # TODO: if we rename the column nodes into something smarter this can be avoided and + # can also modify columns in place + @staticmethod + def contains_duplicates(nodes_: List[node.Node]) -> bool: + """Ensures that we don't run into name clashing of columns and group operations. + + In the case when we extract columns for the user, because ``columns_to_pass`` was used, we want + to safeguard against nameclashing with functions that are passed into ``with_columns`` - i.e. + there are no functions that have the same name as the columns. This effectively means that + using ``columns_to_pass`` will only append new columns to the dataframe and for changing + existing columns ``pass_dataframe_as`` or ``on_input`` needs to be used. + """ + node_counter = defaultdict(int) + for node_ in nodes_: + node_counter[node_.name] += 1 + if node_counter[node_.name] > 1: + return True + return False + + @staticmethod + def validate_dataframe( + fn: Callable, inject_parameter: str, params: Dict[str, Type[Type]], required_type: Type + ) -> None: + input_types = typing.get_type_hints(fn) + if inject_parameter not in params: + raise InvalidDecoratorException( + f"Function: {fn.__name__} does not have the parameter {inject_parameter} as a dependency. " + f"@with_columns requires the parameter names to match the function parameters. " + f"If you wish do not wish to use the first argument, please use ``pass_dataframe_as`` or ``on_input`` option. " + f"It might not be compatible with some other decorators." + ) + + if isinstance(input_types[inject_parameter], required_type): + raise InvalidDecoratorException( + "The selected dataframe parameter is not the correct dataframe type. " + f"You selected a parameter of type {input_types[inject_parameter]}, but we expect to get {required_type}" + ) + + def __init__( + self, + *load_from: Union[Callable, ModuleType], + columns_to_pass: List[str] = None, + pass_dataframe_as: str = None, + on_input: str = None, + select: List[str] = None, + namespace: str = None, + config_required: List[str] = None, + dataframe_type: Type = None, + ): + """Instantiates a ``@with_columns`` decorator. + + :param load_from: The functions or modules that will be used to generate the group of map operations. + :param columns_to_pass: The initial schema of the dataframe. This is used to determine which + upstream inputs should be taken from the dataframe, and which shouldn't. Note that, if this is + left empty (and external_inputs is as well), we will assume that all dependencies come + from the dataframe. This cannot be used in conjunction with pass_dataframe_as. + :param pass_dataframe_as: The name of the dataframe that we're modifying, as known to the subdag. + If you pass this in, you are responsible for extracting columns out. If not provided, you have + to pass columns_to_pass in, and we will extract the columns out for you. + :param on_input: the dataframe parameter that we are applying with_columns on. By default we + will assume the first parameter is the corresponding dataframe. + :param select: The end nodes that represent columns to be appended to the original dataframe + via with_columns. Existing columns will be overridden. + :param namespace: The namespace of the nodes, so they don't clash with the global namespace + and so this can be reused. If its left out, there will be no namespace (in which case you'll want + to be careful about repeating it/reusing the nodes in other parts of the DAG.) + :param config_required: the list of config keys that are required to resolve any functions. Pass in None\ + if you want the functions/modules to have access to all possible config. + """ + + self.subdag_functions = subdag.collect_functions(load_from) + self.select = select + + # This is here to restrict to using either pass_dataframe_as or on_input or columns_to_pass + # TODO: decouple columns_to_pass, pass_dataframe_as and on_input + # For spark, we always perform with_columns on first parameter and use pass_dataframe_as; + # for pandas/polars, we can select which dataframe with on_input, but columns_to_pass, will always only work on first parameter + # We can decouple it so that on_input selects the target dataframe parameter that will inject into the next node + # pass_dataframe_as selects the original dataframe we want to extract columns from + # columns_to_pass is optinal helper that can be toggled on/off so no need to raise this error. + if ( + int(pass_dataframe_as is None) + int(columns_to_pass is None) + int(on_input is None) + == 1 + ): + raise ValueError( + "You must specify only one of ``columns_to_pass``, ``pass_dataframe_as``, and ``on_input``. " + "This is because specifying ``pass_dataframe_as`` or ``on_input`` injects into " + "the set of columns, allowing you to perform your own extraction" + "from the dataframe. We then execute all columns in the subdag" + "in order, passing in that initial dataframe. If you want" + "to reference columns in your code, you'll have to specify " + "the set of initial columns, and allow the subdag decorator " + "to inject the dataframe through. The initial columns tell " + "us which parameters to take from that dataframe, so we can" + "feed the right data into the right columns." + ) + + self.initial_schema = columns_to_pass + self.dataframe_subdag_param = pass_dataframe_as + self.target_dataframe = on_input + self.namespace = namespace + self.config_required = config_required + + if dataframe_type is None: + raise InvalidDecoratorException( + "Please provide the dataframe type for this specific library." + ) + + self.dataframe_type = dataframe_type + + def required_config(self) -> List[str]: + return self.config_required + + @abc.abstractmethod + def get_initial_nodes( + self, fn: Callable, params: Dict[str, Type[Type]] + ) -> Tuple[str, Collection[node.Node]]: + """Preparation stage where columns get extracted into nodes. In case `pass_dataframe_as` or `on_input` is + used, this should return an empty list (no column nodes) since the users will extract it + themselves. + + :param fn: the function we are decorating. By using the inspect library you can get information. + about what arguments it has / find out the dataframe argument. + :param params: Dictionary of all the type names one wants to inject. + :return: name of the dataframe parameter and list of nodes representing the extracted columns (can be empty). + """ + pass + + @abc.abstractmethod + def get_subdag_nodes(self, fn: Callable, config: Dict[str, Any]) -> Collection[node.Node]: + """Creates subdag from the passed in module / functions. + + :param config: Configuration with which the DAG was constructed. + :return: the subdag as a list of nodes. + """ + pass + + @abc.abstractmethod + def chain_subdag_nodes( + self, fn: Callable, inject_parameter: str, generated_nodes: Collection[node.Node] + ) -> node.Node: + """Combines the origanl dataframe with selected columns. This should produce a + dataframe output that is injected into the decorated function with new columns + appended and existing columns overriden. + + :param inject_parameter: the name of the original dataframe that. + :return: the new dataframe with the columns appended / overwritten. + """ + pass + + def inject_nodes( + self, params: Dict[str, Type[Type]], config: Dict[str, Any], fn: Callable + ) -> Tuple[List[node.Node], Dict[str, str]]: + namespace = fn.__name__ if self.namespace is None else self.namespace + + inject_parameter, initial_nodes = self.get_initial_nodes(fn=fn, params=params) + subdag_nodes = self.get_subdag_nodes(fn=fn, config=config) + generated_nodes = initial_nodes + subdag_nodes + # TODO: for now we restrict that if user wants to change columns that already exist, he needs to + # pass the dataframe and extract them himself. If we add namespace to initial nodes and rewire the + # initial node names with the ongoing ones that have a column argument, we can also allow in place + # changes when using columns_to_pass + if with_columns_base.contains_duplicates(generated_nodes): + raise ValueError( + "You can only specify columns once. You used `columns_to_pass` and we " + "extract the columns for you. In this case they cannot be overwritten -- only new columns get " + "appended. If you want to modify in-place columns pass in a dataframe and " + "extract + modify the columns and afterwards select them." + ) + + pruned_nodes = prune_nodes(nodes=generated_nodes, select=self.select) + if len(pruned_nodes) == 0: + raise ValueError( + f"No nodes found upstream from select columns: {self.select} for function: " + f"{fn.__qualname__}" + ) + + # Node combining columns and dataframe might need info about prior nodes + output_nodes, current_param = self.chain_subdag_nodes( + fn=fn, inject_parameter=inject_parameter, generated_nodes=pruned_nodes + ) + output_nodes = subdag.add_namespace(output_nodes, namespace) + return output_nodes, {inject_parameter: assign_namespace(current_param, namespace)} diff --git a/tests/function_modifiers/test_recursive.py b/tests/function_modifiers/test_recursive.py index 7b3ae7a91..e9b76686c 100644 --- a/tests/function_modifiers/test_recursive.py +++ b/tests/function_modifiers/test_recursive.py @@ -5,6 +5,7 @@ import pytest +import hamilton from hamilton import ad_hoc_utils, graph from hamilton.function_modifiers import ( InvalidDecoratorException, @@ -16,7 +17,7 @@ ) from hamilton.function_modifiers.base import NodeTransformer from hamilton.function_modifiers.dependencies import source -from hamilton.function_modifiers.recursive import _validate_config_inputs +from hamilton.function_modifiers.recursive import _validate_config_inputs, with_columns_base import tests.resources.reuse_subdag @@ -539,3 +540,16 @@ def test_recursive_validate_config_inputs_happy(config, inputs): def test_recursive_validate_config_inputs_sad(config, inputs): with pytest.raises(InvalidDecoratorException): _validate_config_inputs(config, inputs) + + +def dummy_fn_with_columns(col_1: int) -> int: + return col_1 + 100 + + +def test_columns_and_subdag_nodes_do_not_clash(): + node_a = hamilton.node.Node.from_fn(dummy_fn_with_columns, name="a") + node_b = hamilton.node.Node.from_fn(dummy_fn_with_columns, name="a") + node_c = hamilton.node.Node.from_fn(dummy_fn_with_columns, name="c") + + assert not with_columns_base.contains_duplicates([node_a, node_c]) + assert with_columns_base.contains_duplicates([node_a, node_b, node_c]) From 65e13d2d25e94f946a81594ab25f3575f91847c0 Mon Sep 17 00:00:00 2001 From: jernejfrank Date: Sun, 24 Nov 2024 11:04:44 +0800 Subject: [PATCH 3/6] Refactor h_spark.with_columns Inherits from with_columns_base. Previous implementation is based on NodeGenerator where the last node had to be implemented. New implementation is based on NodeInjector where the last node is created later. The tests are adjusted so that they do not check this node. --- examples/spark/pyspark/out.png | Bin 1167 -> 80443 bytes hamilton/plugins/h_spark.py | 115 +++++++++++++-------------- plugin_tests/h_spark/test_h_spark.py | 51 +++++++++--- 3 files changed, 94 insertions(+), 72 deletions(-) diff --git a/examples/spark/pyspark/out.png b/examples/spark/pyspark/out.png index e869077614fe4d8125e3797b12cc8b88cc51be06..5ac2eaa1b23f01533f0671dc0514ce49dd0c78db 100644 GIT binary patch literal 80443 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þ{nvRpPKS1IKqg3W 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�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 MPgg&ebxsLQ0K+d?Y5)KL literal 1167 zcmbVLL2kn!5Io1PK)$zmL3*mxM^qKsn2n7}2x4)nw(8#tjsXYN3F^u6FgrWT4%;nz zMuS?Q?mpRz1v4~4_TkIEo6Q~wxj3*_1$$Jx`S-2aP^jVLz)5nlqsS=ni3;|e6B5aj z&b$Sf^o|G%M(7ZbbWBcgf#IF-^ zSY6^bdVirkO+(ymota+lAT=m%kw)cW*DH($Fu1eWIncer8V7vT((yA`3A)32KSiBy zMP{))_VC2!T;#lXtW3fmnMtg$ List[str]: return list(df_deps) -class with_columns(fm_base.NodeCreator): +class with_columns(with_columns_base): def __init__( self, *load_from: Union[Callable, ModuleType], columns_to_pass: List[str] = None, pass_dataframe_as: str = None, + on_input: str = None, select: List[str] = None, namespace: str = None, mode: str = "append", @@ -992,29 +994,24 @@ def final_df(initial_df: ps.DataFrame) -> ps.DataFrame: :param config_required: the list of config keys that are required to resolve any functions. Pass in None\ if you want the functions/modules to have access to all possible config. """ - self.subdag_functions = subdag.collect_functions(load_from) - self.select = select - self.initial_schema = columns_to_pass - if (pass_dataframe_as is not None and columns_to_pass is not None) or ( - pass_dataframe_as is None and columns_to_pass is None - ): - raise ValueError( - "You must specify only one of columns_to_pass and " - "pass_dataframe_as. " - "This is because specifying pass_dataframe_as injects into " - "the set of columns, allowing you to perform your own extraction" - "from the dataframe. We then execute all columns in the sbudag" - "in order, passing in that initial dataframe. If you want" - "to reference columns in your code, you'll have to specify " - "the set of initial columns, and allow the subdag decorator " - "to inject the dataframe through. The initial columns tell " - "us which parameters to take from that dataframe, so we can" - "feed the right data into the right columns." + + if on_input is not None: + raise NotImplementedError( + "We currently do not support on_input for spark. Please reach out if you need this " + "functionality." ) - self.dataframe_subdag_param = pass_dataframe_as - self.namespace = namespace + + super().__init__( + *load_from, + columns_to_pass=columns_to_pass, + pass_dataframe_as=pass_dataframe_as, + select=select, + namespace=namespace, + config_required=config_required, + dataframe_type=DATAFRAME_TYPE, + ) + self.mode = mode - self.config_required = config_required @staticmethod def _prep_nodes(initial_nodes: List[node.Node]) -> List[node.Node]: @@ -1118,42 +1115,43 @@ def _validate_dataframe_subdag_parameter(self, nodes: List[node.Node], fn_name: def required_config(self) -> List[str]: return self.config_required - def generate_nodes(self, fn: Callable, config: Dict[str, Any]) -> List[node.Node]: - """Generates nodes in the with_columns groups. This does the following: - - 1. Collects all the nodes from the subdag functions - 2. Prunes them to only include the ones that are upstream from the select columns - 3. Sorts them topologically - 4. Creates a new node for each one, injecting the dataframe parameter into the first one - 5. Creates a new node for the final one, injecting the last node into that one - 6. Returns the list of nodes + def get_initial_nodes( + self, fn: Callable, params: Dict[str, Type[Type]] + ) -> Tuple[str, Collection[node.Node]]: + inject_parameter = _derive_first_dataframe_parameter_from_fn(fn=fn) + with_columns_base.validate_dataframe( + fn=fn, + inject_parameter=inject_parameter, + params=params, + required_type=self.dataframe_type, + ) + # Cannot extract columns in pyspark + initial_nodes = [] + return inject_parameter, initial_nodes - :param fn: Function to generate from - :param config: Config to use for generating/collecting nodes - :return: List of nodes that this function produces - """ - namespace = fn.__name__ if self.namespace is None else self.namespace + def get_subdag_nodes(self, fn: Callable, config: Dict[str, Any]) -> Collection[node.Node]: initial_nodes = subdag.collect_nodes(config, self.subdag_functions) transformed_nodes = with_columns._prep_nodes(initial_nodes) + self._validate_dataframe_subdag_parameter(transformed_nodes, fn.__qualname__) - pruned_nodes = prune_nodes(transformed_nodes, self.select) - if len(pruned_nodes) == 0: - raise ValueError( - f"No nodes found upstream from select columns: {self.select} for function: " - f"{fn.__qualname__}" - ) - sorted_initial_nodes = graph_functions.topologically_sort_nodes(pruned_nodes) - output_nodes = [] - inject_parameter = _derive_first_dataframe_parameter_from_fn(fn) - current_dataframe_node = inject_parameter + return transformed_nodes + + def chain_subdag_nodes( + self, fn: Callable, inject_parameter: str, generated_nodes: Collection[node.Node] + ) -> node.Node: + generated_nodes = graph_functions.topologically_sort_nodes(generated_nodes) + # Columns that it is dependent on could be from the group of transforms created - columns_produced_within_mapgroup = {node_.name for node_ in pruned_nodes} + columns_produced_within_mapgroup = {node_.name for node_ in generated_nodes} + # Or from the dataframe passed in... columns_passed_in_from_dataframe = ( set(self.initial_schema) if self.initial_schema is not None else [] ) + + current_dataframe_node = inject_parameter + output_nodes = [] drop_list = [] - # Or from the dataframe passed in... - for node_ in sorted_initial_nodes: + for node_ in generated_nodes: # dependent columns are broken into two sets: # 1. Those that come from the group of transforms dependent_columns_in_mapgroup = { @@ -1183,18 +1181,20 @@ def generate_nodes(self, fn: Callable, config: Dict[str, Any]) -> List[node.Node dependent_columns_in_mapgroup, dependent_columns_in_dataframe, ) + if self.select is not None and sparkified.name not in self.select: # we need to create a drop list because we don't want to drop # original columns from the DF by accident. drop_list.append(sparkified.name) + output_nodes.append(sparkified) current_dataframe_node = sparkified.name - # We get the final node, which is the function we're using - # and reassign inputs to be the dataframe + if self.mode == "select": - # this selects over the original DF and the additions + # Have to redo this here since for spark the nodes are of type dataframe and not columns + # so with_columns.inject_nodes does not correctly select all the sink nodes select_columns = ( - self.select if self.select is not None else [item.name for item in output_nodes] + self.select if self.select is not None else [item.name for item in generated_nodes] ) select_node = with_columns.create_selector_node( upstream_name=current_dataframe_node, @@ -1214,11 +1214,8 @@ def generate_nodes(self, fn: Callable, config: Dict[str, Any]) -> List[node.Node ) output_nodes.append(select_node) current_dataframe_node = select_node.name - output_nodes = subdag.add_namespace(output_nodes, namespace) - final_node = node.Node.from_fn(fn).reassign_inputs( - {inject_parameter: assign_namespace(current_dataframe_node, namespace)} - ) - return output_nodes + [final_node] + + return output_nodes, current_dataframe_node def validate(self, fn: Callable): _derive_first_dataframe_parameter_from_fn(fn) diff --git a/plugin_tests/h_spark/test_h_spark.py b/plugin_tests/h_spark/test_h_spark.py index 2f12ea5d8..36bc295a4 100644 --- a/plugin_tests/h_spark/test_h_spark.py +++ b/plugin_tests/h_spark/test_h_spark.py @@ -11,6 +11,8 @@ from pyspark.sql.functions import column from hamilton import base, driver, htypes, node +from hamilton.function_modifiers.base import NodeInjector +from hamilton.function_modifiers.recursive import prune_nodes from hamilton.plugins import h_spark from hamilton.plugins.h_spark import SparkInputValidator @@ -569,7 +571,7 @@ def test_prune_nodes_no_select(): node.Node.from_fn(fn) for fn in [basic_spark_dag.a, basic_spark_dag.b, basic_spark_dag.c] ] select = None - assert {n for n in h_spark.prune_nodes(nodes, select)} == set(nodes) + assert {n for n in prune_nodes(nodes, select)} == set(nodes) def test_prune_nodes_single_select(): @@ -577,7 +579,7 @@ def test_prune_nodes_single_select(): node.Node.from_fn(fn) for fn in [basic_spark_dag.a, basic_spark_dag.b, basic_spark_dag.c] ] select = ["a", "b"] - assert {n for n in h_spark.prune_nodes(nodes, select)} == set(nodes[0:2]) + assert {n for n in prune_nodes(nodes, select)} == set(nodes[0:2]) def test_generate_nodes_invalid_select(): @@ -593,7 +595,10 @@ def test_generate_nodes_invalid_select(): def df_as_pandas(df: DataFrame) -> pd.DataFrame: return df.toPandas() - dec.generate_nodes(df_as_pandas, {}) + dummy_node = node.Node.from_fn(df_as_pandas) + injectable_params = NodeInjector.find_injectable_params([dummy_node]) + + dec.inject_nodes(params=injectable_params, config={}, fn=df_as_pandas) def test_with_columns_generate_nodes_no_select(): @@ -607,13 +612,16 @@ def test_with_columns_generate_nodes_no_select(): def df_as_pandas(df: DataFrame) -> pd.DataFrame: return df.toPandas() - nodes = dec.generate_nodes(df_as_pandas, {}) + dummy_node = node.Node.from_fn(df_as_pandas) + injectable_params = NodeInjector.find_injectable_params([dummy_node]) + + nodes, _ = dec.inject_nodes(params=injectable_params, config={}, fn=df_as_pandas) + nodes_by_names = {n.name: n for n in nodes} assert set(nodes_by_names.keys()) == { "df_as_pandas.a", "df_as_pandas.b", "df_as_pandas.c", - "df_as_pandas", } @@ -629,9 +637,14 @@ def test_with_columns_generate_nodes_select(): def df_as_pandas(df: DataFrame) -> pd.DataFrame: return df.toPandas() - nodes = dec.generate_nodes(df_as_pandas, {}) + dummy_node = node.Node.from_fn(df_as_pandas) + injectable_params = NodeInjector.find_injectable_params([dummy_node]) + + nodes, _ = dec.inject_nodes(params=injectable_params, config={}, fn=df_as_pandas) nodes_by_names = {n.name: n for n in nodes} - assert set(nodes_by_names.keys()) == {"df_as_pandas.c", "df_as_pandas"} + assert set(nodes_by_names.keys()) == { + "df_as_pandas.c", + } def test_with_columns_generate_nodes_select_append_mode(): @@ -644,10 +657,13 @@ def test_with_columns_generate_nodes_select_append_mode(): def df_as_pandas(df: DataFrame) -> pd.DataFrame: return df.toPandas() - nodes = dec.generate_nodes(df_as_pandas, {}) + dummy_node = node.Node.from_fn(df_as_pandas) + injectable_params = NodeInjector.find_injectable_params([dummy_node]) + + nodes, _ = dec.inject_nodes(params=injectable_params, config={}, fn=df_as_pandas) + nodes_by_names = {n.name: n for n in nodes} assert set(nodes_by_names.keys()) == { - "df_as_pandas", "df_as_pandas._select", "df_as_pandas.a", "df_as_pandas.b", @@ -668,11 +684,13 @@ def test_with_columns_generate_nodes_select_mode_select(): def df_as_pandas(df: DataFrame) -> pd.DataFrame: return df.toPandas() - nodes = dec.generate_nodes(df_as_pandas, {}) + dummy_node = node.Node.from_fn(df_as_pandas) + injectable_params = NodeInjector.find_injectable_params([dummy_node]) + + nodes, _ = dec.inject_nodes(params=injectable_params, config={}, fn=df_as_pandas) nodes_by_names = {n.name: n for n in nodes} assert set(nodes_by_names.keys()) == { "df_as_pandas.c", - "df_as_pandas", "df_as_pandas._select", } @@ -689,9 +707,16 @@ def test_with_columns_generate_nodes_specify_namespace(): def df_as_pandas(df: DataFrame) -> pd.DataFrame: return df.toPandas() - nodes = dec.generate_nodes(df_as_pandas, {}) + dummy_node = node.Node.from_fn(df_as_pandas) + injectable_params = NodeInjector.find_injectable_params([dummy_node]) + + nodes, _ = dec.inject_nodes(params=injectable_params, config={}, fn=df_as_pandas) nodes_by_names = {n.name: n for n in nodes} - assert set(nodes_by_names.keys()) == {"foo.a", "foo.b", "foo.c", "df_as_pandas"} + assert set(nodes_by_names.keys()) == { + "foo.a", + "foo.b", + "foo.c", + } def test__format_pandas_udf(): From 26e7983411a9b81aa875a6146088c58ed1d755cb Mon Sep 17 00:00:00 2001 From: jernejfrank Date: Sun, 24 Nov 2024 11:08:32 +0800 Subject: [PATCH 4/6] Refactor h_pandas.with_columns Uses with_columns_base and adjusted internally. Tests had to be adjusted to test pandas specific functionality and internal function naming changes. --- examples/pandas/with_columns/notebook.ipynb | 866 +++++++++--------- hamilton/plugins/h_pandas.py | 234 ++--- .../resources/with_columns_end_to_end.py | 4 +- plugin_tests/h_pandas/test_with_columns.py | 180 ++-- 4 files changed, 630 insertions(+), 654 deletions(-) diff --git a/examples/pandas/with_columns/notebook.ipynb b/examples/pandas/with_columns/notebook.ipynb index 49eca8ed7..495b46aa1 100644 --- a/examples/pandas/with_columns/notebook.ipynb +++ b/examples/pandas/with_columns/notebook.ipynb @@ -30,9 +30,7 @@ "output_type": "stream", "text": [ "/Users/jernejfrank/miniconda3/envs/hamilton/lib/python3.10/site-packages/pyspark/pandas/__init__.py:50: UserWarning: 'PYARROW_IGNORE_TIMEZONE' environment variable was not set. It is required to set this environment variable to '1' in both driver and executor sides if you use pyarrow>=2.0.0. pandas-on-Spark will set it for you but it does not work if there is a Spark context already launched.\n", - " warnings.warn(\n", - "/Users/jernejfrank/miniconda3/envs/hamilton/lib/python3.10/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n", - " from .autonotebook import tqdm as notebook_tqdm\n" + " warnings.warn(\n" ] } ], @@ -59,334 +57,222 @@ "\n", "\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "\n", "\n", "cluster__legend\n", - "\n", - "Legend\n", + "\n", + "Legend\n", "\n", "\n", "\n", "case\n", - "\n", - "\n", - "\n", - "case\n", - "thousands\n", + "\n", + "\n", + "\n", + "case\n", + "thousands\n", "\n", - "\n", + "\n", "\n", - "initial_df\n", - "\n", - "initial_df\n", - "DataFrame\n", - "\n", - "\n", - "\n", - "final_df.signups\n", - "\n", - "final_df.signups\n", - "Series\n", + "final_df.spend_zero_mean\n", + "\n", + "final_df.spend_zero_mean\n", + "Series\n", "\n", - "\n", - "\n", - "initial_df->final_df.signups\n", - "\n", - "\n", + "\n", + "\n", + "final_df.spend_zero_mean_unit_variance\n", + "\n", + "final_df.spend_zero_mean_unit_variance\n", + "Series\n", "\n", - "\n", - "\n", - "final_df.__append\n", - "\n", - "final_df.__append\n", - "DataFrame\n", + "\n", + "\n", + "final_df.spend_zero_mean->final_df.spend_zero_mean_unit_variance\n", + "\n", + "\n", "\n", - "\n", - "\n", - "initial_df->final_df.__append\n", - "\n", - "\n", + "\n", + "\n", + "final_df\n", + "\n", + "final_df\n", + "DataFrame\n", "\n", "\n", - "\n", + "\n", "final_df.spend\n", - "\n", - "final_df.spend\n", - "Series\n", + "\n", + "final_df.spend\n", + "Series\n", "\n", - "\n", - "\n", - "initial_df->final_df.spend\n", - "\n", - "\n", + "\n", + "\n", + "final_df.spend->final_df.spend_zero_mean\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "final_df.spend_per_signup\n", + "\n", + "final_df.spend_per_signup\n", + "Series\n", + "\n", + "\n", + "\n", + "final_df.spend->final_df.spend_per_signup\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "final_df.avg_3wk_spend\n", - "\n", - "final_df.avg_3wk_spend: case\n", - "Series\n", + "\n", + "final_df.avg_3wk_spend: case\n", + "Series\n", "\n", - "\n", - "\n", - "final_df.avg_3wk_spend->final_df.__append\n", - "\n", - "\n", - "\n", - "\n", - "final_df.signups->final_df.__append\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "final_df.spend->final_df.avg_3wk_spend\n", + "\n", + "\n", "\n", - "\n", - "\n", - "final_df.spend_per_signup\n", - "\n", - "final_df.spend_per_signup\n", - "Series\n", + "\n", + "\n", + "final_df.spend_mean\n", + "\n", + "final_df.spend_mean\n", + "float\n", "\n", - "\n", - "\n", - "final_df.signups->final_df.spend_per_signup\n", - "\n", - "\n", + "\n", + "\n", + "final_df.spend->final_df.spend_mean\n", + "\n", + "\n", "\n", - "\n", - "\n", - "final_df.spend_zero_mean\n", - "\n", - "final_df.spend_zero_mean\n", - "Series\n", + "\n", + "\n", + "final_df.spend_std_dev\n", + "\n", + "final_df.spend_std_dev\n", + "float\n", "\n", - "\n", - "\n", - "final_df.spend_zero_mean_unit_variance\n", - "\n", - "final_df.spend_zero_mean_unit_variance\n", - "Series\n", + "\n", + "\n", + "final_df.spend->final_df.spend_std_dev\n", + "\n", + "\n", "\n", - "\n", - "\n", - "final_df.spend_zero_mean->final_df.spend_zero_mean_unit_variance\n", - "\n", - "\n", + "\n", + "\n", + "final_df.__append\n", + "\n", + "final_df.__append\n", + "DataFrame\n", "\n", - "\n", - "\n", - "final_df.spend_zero_mean_unit_variance->final_df.__append\n", - "\n", - "\n", + "\n", + "\n", + "final_df.spend_per_signup->final_df.__append\n", + "\n", "\n", - "\n", - "\n", - "final_df\n", - "\n", - "final_df\n", - "DataFrame\n", + "\n", + "\n", + "final_df.avg_3wk_spend->final_df.__append\n", + "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "final_df.__append->final_df\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "final_df.spend_mean\n", - "\n", - "final_df.spend_mean\n", - "float\n", - "\n", - "\n", - "\n", - "final_df.spend_mean->final_df.spend_zero_mean\n", - "\n", - "\n", + "\n", + "\n", "\n", - "\n", - "\n", - "final_df.spend_std_dev\n", - "\n", - "final_df.spend_std_dev\n", - "float\n", + "\n", + "\n", + "final_df.signups\n", + "\n", + "final_df.signups\n", + "Series\n", "\n", - "\n", + "\n", "\n", - "final_df.spend_std_dev->final_df.spend_zero_mean_unit_variance\n", - "\n", - "\n", + "final_df.signups->final_df.spend_per_signup\n", + "\n", + "\n", "\n", - "\n", - "\n", - "final_df.spend->final_df.avg_3wk_spend\n", - "\n", - "\n", + "\n", + "\n", + "final_df.spend_zero_mean_unit_variance->final_df.__append\n", + "\n", + "\n", "\n", - "\n", - "\n", - "final_df.spend->final_df.spend_zero_mean\n", - "\n", - "\n", + "\n", + "\n", + "initial_df\n", + "\n", + "initial_df\n", + "DataFrame\n", "\n", - "\n", - "\n", - "final_df.spend->final_df.__append\n", - "\n", + "\n", + "\n", + "initial_df->final_df.spend\n", + "\n", + "\n", "\n", - "\n", - "\n", - "final_df.spend->final_df.spend_mean\n", - "\n", - "\n", + "\n", + "\n", + "initial_df->final_df.__append\n", + "\n", + "\n", "\n", - "\n", - "\n", - "final_df.spend->final_df.spend_std_dev\n", - "\n", - "\n", + "\n", + "\n", + "initial_df->final_df.signups\n", + "\n", + "\n", "\n", - "\n", - "\n", - "final_df.spend->final_df.spend_per_signup\n", - "\n", - "\n", + "\n", + "\n", + "final_df.spend_mean->final_df.spend_zero_mean\n", + "\n", + "\n", "\n", - "\n", - "\n", - "final_df.spend_per_signup->final_df.__append\n", - "\n", + "\n", + "\n", + "final_df.spend_std_dev->final_df.spend_zero_mean_unit_variance\n", + "\n", + "\n", "\n", "\n", "\n", "config\n", - "\n", - "\n", - "\n", - "config\n", + "\n", + "\n", + "\n", + "config\n", "\n", "\n", "\n", "function\n", - "\n", - "function\n", + "\n", + "function\n", "\n", "\n", "\n", "output\n", - "\n", - "output\n", + "\n", + "output\n", "\n", "\n", "\n" ], "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
signupsspendavg_3wk_spendspend_per_signupspend_zero_mean_unit_variance
0110000000.0NaN10000000.0-1.064405
11010000000.0NaN1000000.0-1.064405
25020000000.013333.333333400000.0-0.483821
310040000000.023333.333333400000.00.677349
420040000000.033333.333333200000.00.677349
540050000000.043333.333333125000.01.257934
\n", - "
" - ], - "text/plain": [ - " signups spend avg_3wk_spend spend_per_signup \\\n", - "0 1 10000000.0 NaN 10000000.0 \n", - "1 10 10000000.0 NaN 1000000.0 \n", - "2 50 20000000.0 13333.333333 400000.0 \n", - "3 100 40000000.0 23333.333333 400000.0 \n", - "4 200 40000000.0 33333.333333 200000.0 \n", - "5 400 50000000.0 43333.333333 125000.0 \n", - "\n", - " spend_zero_mean_unit_variance \n", - "0 -1.064405 \n", - "1 -1.064405 \n", - "2 -0.483821 \n", - "3 0.677349 \n", - "4 0.677349 \n", - "5 1.257934 " + "" ] }, "metadata": {}, @@ -400,8 +286,8 @@ "import my_functions\n", "\n", "output_columns = [\n", - " \"spend\",\n", - " \"signups\",\n", + " # \"spend\",\n", + " # \"signups\",\n", " \"avg_3wk_spend\",\n", " \"spend_per_signup\",\n", " \"spend_zero_mean_unit_variance\",\n", @@ -461,232 +347,222 @@ "\n", "\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "\n", "\n", "cluster__legend\n", - "\n", - "Legend\n", + "\n", + "Legend\n", "\n", "\n", "\n", "case\n", - "\n", - "\n", - "\n", - "case\n", - "millions\n", + "\n", + "\n", + "\n", + "case\n", + "millions\n", "\n", - "\n", + "\n", "\n", - "initial_df\n", - "\n", - "initial_df\n", - "DataFrame\n", - "\n", - "\n", - "\n", - "final_df.signups\n", - "\n", - "final_df.signups\n", - "Series\n", + "final_df.spend_zero_mean\n", + "\n", + "final_df.spend_zero_mean\n", + "Series\n", "\n", - "\n", - "\n", - "initial_df->final_df.signups\n", - "\n", - "\n", + "\n", + "\n", + "final_df.spend_zero_mean_unit_variance\n", + "\n", + "final_df.spend_zero_mean_unit_variance\n", + "Series\n", "\n", - "\n", - "\n", - "final_df.__append\n", - "\n", - "final_df.__append\n", - "DataFrame\n", + "\n", + "\n", + "final_df.spend_zero_mean->final_df.spend_zero_mean_unit_variance\n", + "\n", + "\n", "\n", - "\n", - "\n", - "initial_df->final_df.__append\n", - "\n", - "\n", + "\n", + "\n", + "final_df\n", + "\n", + "final_df\n", + "DataFrame\n", "\n", "\n", - "\n", + "\n", "final_df.spend\n", - "\n", - "final_df.spend\n", - "Series\n", + "\n", + "final_df.spend\n", + "Series\n", "\n", - "\n", - "\n", - "initial_df->final_df.spend\n", - "\n", - "\n", + "\n", + "\n", + "final_df.spend->final_df.spend_zero_mean\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "final_df.spend_per_signup\n", + "\n", + "final_df.spend_per_signup\n", + "Series\n", + "\n", + "\n", + "\n", + "final_df.spend->final_df.spend_per_signup\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "final_df.avg_3wk_spend\n", - "\n", - "final_df.avg_3wk_spend: case\n", - "Series\n", + "\n", + "final_df.avg_3wk_spend: case\n", + "Series\n", "\n", - "\n", - "\n", - "final_df.avg_3wk_spend->final_df.__append\n", - "\n", - "\n", - "\n", - "\n", - "final_df.signups->final_df.__append\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "final_df.spend->final_df.avg_3wk_spend\n", + "\n", + "\n", "\n", - "\n", - "\n", - "final_df.spend_per_signup\n", - "\n", - "final_df.spend_per_signup\n", - "Series\n", + "\n", + "\n", + "final_df.spend_mean\n", + "\n", + "final_df.spend_mean\n", + "float\n", "\n", - "\n", - "\n", - "final_df.signups->final_df.spend_per_signup\n", - "\n", - "\n", + "\n", + "\n", + "final_df.spend->final_df.spend_mean\n", + "\n", + "\n", "\n", - "\n", - "\n", - "final_df.spend_zero_mean\n", - "\n", - "final_df.spend_zero_mean\n", - "Series\n", + "\n", + "\n", + "final_df.spend_std_dev\n", + "\n", + "final_df.spend_std_dev\n", + "float\n", "\n", - "\n", - "\n", - "final_df.spend_zero_mean_unit_variance\n", - "\n", - "final_df.spend_zero_mean_unit_variance\n", - "Series\n", + "\n", + "\n", + "final_df.spend->final_df.spend_std_dev\n", + "\n", + "\n", "\n", - "\n", - "\n", - "final_df.spend_zero_mean->final_df.spend_zero_mean_unit_variance\n", - "\n", - "\n", + "\n", + "\n", + "final_df.__append\n", + "\n", + "final_df.__append\n", + "DataFrame\n", "\n", - "\n", - "\n", - "final_df.spend_zero_mean_unit_variance->final_df.__append\n", - "\n", - "\n", + "\n", + "\n", + "final_df.spend_per_signup->final_df.__append\n", + "\n", "\n", - "\n", - "\n", - "final_df\n", - "\n", - "final_df\n", - "DataFrame\n", + "\n", + "\n", + "final_df.avg_3wk_spend->final_df.__append\n", + "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "final_df.__append->final_df\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "final_df.spend_mean\n", - "\n", - "final_df.spend_mean\n", - "float\n", - "\n", - "\n", - "\n", - "final_df.spend_mean->final_df.spend_zero_mean\n", - "\n", - "\n", + "\n", + "\n", "\n", - "\n", - "\n", - "final_df.spend_std_dev\n", - "\n", - "final_df.spend_std_dev\n", - "float\n", + "\n", + "\n", + "final_df.signups\n", + "\n", + "final_df.signups\n", + "Series\n", "\n", - "\n", + "\n", "\n", - "final_df.spend_std_dev->final_df.spend_zero_mean_unit_variance\n", - "\n", - "\n", + "final_df.signups->final_df.spend_per_signup\n", + "\n", + "\n", "\n", - "\n", - "\n", - "final_df.spend->final_df.avg_3wk_spend\n", - "\n", - "\n", + "\n", + "\n", + "final_df.spend_zero_mean_unit_variance->final_df.__append\n", + "\n", + "\n", "\n", - "\n", - "\n", - "final_df.spend->final_df.spend_zero_mean\n", - "\n", - "\n", + "\n", + "\n", + "initial_df\n", + "\n", + "initial_df\n", + "DataFrame\n", "\n", - "\n", - "\n", - "final_df.spend->final_df.__append\n", - "\n", + "\n", + "\n", + "initial_df->final_df.spend\n", + "\n", + "\n", "\n", - "\n", - "\n", - "final_df.spend->final_df.spend_mean\n", - "\n", - "\n", + "\n", + "\n", + "initial_df->final_df.__append\n", + "\n", + "\n", "\n", - "\n", - "\n", - "final_df.spend->final_df.spend_std_dev\n", - "\n", - "\n", + "\n", + "\n", + "initial_df->final_df.signups\n", + "\n", + "\n", "\n", - "\n", - "\n", - "final_df.spend->final_df.spend_per_signup\n", - "\n", - "\n", + "\n", + "\n", + "final_df.spend_mean->final_df.spend_zero_mean\n", + "\n", + "\n", "\n", - "\n", - "\n", - "final_df.spend_per_signup->final_df.__append\n", - "\n", + "\n", + "\n", + "final_df.spend_std_dev->final_df.spend_zero_mean_unit_variance\n", + "\n", + "\n", "\n", "\n", "\n", "config\n", - "\n", - "\n", - "\n", - "config\n", + "\n", + "\n", + "\n", + "config\n", "\n", "\n", "\n", "function\n", - "\n", - "function\n", + "\n", + "function\n", "\n", "\n", "\n", "output\n", - "\n", - "output\n", + "\n", + "output\n", "\n", "\n", "\n" ], "text/plain": [ - "" + "" ] }, "execution_count": 3, @@ -701,6 +577,102 @@ "dr.visualize_execution(final_vars=[\"final_df\"])\n" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# We can also run it async" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "%reload_ext hamilton.plugins.jupyter_magic" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "%%cell_to_module with_columns_async\n", + "\n", + "import asyncio\n", + "import pandas as pd\n", + "from hamilton.plugins.h_pandas import with_columns\n", + "\n", + "async def data_input() -> pd.DataFrame:\n", + " await asyncio.sleep(0.0001)\n", + " return pd.DataFrame({\n", + " \"a\": [1, 2, 3],\n", + " \"b\": [4, 5, 6],\n", + " \"c\": [7, 8, 9]\n", + " })\n", + "\n", + "\n", + "async def multiply_a(a: pd.Series) -> pd.Series:\n", + " await asyncio.sleep(0.0001)\n", + " return a * 10\n", + "\n", + "\n", + "async def mean_b(b: pd.Series) -> pd.Series:\n", + " await asyncio.sleep(5)\n", + " return b.mean()\n", + "\n", + "async def a_plus_b(a: pd.Series, b: pd.Series) -> pd.Series:\n", + " await asyncio.sleep(1)\n", + " return a + b\n", + "\n", + "async def multiply_a_plus_mean_b(multiply_a: pd.Series, mean_b: pd.Series) -> pd.Series:\n", + " await asyncio.sleep(0.0001)\n", + " return multiply_a + mean_b\n", + "\n", + "\n", + "@with_columns(\n", + " multiply_a,mean_b,a_plus_b, multiply_a_plus_mean_b,\n", + " columns_to_pass=[\"a\", \"b\"]\n", + ")\n", + "def final_df(data_input: pd.DataFrame) -> pd.DataFrame:\n", + " return data_input" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " a b c multiply_a mean_b a_plus_b multiply_a_plus_mean_b\n", + "0 1 4 7 10 5.0 5 15.0\n", + "1 2 5 8 20 5.0 7 25.0\n", + "2 3 6 9 30 5.0 9 35.0\n" + ] + } + ], + "source": [ + "import asyncio\n", + "from hamilton import async_driver\n", + "import with_columns_async\n", + "\n", + "async def main():\n", + " await asyncio.sleep(2)\n", + " dr = (await async_driver.Builder()\n", + " .with_modules(with_columns_async)\n", + " .with_config({\"case\":\"millions\"})\n", + " .build())\n", + " results = await dr.execute([\"final_df\"])\n", + " print(results[\"final_df\"])\n", + "\n", + "await main()\n" + ] + }, { "cell_type": "code", "execution_count": null, diff --git a/hamilton/plugins/h_pandas.py b/hamilton/plugins/h_pandas.py index 722896dcf..bcbc2e2b3 100644 --- a/hamilton/plugins/h_pandas.py +++ b/hamilton/plugins/h_pandas.py @@ -1,9 +1,6 @@ -import inspect import sys -import typing -from collections import defaultdict from types import ModuleType -from typing import Any, Callable, Collection, Dict, List, Tuple, Type, Union +from typing import Any, Callable, Collection, Dict, List, Tuple, Type, Union, get_type_hints _sys_version_info = sys.version_info _version_tuple = (_sys_version_info.major, _sys_version_info.minor, _sys_version_info.micro) @@ -13,17 +10,17 @@ else: pass -import pandas as pd - -# Copied this over from function_graph -# TODO -- determine the best place to put this code -from hamilton import node -from hamilton.function_modifiers import base +from hamilton import node, registry from hamilton.function_modifiers.expanders import extract_columns -from hamilton.function_modifiers.recursive import assign_namespace, prune_nodes, subdag +from hamilton.function_modifiers.recursive import ( + _default_inject_parameter, + subdag, + with_columns_base, +) +from hamilton.plugins.pandas_extensions import DATAFRAME_TYPE -class with_columns(base.NodeInjector): +class with_columns(with_columns_base): """Initializes a with_columns decorator for pandas. This allows you to efficiently run groups of map operations on a dataframe. Here's an example of calling it -- if you've seen ``@subdag``, you should be familiar with @@ -81,69 +78,56 @@ def final_df(initial_df: pd.DataFrame) -> pd.DataFrame: from my_module. It starts with the columns a_from_df and b_from_df, and then adds the columns a, b, and a_plus_b to the dataframe. It then returns the dataframe, and does some processing on it." - In case you need more flexibility you can alternatively use ``pass_dataframe_as``, for example, + In case you need more flexibility you can alternatively use ``on_input``, for example, .. code-block:: python - # with_columns_module.py - def a_from_df(initial_df: pd.Series) -> pd.Series: - return initial_df["a_from_df"] / 100 + # with_columns_module.py + def a_from_df(initial_df: pd.Series) -> pd.Series: + return initial_df["a_from_df"] / 100 def b_from_df(initial_df: pd.Series) -> pd.Series: - return initial_df["b_from_df"] / 100 + return initial_df["b_from_df"] / 100 - # the with_columns call - @with_columns( - *[my_module], - *[a_from_df], - columns_to_pass=["a_from_df", "b_from_df"], - select=["a_from_df", "b_from_df", "a", "b", "a_plus_b", "a_b_average"], - ) - def final_df(initial_df: pd.DataFrame) -> pd.DataFrame: - # process, or just return unprocessed - ... + # the with_columns call + @with_columns( + *[my_module], + *[a_from_df], + on_input="initial_df", + select=["a_from_df", "b_from_df", "a", "b", "a_plus_b", "a_b_average"], + ) + def final_df(initial_df: pd.DataFrame, ...) -> pd.DataFrame: + # process, or just return unprocessed + ... the above would output a dataframe where the two columns ``a_from_df`` and ``b_from_df`` get overwritten. """ - @staticmethod - def _check_for_duplicates(nodes_: List[node.Node]) -> bool: - """Ensures that we don't run into name clashing of columns and group operations. - - In the case when we extract columns for the user, because ``columns_to_pass`` was used, we want - to safeguard against nameclashing with functions that are passed into ``with_columns`` - i.e. - there are no functions that have the same name as the columns. This effectively means that - using ``columns_to_pass`` will only append new columns to the dataframe and for changing - existing columns ``pass_dataframe_as`` needs to be used. - """ - node_counter = defaultdict(int) - for node_ in nodes_: - node_counter[node_.name] += 1 - if node_counter[node_.name] > 1: - return True - return False - def __init__( self, *load_from: Union[Callable, ModuleType], columns_to_pass: List[str] = None, pass_dataframe_as: str = None, + on_input: str = None, select: List[str] = None, namespace: str = None, config_required: List[str] = None, ): - """Instantiates a ``@with_column`` decorator. + """Instantiates a ``@with_columns`` decorator. :param load_from: The functions or modules that will be used to generate the group of map operations. :param columns_to_pass: The initial schema of the dataframe. This is used to determine which upstream inputs should be taken from the dataframe, and which shouldn't. Note that, if this is left empty (and external_inputs is as well), we will assume that all dependencies come - from the dataframe. This cannot be used in conjunction with pass_dataframe_as. - :param pass_dataframe_as: The name of the dataframe that we're modifying, as known to the subdag. + from the dataframe. This cannot be used in conjunction with on_input. + :param on_input: The name of the dataframe that we're modifying, as known to the subdag. If you pass this in, you are responsible for extracting columns out. If not provided, you have - to pass columns_to_pass in, and we will extract the columns out for you. + to pass columns_to_pass in, and we will extract the columns out on the first parameter for you. + :param select: The end nodes that represent columns to be appended to the original dataframe + via with_columns. Existing columns will be overridden. The selected nodes need to have the + corresponding column type, in this case pd.Series, to be appended to the original dataframe. :param namespace: The namespace of the nodes, so they don't clash with the global namespace and so this can be reused. If its left out, there will be no namespace (in which case you'll want to be careful about repeating it/reusing the nodes in other parts of the DAG.) @@ -151,44 +135,28 @@ def __init__( if you want the functions/modules to have access to all possible config. """ - self.subdag_functions = subdag.collect_functions(load_from) - - if select is None: - raise ValueError("Please specify at least one column to append or update.") - else: - self.select = select - - if (pass_dataframe_as is not None and columns_to_pass is not None) or ( - pass_dataframe_as is None and columns_to_pass is None - ): - raise ValueError( - "You must specify only one of columns_to_pass and " - "pass_dataframe_as. " - "This is because specifying pass_dataframe_as injects into " - "the set of columns, allowing you to perform your own extraction" - "from the dataframe. We then execute all columns in the sbudag" - "in order, passing in that initial dataframe. If you want" - "to reference columns in your code, you'll have to specify " - "the set of initial columns, and allow the subdag decorator " - "to inject the dataframe through. The initial columns tell " - "us which parameters to take from that dataframe, so we can" - "feed the right data into the right columns." + if pass_dataframe_as is not None: + raise NotImplementedError( + "We currently do not support pass_dataframe_as for pandas. Please reach out if you need this " + "functionality." ) - self.initial_schema = columns_to_pass - self.dataframe_subdag_param = pass_dataframe_as - self.namespace = namespace - self.config_required = config_required - - def required_config(self) -> List[str]: - return self.config_required + super().__init__( + *load_from, + columns_to_pass=columns_to_pass, + on_input=on_input, + select=select, + namespace=namespace, + config_required=config_required, + dataframe_type=DATAFRAME_TYPE, + ) def _create_column_nodes( - self, inject_parameter: str, params: Dict[str, Type[Type]] + self, fn: Callable, inject_parameter: str, params: Dict[str, Type[Type]] ) -> List[node.Node]: output_type = params[inject_parameter] - def temp_fn(**kwargs) -> pd.DataFrame: + def temp_fn(**kwargs) -> Any: return kwargs[inject_parameter] # We recreate the df node to use extract columns @@ -204,88 +172,68 @@ def temp_fn(**kwargs) -> pd.DataFrame: out_nodes = extract_columns_decorator.transform_node(temp_node, config={}, fn=temp_fn) return out_nodes[1:] - def _get_inital_nodes( + def get_initial_nodes( self, fn: Callable, params: Dict[str, Type[Type]] ) -> Tuple[str, Collection[node.Node]]: """Selects the correct dataframe and optionally extracts out columns.""" - initial_nodes = [] - if self.dataframe_subdag_param is not None: - inject_parameter = self.dataframe_subdag_param - else: - # If we don't have a specified dataframe we assume it's the first argument - sig = inspect.signature(fn) - inject_parameter = list(sig.parameters.values())[0].name - input_types = typing.get_type_hints(fn) - - if not input_types[inject_parameter] == pd.DataFrame: - raise ValueError( - "First argument has to be a pandas DataFrame. If you wish to use a " - "different argument, please use `pass_dataframe_as` option." - ) - - initial_nodes.extend( - self._create_column_nodes(inject_parameter=inject_parameter, params=params) - ) + inject_parameter = _default_inject_parameter(fn=fn, target_dataframe=self.target_dataframe) + with_columns_base.validate_dataframe( + fn=fn, + inject_parameter=inject_parameter, + params=params, + required_type=self.dataframe_type, + ) - if inject_parameter not in params: - raise base.InvalidDecoratorException( - f"Function: {fn.__name__} has a first parameter that is not a dependency. " - f"@with_columns requires the parameter names to match the function parameters. " - f"Thus it might not be compatible with some other decorators" - ) + initial_nodes = ( + [] + if self.target_dataframe is not None + else self._create_column_nodes(fn=fn, inject_parameter=inject_parameter, params=params) + ) return inject_parameter, initial_nodes - def _create_merge_node(self, upstream_node: str, node_name: str) -> node.Node: + def get_subdag_nodes(self, fn: Callable, config: Dict[str, Any]) -> Collection[node.Node]: + return subdag.collect_nodes(config, self.subdag_functions) + + def chain_subdag_nodes( + self, fn: Callable, inject_parameter: str, generated_nodes: Collection[node.Node] + ) -> node.Node: "Node that adds to / overrides columns for the original dataframe based on selected output." + # In case no node is selected we append all possible nodes that have a column type matching + # what the dataframe expects + if self.select is None: + self.select = [ + sink_node.name + for sink_node in generated_nodes + if sink_node.type == registry.get_column_type_from_df_type(self.dataframe_type) + ] def new_callable(**kwargs) -> Any: - df = kwargs[upstream_node] + df = kwargs[inject_parameter] columns_to_append = {} for column in self.select: columns_to_append[column] = kwargs[column] return df.assign(**columns_to_append) - input_map = {column: pd.Series for column in self.select} - input_map[upstream_node] = pd.DataFrame - - return node.Node( - name=node_name, - typ=pd.DataFrame, + column_type = registry.get_column_type_from_df_type(self.dataframe_type) + input_map = {column: column_type for column in self.select} + input_map[inject_parameter] = self.dataframe_type + merge_node = node.Node( + name="_append", + typ=self.dataframe_type, callabl=new_callable, input_types=input_map, ) - - def inject_nodes( - self, params: Dict[str, Type[Type]], config: Dict[str, Any], fn: Callable - ) -> Tuple[List[node.Node], Dict[str, str]]: - namespace = fn.__name__ if self.namespace is None else self.namespace - - inject_parameter, initial_nodes = self._get_inital_nodes(fn=fn, params=params) - - subdag_nodes = subdag.collect_nodes(config, self.subdag_functions) - - if with_columns._check_for_duplicates(initial_nodes + subdag_nodes): - raise ValueError( - "You can only specify columns once. You used `columns_to_pass` and we " - "extract the columns for you. In this case they cannot be overwritten -- only new columns get " - "appended. If you want to modify in-place columns pass in a dataframe and " - "extract + modify the columns and afterwards select them." - ) - - pruned_nodes = prune_nodes(subdag_nodes, self.select) - if len(pruned_nodes) == 0: - raise ValueError( - f"No nodes found upstream from select columns: {self.select} for function: " - f"{fn.__qualname__}" - ) - - merge_node = self._create_merge_node(inject_parameter, node_name="__append") - - output_nodes = initial_nodes + pruned_nodes + [merge_node] - output_nodes = subdag.add_namespace(output_nodes, namespace) - return output_nodes, {inject_parameter: assign_namespace(merge_node.name, namespace)} + output_nodes = generated_nodes + [merge_node] + return output_nodes, merge_node.name def validate(self, fn: Callable): - pass + inject_parameter = _default_inject_parameter(fn=fn, target_dataframe=self.target_dataframe) + params = get_type_hints(fn) + with_columns_base.validate_dataframe( + fn=fn, + inject_parameter=inject_parameter, + params=params, + required_type=self.dataframe_type, + ) diff --git a/plugin_tests/h_pandas/resources/with_columns_end_to_end.py b/plugin_tests/h_pandas/resources/with_columns_end_to_end.py index 16d493e46..58192b119 100644 --- a/plugin_tests/h_pandas/resources/with_columns_end_to_end.py +++ b/plugin_tests/h_pandas/resources/with_columns_end_to_end.py @@ -59,7 +59,9 @@ def col_3(initial_df: pd.DataFrame) -> pd.Series: @with_columns( col_3, - pass_dataframe_as="initial_df", + multiply_3__by_5, + multiply_3__by_7, + on_input="initial_df", select=["col_3", "multiply_3"], ) def final_df_2(initial_df: pd.DataFrame) -> pd.DataFrame: diff --git a/plugin_tests/h_pandas/test_with_columns.py b/plugin_tests/h_pandas/test_with_columns.py index b3a84d666..f9012e718 100644 --- a/plugin_tests/h_pandas/test_with_columns.py +++ b/plugin_tests/h_pandas/test_with_columns.py @@ -8,58 +8,96 @@ from .resources import with_columns_end_to_end -def dummy_fn_with_columns(col_1: pd.Series) -> pd.Series: - return col_1 + 100 +def test__create_column_nodes(): + def dummy_fn_with_columns(col_1: pd.Series) -> pd.Series: + return col_1 + 100 + def dummy_df() -> pd.DataFrame: + return pd.DataFrame({"col_1": [1, 2, 3, 4], "col_2": [11, 12, 13, 14]}) + + def target_fn(upstream_df: pd.DataFrame) -> pd.DataFrame: + return upstream_df + + decorator = with_columns( + dummy_fn_with_columns, columns_to_pass=["col_1", "col_2"], select=["dummy_fn_with_columns"] + ) -def test_detect_duplicate_nodes(): - node_a = node.Node.from_fn(dummy_fn_with_columns, name="a") - node_b = node.Node.from_fn(dummy_fn_with_columns, name="a") - node_c = node.Node.from_fn(dummy_fn_with_columns, name="c") + column_nodes = decorator._create_column_nodes( + fn=target_fn, inject_parameter="upstream_df", params={"upstream_df": pd.DataFrame} + ) + + col1 = column_nodes[0] + col2 = column_nodes[1] + + assert col1.name == "col_1" + assert col2.name == "col_2" + + pd.testing.assert_series_equal( + col1.callable(upstream_df=dummy_df()), + pd.Series([1, 2, 3, 4]), + check_names=False, + ) - if not with_columns._check_for_duplicates([node_a, node_b, node_c]): - raise (AssertionError) + pd.testing.assert_series_equal( + col2.callable(upstream_df=dummy_df()), + pd.Series([11, 12, 13, 14]), + check_names=False, + ) - if with_columns._check_for_duplicates([node_a, node_c]): - raise (AssertionError) +def test__get_initial_nodes_when_extracting_columns(): + def dummy_fn_with_columns(col_1: pd.Series) -> pd.Series: + return col_1 + 100 -def test_select_not_empty(): - error_message = "Please specify at least one column to append or update." + def dummy_df() -> pd.DataFrame: + return pd.DataFrame({"col_1": [1, 2, 3, 4], "col_2": [11, 12, 13, 14]}) - with pytest.raises(ValueError) as e: - with_columns(dummy_fn_with_columns) - assert str(e.value) == error_message + def target_fn(upstream_df: pd.DataFrame) -> pd.DataFrame: + return upstream_df + dummy_node = node.Node.from_fn(target_fn) -def test_columns_to_pass_and_pass_dataframe_as_raises_error(): - error_message = ( - "You must specify only one of columns_to_pass and " - "pass_dataframe_as. " - "This is because specifying pass_dataframe_as injects into " - "the set of columns, allowing you to perform your own extraction" - "from the dataframe. We then execute all columns in the sbudag" - "in order, passing in that initial dataframe. If you want" - "to reference columns in your code, you'll have to specify " - "the set of initial columns, and allow the subdag decorator " - "to inject the dataframe through. The initial columns tell " - "us which parameters to take from that dataframe, so we can" - "feed the right data into the right columns." + decorator = with_columns( + dummy_fn_with_columns, columns_to_pass=["col_1", "col_2"], select=["dummy_fn_with_columns"] ) + injectable_params = NodeInjector.find_injectable_params([dummy_node]) - with pytest.raises(ValueError) as e: - with_columns( - dummy_fn_with_columns, columns_to_pass=["a"], pass_dataframe_as="a", select=["a"] - ) - assert str(e.value) == error_message + inject_parameter, initial_nodes = decorator.get_initial_nodes( + fn=target_fn, params=injectable_params + ) + assert inject_parameter == "upstream_df" + assert len(initial_nodes) == 2 -def test_first_parameter_is_dataframe(): - error_message = ( - "First argument has to be a pandas DataFrame. If you wish to use a " - "different argument, please use `pass_dataframe_as` option." + +def test__get_initial_nodes_when_passing_dataframe(): + def dummy_fn_with_columns(col_1: pd.Series) -> pd.Series: + return col_1 + 100 + + def dummy_df() -> pd.DataFrame: + return pd.DataFrame({"col_1": [1, 2, 3, 4], "col_2": [11, 12, 13, 14]}) + + def target_fn(upstream_df: pd.DataFrame) -> pd.DataFrame: + return upstream_df + + dummy_node = node.Node.from_fn(target_fn) + + decorator = with_columns( + dummy_fn_with_columns, on_input="upstream_df", select=["dummy_fn_with_columns"] + ) + injectable_params = NodeInjector.find_injectable_params([dummy_node]) + inject_parameter, initial_nodes = decorator.get_initial_nodes( + fn=target_fn, params=injectable_params ) + assert inject_parameter == "upstream_df" + assert len(initial_nodes) == 0 + + +def test_first_parameter_is_dataframe(): + def dummy_fn_with_columns(col_1: pd.Series) -> pd.Series: + return col_1 + 100 + def target_fn(upstream_df: int) -> pd.DataFrame: return upstream_df @@ -70,23 +108,25 @@ def target_fn(upstream_df: int) -> pd.DataFrame: ) injectable_params = NodeInjector.find_injectable_params([dummy_node]) - with pytest.raises(ValueError) as e: - decorator._get_inital_nodes(fn=target_fn, params=injectable_params) - - assert str(e.value) == error_message + # Raises error that is not pandas dataframe + with pytest.raises(NotImplementedError): + decorator.get_initial_nodes(fn=target_fn, params=injectable_params) def test_create_column_nodes_pass_dataframe(): + def dummy_fn_with_columns(col_1: pd.Series) -> pd.Series: + return col_1 + 100 + def target_fn(some_var: int, upstream_df: pd.DataFrame) -> pd.DataFrame: return upstream_df dummy_node = node.Node.from_fn(target_fn) decorator = with_columns( - dummy_fn_with_columns, pass_dataframe_as="upstream_df", select=["dummy_fn_with_columns"] + dummy_fn_with_columns, on_input="upstream_df", select=["dummy_fn_with_columns"] ) injectable_params = NodeInjector.find_injectable_params([dummy_node]) - inject_parameter, initial_nodes = decorator._get_inital_nodes( + inject_parameter, initial_nodes = decorator.get_initial_nodes( fn=target_fn, params=injectable_params ) @@ -95,6 +135,9 @@ def target_fn(some_var: int, upstream_df: pd.DataFrame) -> pd.DataFrame: def test_create_column_nodes_extract_single_columns(): + def dummy_fn_with_columns(col_1: pd.Series) -> pd.Series: + return col_1 + 100 + def dummy_df() -> pd.DataFrame: return pd.DataFrame({"col_1": [1, 2, 3, 4], "col_2": [11, 12, 13, 14]}) @@ -107,8 +150,7 @@ def target_fn(upstream_df: pd.DataFrame) -> pd.DataFrame: dummy_fn_with_columns, columns_to_pass=["col_1"], select=["dummy_fn_with_columns"] ) injectable_params = NodeInjector.find_injectable_params([dummy_node]) - - inject_parameter, initial_nodes = decorator._get_inital_nodes( + inject_parameter, initial_nodes = decorator.get_initial_nodes( fn=target_fn, params=injectable_params ) @@ -124,6 +166,9 @@ def target_fn(upstream_df: pd.DataFrame) -> pd.DataFrame: def test_create_column_nodes_extract_multiple_columns(): + def dummy_fn_with_columns(col_1: pd.Series) -> pd.Series: + return col_1 + 100 + def dummy_df() -> pd.DataFrame: return pd.DataFrame({"col_1": [1, 2, 3, 4], "col_2": [11, 12, 13, 14]}) @@ -137,7 +182,7 @@ def target_fn(upstream_df: pd.DataFrame) -> pd.DataFrame: ) injectable_params = NodeInjector.find_injectable_params([dummy_node]) - inject_parameter, initial_nodes = decorator._get_inital_nodes( + inject_parameter, initial_nodes = decorator.get_initial_nodes( fn=target_fn, params=injectable_params ) @@ -160,6 +205,9 @@ def target_fn(upstream_df: pd.DataFrame) -> pd.DataFrame: def test_no_matching_select_column_error(): + def dummy_fn_with_columns(col_1: pd.Series) -> pd.Series: + return col_1 + 100 + def target_fn(upstream_df: pd.DataFrame) -> pd.DataFrame: return upstream_df @@ -171,17 +219,14 @@ def target_fn(upstream_df: pd.DataFrame) -> pd.DataFrame: ) injectable_params = NodeInjector.find_injectable_params([dummy_node]) - error_message = ( - f"No nodes found upstream from select columns: {select} for function: " - f"{target_fn.__qualname__}" - ) - with pytest.raises(ValueError) as e: + with pytest.raises(ValueError): decorator.inject_nodes(injectable_params, {}, fn=target_fn) - assert str(e.value) == error_message - def test_append_into_original_df(): + def dummy_fn_with_columns(col_1: pd.Series) -> pd.Series: + return col_1 + 100 + def dummy_df() -> pd.DataFrame: return pd.DataFrame({"col_1": [1, 2, 3, 4], "col_2": [11, 12, 13, 14]}) @@ -191,13 +236,17 @@ def target_fn(upstream_df: pd.DataFrame) -> pd.DataFrame: decorator = with_columns( dummy_fn_with_columns, columns_to_pass=["col_1", "col_2"], select=["dummy_fn_with_columns"] ) - merge_node = decorator._create_merge_node(upstream_node="upstream_df", node_name="merge_node") + + output_nodes, _ = decorator.chain_subdag_nodes( + fn=target_fn, inject_parameter="upstream_df", generated_nodes=[] + ) + merge_node = output_nodes[-1] output_df = merge_node.callable( upstream_df=dummy_df(), dummy_fn_with_columns=dummy_fn_with_columns(col_1=pd.Series([1, 2, 3, 4])), ) - assert merge_node.name == "merge_node" + assert merge_node.name == "__append" assert merge_node.type == pd.DataFrame pd.testing.assert_series_equal(output_df["col_1"], pd.Series([1, 2, 3, 4]), check_names=False) @@ -219,11 +268,14 @@ def target_fn(upstream_df: pd.DataFrame) -> pd.DataFrame: def col_1() -> pd.Series: return pd.Series([0, 3, 5, 7]) - decorator = with_columns(col_1, pass_dataframe_as=["upstream_df"], select=["col_1"]) - merge_node = decorator._create_merge_node(upstream_node="upstream_df", node_name="merge_node") + decorator = with_columns(col_1, on_input="upstream_df", select=["col_1"]) + output_nodes, _ = decorator.chain_subdag_nodes( + fn=target_fn, inject_parameter="upstream_df", generated_nodes=[] + ) + merge_node = output_nodes[-1] output_df = merge_node.callable(upstream_df=dummy_df(), col_1=col_1()) - assert merge_node.name == "merge_node" + assert merge_node.name == "__append" assert merge_node.type == pd.DataFrame pd.testing.assert_series_equal(output_df["col_1"], pd.Series([0, 3, 5, 7]), check_names=False) @@ -233,6 +285,9 @@ def col_1() -> pd.Series: def test_assign_custom_namespace_with_columns(): + def dummy_fn_with_columns(col_1: pd.Series) -> pd.Series: + return col_1 + 100 + def target_fn(upstream_df: pd.DataFrame) -> pd.DataFrame: return upstream_df @@ -244,12 +299,11 @@ def target_fn(upstream_df: pd.DataFrame) -> pd.DataFrame: namespace="dummy_namespace", ) nodes_ = decorator.transform_dag([dummy_node], {}, target_fn) - + print(nodes_) assert nodes_[0].name == "target_fn" - assert nodes_[1].name == "dummy_namespace.col_1" - assert nodes_[2].name == "dummy_namespace.col_2" - assert nodes_[3].name == "dummy_namespace.dummy_fn_with_columns" - assert nodes_[4].name == "dummy_namespace.__append" + assert nodes_[1].name == "dummy_namespace.dummy_fn_with_columns" + assert nodes_[2].name == "dummy_namespace.col_1" + assert nodes_[3].name == "dummy_namespace.__append" def test_end_to_end_with_columns_automatic_extract(): From 7002e5d03ff63243723b1c9c985cf342f522402c Mon Sep 17 00:00:00 2001 From: jernejfrank Date: Sun, 24 Nov 2024 11:10:44 +0800 Subject: [PATCH 5/6] Add h_polars.with_columns Supporting now using with_columns for both polars eager and lazy execution. Inherits from with_columns_base. Some functionality is shared with h_pandas.with_columns -- TODO: refactor out common logic when appropriate. --- examples/polars/notebook.ipynb | 240 ++-- .../polars/with_columns/DAG_DataFrame.png | Bin 0 -> 118573 bytes examples/polars/with_columns/DAG_lazy.png | Bin 0 -> 118985 bytes examples/polars/with_columns/README | 8 + examples/polars/with_columns/my_functions.py | 51 + .../polars/with_columns/my_functions_lazy.py | 47 + examples/polars/with_columns/notebook.ipynb | 1239 +++++++++++++++++ hamilton/plugins/h_polars.py | 236 +++- hamilton/plugins/h_polars_lazyframe.py | 223 ++- plugin_tests/h_polars/__init__.py | 0 plugin_tests/h_polars/conftest.py | 4 + plugin_tests/h_polars/resources/__init__.py | 0 .../resources/with_columns_end_to_end.py | 68 + .../resources/with_columns_end_to_end_lazy.py | 80 ++ plugin_tests/h_polars/test_with_columns.py | 265 ++++ .../h_polars/test_with_columns_lazy.py | 64 + 16 files changed, 2402 insertions(+), 123 deletions(-) create mode 100644 examples/polars/with_columns/DAG_DataFrame.png create mode 100644 examples/polars/with_columns/DAG_lazy.png create mode 100644 examples/polars/with_columns/README create mode 100644 examples/polars/with_columns/my_functions.py create mode 100644 examples/polars/with_columns/my_functions_lazy.py create mode 100644 examples/polars/with_columns/notebook.ipynb create mode 100644 plugin_tests/h_polars/__init__.py create mode 100644 plugin_tests/h_polars/conftest.py create mode 100644 plugin_tests/h_polars/resources/__init__.py create mode 100644 plugin_tests/h_polars/resources/with_columns_end_to_end.py create mode 100644 plugin_tests/h_polars/resources/with_columns_end_to_end_lazy.py create mode 100644 plugin_tests/h_polars/test_with_columns.py create mode 100644 plugin_tests/h_polars/test_with_columns_lazy.py diff --git a/examples/polars/notebook.ipynb b/examples/polars/notebook.ipynb index c8cad7e44..c81678590 100644 --- a/examples/polars/notebook.ipynb +++ b/examples/polars/notebook.ipynb @@ -38,8 +38,10 @@ "name": "stderr", "output_type": "stream", "text": [ - "/Users/stefankrawczyk/.pyenv/versions/knowledge_retrieval-py39/lib/python3.9/site-packages/pyspark/pandas/__init__.py:50: UserWarning: 'PYARROW_IGNORE_TIMEZONE' environment variable was not set. It is required to set this environment variable to '1' in both driver and executor sides if you use pyarrow>=2.0.0. pandas-on-Spark will set it for you but it does not work if there is a Spark context already launched.\n", - " warnings.warn(\n" + "/Users/jernejfrank/miniconda3/envs/hamilton/lib/python3.10/site-packages/pyspark/pandas/__init__.py:50: UserWarning: 'PYARROW_IGNORE_TIMEZONE' environment variable was not set. It is required to set this environment variable to '1' in both driver and executor sides if you use pyarrow>=2.0.0. pandas-on-Spark will set it for you but it does not work if there is a Spark context already launched.\n", + " warnings.warn(\n", + "/Users/jernejfrank/miniconda3/envs/hamilton/lib/python3.10/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n", + " from .autonotebook import tqdm as notebook_tqdm\n" ] } ], @@ -70,177 +72,177 @@ "\n", "\n", - "\n", "\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "\n", "\n", "cluster__legend\n", - "\n", - "Legend\n", + "\n", + "Legend\n", "\n", - "\n", + "\n", "\n", + "spend_zero_mean\n", + "\n", + "spend_zero_mean\n", + "Series\n", + "\n", + "\n", + "\n", + "spend_zero_mean_unit_variance\n", + "\n", + "spend_zero_mean_unit_variance\n", + "Series\n", + "\n", + "\n", + "\n", + "spend_zero_mean->spend_zero_mean_unit_variance\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "spend_mean\n", + "\n", + "spend_mean\n", + "float\n", + "\n", + "\n", + "\n", + "spend_mean->spend_zero_mean\n", + "\n", + "\n", + "\n", + "\n", + "\n", "spend_per_signup\n", "\n", "spend_per_signup\n", "Series\n", "\n", "\n", - "\n", + "\n", "avg_3wk_spend\n", - "\n", - "avg_3wk_spend\n", - "Series\n", + "\n", + "avg_3wk_spend\n", + "Series\n", "\n", - "\n", - "\n", - "spend\n", - "\n", - "spend\n", - "Series\n", + "\n", + "\n", + "base_df\n", + "\n", + "base_df\n", + "DataFrame\n", "\n", - "\n", - "\n", - "spend->spend_per_signup\n", - "\n", - "\n", + "\n", + "\n", + "signups\n", + "\n", + "signups\n", + "Series\n", "\n", - "\n", - "\n", - "spend->avg_3wk_spend\n", - "\n", - "\n", + "\n", + "\n", + "base_df->signups\n", + "\n", + "\n", "\n", - "\n", - "\n", - "spend_mean\n", - "\n", - "spend_mean\n", - "float\n", + "\n", + "\n", + "spend\n", + "\n", + "spend\n", + "Series\n", "\n", - "\n", - "\n", - "spend->spend_mean\n", - "\n", - "\n", + "\n", + "\n", + "base_df->spend\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "spend_std_dev\n", "\n", "spend_std_dev\n", "float\n", "\n", - "\n", + "\n", "\n", - "spend->spend_std_dev\n", - "\n", - "\n", + "spend_std_dev->spend_zero_mean_unit_variance\n", + "\n", + "\n", "\n", - "\n", - "\n", - "spend_zero_mean\n", - "\n", - "spend_zero_mean\n", - "Series\n", + "\n", + "\n", + "signups->spend_per_signup\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "spend->spend_zero_mean\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "spend_mean->spend_zero_mean\n", - "\n", - "\n", + "\n", + "\n", "\n", - "\n", - "\n", - "base_df\n", - "\n", - "base_df\n", - "DataFrame\n", + "\n", + "\n", + "spend->spend_mean\n", + "\n", + "\n", "\n", - "\n", + "\n", "\n", - "base_df->spend\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "signups\n", - "\n", - "signups\n", - "Series\n", + "spend->spend_per_signup\n", + "\n", + "\n", "\n", - "\n", + "\n", "\n", - "base_df->signups\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "spend_zero_mean_unit_variance\n", - "\n", - "spend_zero_mean_unit_variance\n", - "Series\n", - "\n", - "\n", - "\n", - "spend_std_dev->spend_zero_mean_unit_variance\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "signups->spend_per_signup\n", - "\n", - "\n", + "spend->avg_3wk_spend\n", + "\n", + "\n", "\n", - "\n", - "\n", - "spend_zero_mean->spend_zero_mean_unit_variance\n", - "\n", - "\n", + "\n", + "\n", + "spend->spend_std_dev\n", + "\n", + "\n", "\n", "\n", "\n", "_base_df_inputs\n", - "\n", - "base_df_location\n", - "str\n", + "\n", + "base_df_location\n", + "str\n", "\n", "\n", - "\n", + "\n", "_base_df_inputs->base_df\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "input\n", - "\n", - "input\n", + "\n", + "input\n", "\n", "\n", "\n", "function\n", - "\n", - "function\n", + "\n", + "function\n", "\n", "\n", "\n" ], "text/plain": [ - "" + "" ] }, "metadata": {}, @@ -777,7 +779,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3 (ipykernel)", + "display_name": "hamilton", "language": "python", "name": "python3" }, @@ -791,7 +793,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.9" + "version": "3.10.14" } }, "nbformat": 4, diff --git a/examples/polars/with_columns/DAG_DataFrame.png b/examples/polars/with_columns/DAG_DataFrame.png new file mode 100644 index 0000000000000000000000000000000000000000..cc3d713b73dd3e507ecb9f067ddb0935afe95d86 GIT binary patch literal 118573 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%0D?b&{mrM7N&)}ZxzOJ$fkGZ; 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 <*Y`~!%T7~MDn)_SdQu5a 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%0Ay9;GBqXEYNPHW42tOpbwn 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 literal 0 HcmV?d00001 diff --git a/examples/polars/with_columns/README b/examples/polars/with_columns/README new file mode 100644 index 000000000..86db77204 --- /dev/null +++ b/examples/polars/with_columns/README @@ -0,0 +1,8 @@ +# Using with_columns with Polars + +We show the ability to use the familiar `with_columns` from `polars`. Supported for both `pl.DataFrame` and `pl.LazyFrame`. + +To see the example look at the notebook. + +![image info](./DAG_DataFrame.png) +![image info](./DAG_lazy.png) diff --git a/examples/polars/with_columns/my_functions.py b/examples/polars/with_columns/my_functions.py new file mode 100644 index 000000000..3b2c401b9 --- /dev/null +++ b/examples/polars/with_columns/my_functions.py @@ -0,0 +1,51 @@ +import polars as pl + +from hamilton.function_modifiers import config + +""" +Notes: + 1. This file is used for all the [ray|dask|spark]/hello_world examples. + 2. It therefore show cases how you can write something once and not only scale it, but port it + to different frameworks with ease! +""" + + +@config.when(case="millions") +def avg_3wk_spend__millions(spend: pl.Series) -> pl.Series: + """Rolling 3 week average spend.""" + return ( + spend.to_frame("spend").select(pl.col("spend").rolling_mean(window_size=3) / 1e6) + ).to_series(0) + + +@config.when(case="thousands") +def avg_3wk_spend__thousands(spend: pl.Series) -> pl.Series: + """Rolling 3 week average spend.""" + return ( + spend.to_frame("spend").select(pl.col("spend").rolling_mean(window_size=3) / 1e3) + ).to_series(0) + + +def spend_per_signup(spend: pl.Series, signups: pl.Series) -> pl.Series: + """The cost per signup in relation to spend.""" + return spend / signups + + +def spend_mean(spend: pl.Series) -> float: + """Shows function creating a scalar. In this case it computes the mean of the entire column.""" + return spend.mean() + + +def spend_zero_mean(spend: pl.Series, spend_mean: float) -> pl.Series: + """Shows function that takes a scalar. In this case to zero mean spend.""" + return spend - spend_mean + + +def spend_std_dev(spend: pl.Series) -> float: + """Function that computes the standard deviation of the spend column.""" + return spend.std() + + +def spend_zero_mean_unit_variance(spend_zero_mean: pl.Series, spend_std_dev: float) -> pl.Series: + """Function showing one way to make spend have zero mean and unit variance.""" + return spend_zero_mean / spend_std_dev diff --git a/examples/polars/with_columns/my_functions_lazy.py b/examples/polars/with_columns/my_functions_lazy.py new file mode 100644 index 000000000..4b65b2ac2 --- /dev/null +++ b/examples/polars/with_columns/my_functions_lazy.py @@ -0,0 +1,47 @@ +import polars as pl + +from hamilton.function_modifiers import config + +""" +Notes: + 1. This file is used for all the [ray|dask|spark]/hello_world examples. + 2. It therefore show cases how you can write something once and not only scale it, but port it + to different frameworks with ease! +""" + + +@config.when(case="millions") +def avg_3wk_spend__millions(spend: pl.Expr) -> pl.Expr: + """Rolling 3 week average spend.""" + return spend.rolling_mean(window_size=3) / 1e6 + + +@config.when(case="thousands") +def avg_3wk_spend__thousands(spend: pl.Expr) -> pl.Expr: + """Rolling 3 week average spend.""" + return spend.rolling_mean(window_size=3) / 1e3 + + +def spend_per_signup(spend: pl.Expr, signups: pl.Expr) -> pl.Expr: + """The cost per signup in relation to spend.""" + return spend / signups + + +def spend_mean(spend: pl.Expr) -> float: + """Shows function creating a scalar. In this case it computes the mean of the entire column.""" + return spend.mean() + + +def spend_zero_mean(spend: pl.Expr, spend_mean: float) -> pl.Expr: + """Shows function that takes a scalar. In this case to zero mean spend.""" + return spend - spend_mean + + +def spend_std_dev(spend: pl.Expr) -> float: + """Function that computes the standard deviation of the spend column.""" + return spend.std() + + +def spend_zero_mean_unit_variance(spend_zero_mean: pl.Expr, spend_std_dev: float) -> pl.Expr: + """Function showing one way to make spend have zero mean and unit variance.""" + return spend_zero_mean / spend_std_dev diff --git a/examples/polars/with_columns/notebook.ipynb b/examples/polars/with_columns/notebook.ipynb new file mode 100644 index 000000000..39bd66d35 --- /dev/null +++ b/examples/polars/with_columns/notebook.ipynb @@ -0,0 +1,1239 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Execute this cell to install dependencies\n", + "%pip install sf-hamilton[visualization]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Example of using with_columns for Polars DataFrame [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/dagworks-inc/hamilton/blob/main/examples/polars/with_columns/notebook.ipynb) [![GitHub badge](https://img.shields.io/badge/github-view_source-2b3137?logo=github)](https://github.com/dagworks-inc/hamilton/blob/main/examples/polars/with_columns/notebook.ipynb)\n", + "\n", + "This allows you to efficiently run groups of map operations on a dataframe.\n", + "Here's an example of calling it -- if you've seen `@subdag`, you should be familiar with the concepts." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/Users/jernejfrank/miniconda3/envs/hamilton/lib/python3.10/site-packages/pyspark/pandas/__init__.py:50: UserWarning: 'PYARROW_IGNORE_TIMEZONE' environment variable was not set. It is required to set this environment variable to '1' in both driver and executor sides if you use pyarrow>=2.0.0. pandas-on-Spark will set it for you but it does not work if there is a Spark context already launched.\n", + " warnings.warn(\n" + ] + } + ], + "source": [ + "%reload_ext hamilton.plugins.jupyter_magic\n", + "from hamilton import driver\n", + "import my_functions\n", + "\n", + "my_builder = driver.Builder().with_modules(my_functions).with_config({\"case\":\"thousands\"})\n", + "output_node = [\"final_df\"]" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "cluster__legend\n", + "\n", + "Legend\n", + "\n", + "\n", + "\n", + "case\n", + "\n", + "\n", + "\n", + "case\n", + "thousands\n", + "\n", + "\n", + "\n", + "final_df.spend\n", + "\n", + "final_df.spend\n", + "Series\n", + "\n", + "\n", + "\n", + "final_df.spend_std_dev\n", + "\n", + "final_df.spend_std_dev\n", + "float\n", + "\n", + "\n", + "\n", + "final_df.spend->final_df.spend_std_dev\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "final_df.spend_per_signup\n", + "\n", + "final_df.spend_per_signup\n", + "Series\n", + "\n", + "\n", + "\n", + "final_df.spend->final_df.spend_per_signup\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "final_df.__append\n", + "\n", + "final_df.__append\n", + "DataFrame\n", + "\n", + "\n", + "\n", + "final_df.spend->final_df.__append\n", + "\n", + "\n", + "\n", + "\n", + "final_df.spend_zero_mean\n", + "\n", + "final_df.spend_zero_mean\n", + "Series\n", + "\n", + "\n", + "\n", + "final_df.spend->final_df.spend_zero_mean\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "final_df.spend_mean\n", + "\n", + "final_df.spend_mean\n", + "float\n", + "\n", + "\n", + "\n", + "final_df.spend->final_df.spend_mean\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "final_df.avg_3wk_spend\n", + "\n", + "final_df.avg_3wk_spend: case\n", + "Series\n", + "\n", + "\n", + "\n", + "final_df.spend->final_df.avg_3wk_spend\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "final_df.spend_zero_mean_unit_variance\n", + "\n", + "final_df.spend_zero_mean_unit_variance\n", + "Series\n", + "\n", + "\n", + "\n", + "final_df.spend_zero_mean_unit_variance->final_df.__append\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "final_df\n", + "\n", + "final_df\n", + "DataFrame\n", + "\n", + "\n", + "\n", + "final_df.spend_std_dev->final_df.spend_zero_mean_unit_variance\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "initial_df\n", + "\n", + "initial_df\n", + "DataFrame\n", + "\n", + "\n", + "\n", + "initial_df->final_df.spend\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "final_df.signups\n", + "\n", + "final_df.signups\n", + "Series\n", + "\n", + "\n", + "\n", + "initial_df->final_df.signups\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "initial_df->final_df.__append\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "final_df.spend_per_signup->final_df.__append\n", + "\n", + "\n", + "\n", + "\n", + "final_df.signups->final_df.spend_per_signup\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "final_df.signups->final_df.__append\n", + "\n", + "\n", + "\n", + "\n", + "final_df.__append->final_df\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "final_df.spend_zero_mean->final_df.spend_zero_mean_unit_variance\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "final_df.spend_zero_mean->final_df.__append\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "final_df.spend_mean->final_df.spend_zero_mean\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "final_df.avg_3wk_spend->final_df.__append\n", + "\n", + "\n", + "\n", + "\n", + "config\n", + "\n", + "\n", + "\n", + "config\n", + "\n", + "\n", + "\n", + "function\n", + "\n", + "function\n", + "\n", + "\n", + "\n", + "output\n", + "\n", + "output\n", + "\n", + "\n", + "\n" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "%%cell_to_module with_columns_example --builder my_builder --display --execute output_node\n", + "import polars as pl\n", + "from hamilton.plugins.h_polars import with_columns\n", + "import my_functions\n", + "\n", + "output_columns = [\n", + " \"spend\",\n", + " \"signups\",\n", + " \"avg_3wk_spend\",\n", + " \"spend_per_signup\",\n", + " \"spend_zero_mean_unit_variance\",\n", + "]\n", + "\n", + "def initial_df()->pl.DataFrame:\n", + " return pl.DataFrame(\n", + " { \n", + " \"signups\": pl.Series([1, 10, 50, 100, 200, 400]),\n", + " \"spend\": pl.Series([10, 10, 20, 40, 40, 50])*1e6,\n", + " }\n", + " )\n", + "\n", + "# the with_columns call\n", + "@with_columns(\n", + " *[my_functions],\n", + " columns_to_pass=[\"spend\", \"signups\"], # The columns to select from the dataframe\n", + " # select=output_columns, # The columns to append to the dataframe\n", + " # config_required = [\"a\"]\n", + ")\n", + "def final_df(initial_df: pl.DataFrame) -> pl.DataFrame:\n", + " return initial_df" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "shape: (6, 6)\n", + "┌─────────┬───────┬───────────────┬──────────────────┬─────────────────┬───────────────────────────┐\n", + "│ signups ┆ spend ┆ avg_3wk_spend ┆ spend_per_signup ┆ spend_zero_mean ┆ spend_zero_mean_unit_vari │\n", + "│ --- ┆ --- ┆ --- ┆ --- ┆ --- ┆ ance │\n", + "│ i64 ┆ f64 ┆ f64 ┆ f64 ┆ f64 ┆ --- │\n", + "│ ┆ ┆ ┆ ┆ ┆ f64 │\n", + "╞═════════╪═══════╪═══════════════╪══════════════════╪═════════════════╪═══════════════════════════╡\n", + "│ 1 ┆ 1e7 ┆ null ┆ 1e7 ┆ -1.8333e7 ┆ -1.064405 │\n", + "│ 10 ┆ 1e7 ┆ null ┆ 1e6 ┆ -1.8333e7 ┆ -1.064405 │\n", + "│ 50 ┆ 2e7 ┆ 13.333333 ┆ 400000.0 ┆ -8.3333e6 ┆ -0.483821 │\n", + "│ 100 ┆ 4e7 ┆ 23.333333 ┆ 400000.0 ┆ 1.1667e7 ┆ 0.677349 │\n", + "│ 200 ┆ 4e7 ┆ 33.333333 ┆ 200000.0 ┆ 1.1667e7 ┆ 0.677349 │\n", + "│ 400 ┆ 5e7 ┆ 43.333333 ┆ 125000.0 ┆ 2.1667e7 ┆ 1.257934 │\n", + "└─────────┴───────┴───────────────┴──────────────────┴─────────────────┴───────────────────────────┘\n" + ] + }, + { + "data": { + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "cluster__legend\n", + "\n", + "Legend\n", + "\n", + "\n", + "\n", + "case\n", + "\n", + "\n", + "\n", + "case\n", + "millions\n", + "\n", + "\n", + "\n", + "final_df.spend\n", + "\n", + "final_df.spend\n", + "Series\n", + "\n", + "\n", + "\n", + "final_df.spend_std_dev\n", + "\n", + "final_df.spend_std_dev\n", + "float\n", + "\n", + "\n", + "\n", + "final_df.spend->final_df.spend_std_dev\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "final_df.spend_per_signup\n", + "\n", + "final_df.spend_per_signup\n", + "Series\n", + "\n", + "\n", + "\n", + "final_df.spend->final_df.spend_per_signup\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "final_df.__append\n", + "\n", + "final_df.__append\n", + "DataFrame\n", + "\n", + "\n", + "\n", + "final_df.spend->final_df.__append\n", + "\n", + "\n", + "\n", + "\n", + "final_df.spend_zero_mean\n", + "\n", + "final_df.spend_zero_mean\n", + "Series\n", + "\n", + "\n", + "\n", + "final_df.spend->final_df.spend_zero_mean\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "final_df.spend_mean\n", + "\n", + "final_df.spend_mean\n", + "float\n", + "\n", + "\n", + "\n", + "final_df.spend->final_df.spend_mean\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "final_df.avg_3wk_spend\n", + "\n", + "final_df.avg_3wk_spend: case\n", + "Series\n", + "\n", + "\n", + "\n", + "final_df.spend->final_df.avg_3wk_spend\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "final_df.spend_zero_mean_unit_variance\n", + "\n", + "final_df.spend_zero_mean_unit_variance\n", + "Series\n", + "\n", + "\n", + "\n", + "final_df.spend_zero_mean_unit_variance->final_df.__append\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "final_df\n", + "\n", + "final_df\n", + "DataFrame\n", + "\n", + "\n", + "\n", + "final_df.spend_std_dev->final_df.spend_zero_mean_unit_variance\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "initial_df\n", + "\n", + "initial_df\n", + "DataFrame\n", + "\n", + "\n", + "\n", + "initial_df->final_df.spend\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "final_df.signups\n", + "\n", + "final_df.signups\n", + "Series\n", + "\n", + "\n", + "\n", + "initial_df->final_df.signups\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "initial_df->final_df.__append\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "final_df.spend_per_signup->final_df.__append\n", + "\n", + "\n", + "\n", + "\n", + "final_df.signups->final_df.spend_per_signup\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "final_df.signups->final_df.__append\n", + "\n", + "\n", + "\n", + "\n", + "final_df.__append->final_df\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "final_df.spend_zero_mean->final_df.spend_zero_mean_unit_variance\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "final_df.spend_zero_mean->final_df.__append\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "final_df.spend_mean->final_df.spend_zero_mean\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "final_df.avg_3wk_spend->final_df.__append\n", + "\n", + "\n", + "\n", + "\n", + "config\n", + "\n", + "\n", + "\n", + "config\n", + "\n", + "\n", + "\n", + "function\n", + "\n", + "function\n", + "\n", + "\n", + "\n", + "output\n", + "\n", + "output\n", + "\n", + "\n", + "\n" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import with_columns_example\n", + "dr = driver.Builder().with_modules(my_functions, with_columns_example).with_config({\"case\":\"millions\"}).build()\n", + "print(dr.execute(final_vars=[\"final_df\"])[\"final_df\"])\n", + "dr.visualize_execution(final_vars=[\"final_df\"])\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Example of using with_columns for Polars LazyFrame\n", + "\n", + "This allows you to efficiently run groups of map operations on a dataframe.\n", + "Here's an example of calling it -- if you've seen `@subdag`, you should be familiar with the concepts." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "%reload_ext hamilton.plugins.jupyter_magic\n", + "from hamilton import driver\n", + "import my_functions_lazy\n", + "\n", + "my_builder_lazy = driver.Builder().with_modules(my_functions_lazy).with_config({\"case\":\"thousands\"})\n", + "output_node = [\"final_df\"]" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "cluster__legend\n", + "\n", + "Legend\n", + "\n", + "\n", + "\n", + "case\n", + "\n", + "\n", + "\n", + "case\n", + "thousands\n", + "\n", + "\n", + "\n", + "final_df.spend\n", + "\n", + "final_df.spend\n", + "Expr\n", + "\n", + "\n", + "\n", + "final_df.spend_std_dev\n", + "\n", + "final_df.spend_std_dev\n", + "float\n", + "\n", + "\n", + "\n", + "final_df.spend->final_df.spend_std_dev\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "final_df.spend_per_signup\n", + "\n", + "final_df.spend_per_signup\n", + "Expr\n", + "\n", + "\n", + "\n", + "final_df.spend->final_df.spend_per_signup\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "final_df.__append\n", + "\n", + "final_df.__append\n", + "LazyFrame\n", + "\n", + "\n", + "\n", + "final_df.spend->final_df.__append\n", + "\n", + "\n", + "\n", + "\n", + "final_df.spend_zero_mean\n", + "\n", + "final_df.spend_zero_mean\n", + "Expr\n", + "\n", + "\n", + "\n", + "final_df.spend->final_df.spend_zero_mean\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "final_df.spend_mean\n", + "\n", + "final_df.spend_mean\n", + "float\n", + "\n", + "\n", + "\n", + "final_df.spend->final_df.spend_mean\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "final_df.avg_3wk_spend\n", + "\n", + "final_df.avg_3wk_spend: case\n", + "Expr\n", + "\n", + "\n", + "\n", + "final_df.spend->final_df.avg_3wk_spend\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "final_df.spend_zero_mean_unit_variance\n", + "\n", + "final_df.spend_zero_mean_unit_variance\n", + "Expr\n", + "\n", + "\n", + "\n", + "final_df.spend_zero_mean_unit_variance->final_df.__append\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "final_df\n", + "\n", + "final_df\n", + "LazyFrame\n", + "\n", + "\n", + "\n", + "final_df.spend_std_dev->final_df.spend_zero_mean_unit_variance\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "initial_df\n", + "\n", + "initial_df\n", + "LazyFrame\n", + "\n", + "\n", + "\n", + "initial_df->final_df.spend\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "final_df.signups\n", + "\n", + "final_df.signups\n", + "Expr\n", + "\n", + "\n", + "\n", + "initial_df->final_df.signups\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "initial_df->final_df.__append\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "final_df.spend_per_signup->final_df.__append\n", + "\n", + "\n", + "\n", + "\n", + "final_df.signups->final_df.spend_per_signup\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "final_df.signups->final_df.__append\n", + "\n", + "\n", + "\n", + "\n", + "final_df.__append->final_df\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "final_df.spend_zero_mean->final_df.spend_zero_mean_unit_variance\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "final_df.spend_zero_mean->final_df.__append\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "final_df.spend_mean->final_df.spend_zero_mean\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "final_df.avg_3wk_spend->final_df.__append\n", + "\n", + "\n", + "\n", + "\n", + "config\n", + "\n", + "\n", + "\n", + "config\n", + "\n", + "\n", + "\n", + "function\n", + "\n", + "function\n", + "\n", + "\n", + "\n", + "output\n", + "\n", + "output\n", + "\n", + "\n", + "\n" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "%%cell_to_module with_columns_lazy_example --builder my_builder_lazy --display --execute output_node\n", + "import polars as pl\n", + "from hamilton.plugins.h_polars_lazyframe import with_columns\n", + "import my_functions_lazy\n", + "\n", + "output_columns = [\n", + " \"spend\",\n", + " \"signups\",\n", + " \"avg_3wk_spend\",\n", + " \"spend_per_signup\",\n", + " \"spend_zero_mean_unit_variance\",\n", + "]\n", + "\n", + "def initial_df()->pl.LazyFrame:\n", + " return pl.DataFrame(\n", + " { \n", + " \"signups\": pl.Series([1, 10, 50, 100, 200, 400]),\n", + " \"spend\": pl.Series([10, 10, 20, 40, 40, 50])*1e6,\n", + " }\n", + " ).lazy()\n", + "\n", + "# the with_columns call\n", + "@with_columns(\n", + " *[my_functions_lazy],\n", + " columns_to_pass=[\"spend\", \"signups\"], # The columns to select from the dataframe\n", + " # select=output_columns, # The columns to append to the dataframe\n", + " # config_required = [\"a\"]\n", + ")\n", + "def final_df(initial_df: pl.LazyFrame) -> pl.LazyFrame:\n", + " return initial_df" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "shape: (6, 6)\n", + "┌─────────┬───────┬───────────────┬──────────────────┬─────────────────┬───────────────────────────┐\n", + "│ signups ┆ spend ┆ avg_3wk_spend ┆ spend_per_signup ┆ spend_zero_mean ┆ spend_zero_mean_unit_vari │\n", + "│ --- ┆ --- ┆ --- ┆ --- ┆ --- ┆ ance │\n", + "│ i64 ┆ f64 ┆ f64 ┆ f64 ┆ f64 ┆ --- │\n", + "│ ┆ ┆ ┆ ┆ ┆ f64 │\n", + "╞═════════╪═══════╪═══════════════╪══════════════════╪═════════════════╪═══════════════════════════╡\n", + "│ 1 ┆ 1e7 ┆ null ┆ 1e7 ┆ -1.8333e7 ┆ -1.064405 │\n", + "│ 10 ┆ 1e7 ┆ null ┆ 1e6 ┆ -1.8333e7 ┆ -1.064405 │\n", + "│ 50 ┆ 2e7 ┆ 13.333333 ┆ 400000.0 ┆ -8.3333e6 ┆ -0.483821 │\n", + "│ 100 ┆ 4e7 ┆ 23.333333 ┆ 400000.0 ┆ 1.1667e7 ┆ 0.677349 │\n", + "│ 200 ┆ 4e7 ┆ 33.333333 ┆ 200000.0 ┆ 1.1667e7 ┆ 0.677349 │\n", + "│ 400 ┆ 5e7 ┆ 43.333333 ┆ 125000.0 ┆ 2.1667e7 ┆ 1.257934 │\n", + "└─────────┴───────┴───────────────┴──────────────────┴─────────────────┴───────────────────────────┘\n" + ] + }, + { + "data": { + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "cluster__legend\n", + "\n", + "Legend\n", + "\n", + "\n", + "\n", + "case\n", + "\n", + "\n", + "\n", + "case\n", + "millions\n", + "\n", + "\n", + "\n", + "final_df.spend\n", + "\n", + "final_df.spend\n", + "Expr\n", + "\n", + "\n", + "\n", + "final_df.spend_std_dev\n", + "\n", + "final_df.spend_std_dev\n", + "float\n", + "\n", + "\n", + "\n", + "final_df.spend->final_df.spend_std_dev\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "final_df.spend_per_signup\n", + "\n", + "final_df.spend_per_signup\n", + "Expr\n", + "\n", + "\n", + "\n", + "final_df.spend->final_df.spend_per_signup\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "final_df.__append\n", + "\n", + "final_df.__append\n", + "LazyFrame\n", + "\n", + "\n", + "\n", + "final_df.spend->final_df.__append\n", + "\n", + "\n", + "\n", + "\n", + "final_df.spend_zero_mean\n", + "\n", + "final_df.spend_zero_mean\n", + "Expr\n", + "\n", + "\n", + "\n", + "final_df.spend->final_df.spend_zero_mean\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "final_df.spend_mean\n", + "\n", + "final_df.spend_mean\n", + "float\n", + "\n", + "\n", + "\n", + "final_df.spend->final_df.spend_mean\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "final_df.avg_3wk_spend\n", + "\n", + "final_df.avg_3wk_spend: case\n", + "Expr\n", + "\n", + "\n", + "\n", + "final_df.spend->final_df.avg_3wk_spend\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "final_df.spend_zero_mean_unit_variance\n", + "\n", + "final_df.spend_zero_mean_unit_variance\n", + "Expr\n", + "\n", + "\n", + "\n", + "final_df.spend_zero_mean_unit_variance->final_df.__append\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "final_df\n", + "\n", + "final_df\n", + "LazyFrame\n", + "\n", + "\n", + "\n", + "final_df.spend_std_dev->final_df.spend_zero_mean_unit_variance\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "initial_df\n", + "\n", + "initial_df\n", + "LazyFrame\n", + "\n", + "\n", + "\n", + "initial_df->final_df.spend\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "final_df.signups\n", + "\n", + "final_df.signups\n", + "Expr\n", + "\n", + "\n", + "\n", + "initial_df->final_df.signups\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "initial_df->final_df.__append\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "final_df.spend_per_signup->final_df.__append\n", + "\n", + "\n", + "\n", + "\n", + "final_df.signups->final_df.spend_per_signup\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "final_df.signups->final_df.__append\n", + "\n", + "\n", + "\n", + "\n", + "final_df.__append->final_df\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "final_df.spend_zero_mean->final_df.spend_zero_mean_unit_variance\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "final_df.spend_zero_mean->final_df.__append\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "final_df.spend_mean->final_df.spend_zero_mean\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "final_df.avg_3wk_spend->final_df.__append\n", + "\n", + "\n", + "\n", + "\n", + "config\n", + "\n", + "\n", + "\n", + "config\n", + "\n", + "\n", + "\n", + "function\n", + "\n", + "function\n", + "\n", + "\n", + "\n", + "output\n", + "\n", + "output\n", + "\n", + "\n", + "\n" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import with_columns_lazy_example\n", + "from hamilton import base\n", + "from hamilton.plugins import h_polars\n", + "\n", + "dr = (\n", + " driver.Builder()\n", + " .with_adapter(\n", + " adapter=base.SimplePythonGraphAdapter(result_builder=h_polars.PolarsDataFrameResult()))\n", + " .with_modules(my_functions_lazy, with_columns_lazy_example)\n", + " .with_config({\"case\":\"millions\"})\n", + " .build()\n", + " )\n", + "print(dr.execute(final_vars=[\"final_df\"]))\n", + "dr.visualize_execution(final_vars=[\"final_df\"])\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "hamilton", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.14" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/hamilton/plugins/h_polars.py b/hamilton/plugins/h_polars.py index 799882a30..4ef8609ab 100644 --- a/hamilton/plugins/h_polars.py +++ b/hamilton/plugins/h_polars.py @@ -1,8 +1,27 @@ -from typing import Any, Dict, Type, Union +import sys +from types import ModuleType +from typing import Any, Callable, Collection, Dict, List, Tuple, Type, Union, get_type_hints import polars as pl -from hamilton import base +_sys_version_info = sys.version_info +_version_tuple = (_sys_version_info.major, _sys_version_info.minor, _sys_version_info.micro) + +if _version_tuple < (3, 11, 0): + pass +else: + pass + +# Copied this over from function_graph +# TODO -- determine the best place to put this code +from hamilton import base, node, registry +from hamilton.function_modifiers.expanders import extract_columns +from hamilton.function_modifiers.recursive import ( + _default_inject_parameter, + subdag, + with_columns_base, +) +from hamilton.plugins.polars_extensions import DATAFRAME_TYPE class PolarsDataFrameResult(base.ResultMixin): @@ -54,3 +73,216 @@ def build_result( def output_type(self) -> Type: return pl.DataFrame + + +# Do we need this here? +class with_columns(with_columns_base): + """Initializes a with_columns decorator for polars. + + This allows you to efficiently run groups of map operations on a dataframe. We support + both eager and lazy mode in polars. In case of using eager mode the type should be + pl.DataFrame and the subsequent operations run on columns with type pl.Series. + + Here's an example of calling in eager mode -- if you've seen ``@subdag``, you should be familiar with + the concepts: + + .. code-block:: python + + # my_module.py + def a_b_average(a: pl.Series, b: pl.Series) -> pl.Series: + return (a + b) / 2 + + + .. code-block:: python + + # with_columns_module.py + def a_plus_b(a: pl.Series, b: pl.Series) -> pl.Series: + return a + b + + + # the with_columns call + @with_columns( + *[my_module], # Load from any module + *[a_plus_b], # or list operations directly + columns_to_pass=["a", "b"], # The columns to pass from the dataframe to + # the subdag + select=["a_plus_b", "a_b_average"], # The columns to append to the dataframe + ) + def final_df(initial_df: pl.DataFrame) -> pl.DataFrame: + # process, or just return unprocessed + ... + + In this instance the ``initial_df`` would get two columns added: ``a_plus_b`` and ``a_b_average``. + + Note that the operation is "append", meaning that the columns that are selected are appended + onto the dataframe. + + If the function takes multiple dataframes, the dataframe input to process will always be + the first argument. This will be passed to the subdag, transformed, and passed back to the function. + This follows the hamilton rule of reference by parameter name. To demonstarte this, in the code + above, the dataframe that is passed to the subdag is `initial_df`. That is transformed + by the subdag, and then returned as the final dataframe. + + You can read it as: + + "final_df is a function that transforms the upstream dataframe initial_df, running the transformations + from my_module. It starts with the columns a_from_df and b_from_df, and then adds the columns + a, b, and a_plus_b to the dataframe. It then returns the dataframe, and does some processing on it." + + In case you need more flexibility you can alternatively use ``on_input``, for example, + + .. code-block:: python + + # with_columns_module.py + def a_from_df() -> pl.Expr: + return pl.col(a).alias("a") / 100 + + def b_from_df() -> pl.Expr: + return pl.col(b).alias("b") / 100 + + + # the with_columns call + @with_columns( + *[my_module], + on_input="initial_df", + select=["a_from_df", "b_from_df", "a_plus_b", "a_b_average"], + ) + def final_df(initial_df: pl.DataFrame) -> pl.DataFrame: + # process, or just return unprocessed + ... + + the above would output a dataframe where the two columns ``a`` and ``b`` get + overwritten. + """ + + def __init__( + self, + *load_from: Union[Callable, ModuleType], + columns_to_pass: List[str] = None, + pass_dataframe_as: str = None, + on_input: str = None, + select: List[str] = None, + namespace: str = None, + config_required: List[str] = None, + ): + """Instantiates a ``@with_columns`` decorator. + + :param load_from: The functions or modules that will be used to generate the group of map operations. + :param columns_to_pass: The initial schema of the dataframe. This is used to determine which + upstream inputs should be taken from the dataframe, and which shouldn't. Note that, if this is + left empty (and external_inputs is as well), we will assume that all dependencies come + from the dataframe. This cannot be used in conjunction with on_input. + :param on_input: The name of the dataframe that we're modifying, as known to the subdag. + If you pass this in, you are responsible for extracting columns out. If not provided, you have + to pass columns_to_pass in, and we will extract the columns out on the first parameter for you. + :param select: The end nodes that represent columns to be appended to the original dataframe + via with_columns. Existing columns will be overridden. The selected nodes need to have the + corresponding column type, in this case pl.Series, to be appended to the original dataframe. + :param namespace: The namespace of the nodes, so they don't clash with the global namespace + and so this can be reused. If its left out, there will be no namespace (in which case you'll want + to be careful about repeating it/reusing the nodes in other parts of the DAG.) + :param config_required: the list of config keys that are required to resolve any functions. Pass in None\ + if you want the functions/modules to have access to all possible config. + """ + + if pass_dataframe_as is not None: + raise NotImplementedError( + "We currently do not support pass_dataframe_as for pandas. Please reach out if you need this " + "functionality." + ) + + super().__init__( + *load_from, + columns_to_pass=columns_to_pass, + on_input=on_input, + select=select, + namespace=namespace, + config_required=config_required, + dataframe_type=DATAFRAME_TYPE, + ) + + def _create_column_nodes( + self, fn: Callable, inject_parameter: str, params: Dict[str, Type[Type]] + ) -> List[node.Node]: + output_type = params[inject_parameter] + + def temp_fn(**kwargs) -> Any: + return kwargs[inject_parameter] + + # We recreate the df node to use extract columns + temp_node = node.Node( + name=inject_parameter, + typ=output_type, + callabl=temp_fn, + input_types={inject_parameter: output_type}, + ) + + extract_columns_decorator = extract_columns(*self.initial_schema) + + out_nodes = extract_columns_decorator.transform_node(temp_node, config={}, fn=temp_fn) + return out_nodes[1:] + + def get_initial_nodes( + self, fn: Callable, params: Dict[str, Type[Type]] + ) -> Tuple[str, Collection[node.Node]]: + """Selects the correct dataframe and optionally extracts out columns.""" + inject_parameter = _default_inject_parameter(fn=fn, target_dataframe=self.target_dataframe) + with_columns_base.validate_dataframe( + fn=fn, + inject_parameter=inject_parameter, + params=params, + required_type=self.dataframe_type, + ) + + initial_nodes = ( + [] + if self.target_dataframe is not None + else self._create_column_nodes(fn=fn, inject_parameter=inject_parameter, params=params) + ) + + return inject_parameter, initial_nodes + + def get_subdag_nodes(self, fn: Callable, config: Dict[str, Any]) -> Collection[node.Node]: + return subdag.collect_nodes(config, self.subdag_functions) + + def chain_subdag_nodes( + self, fn: Callable, inject_parameter: str, generated_nodes: Collection[node.Node] + ) -> node.Node: + "Node that adds to / overrides columns for the original dataframe based on selected output." + + if self.select is None: + self.select = [ + sink_node.name + for sink_node in generated_nodes + if sink_node.type == registry.get_column_type_from_df_type(self.dataframe_type) + ] + + def new_callable(**kwargs) -> Any: + df = kwargs[inject_parameter] + columns_to_append = {} + for column in self.select: + columns_to_append[column] = kwargs[column] + + return df.with_columns(**columns_to_append) + + column_type = registry.get_column_type_from_df_type(self.dataframe_type) + input_map = {column: column_type for column in self.select} + input_map[inject_parameter] = self.dataframe_type + merge_node = node.Node( + name="_append", + typ=self.dataframe_type, + callabl=new_callable, + input_types=input_map, + ) + output_nodes = generated_nodes + [merge_node] + return output_nodes, merge_node.name + + def validate(self, fn: Callable): + inject_parameter = _default_inject_parameter(fn=fn, target_dataframe=self.target_dataframe) + params = get_type_hints(fn) + with_columns_base.validate_dataframe( + fn=fn, + inject_parameter=inject_parameter, + params=params, + required_type=self.dataframe_type, + ) diff --git a/hamilton/plugins/h_polars_lazyframe.py b/hamilton/plugins/h_polars_lazyframe.py index a933762a7..00f4326e1 100644 --- a/hamilton/plugins/h_polars_lazyframe.py +++ b/hamilton/plugins/h_polars_lazyframe.py @@ -1,8 +1,16 @@ -from typing import Any, Dict, Type, Union +from types import ModuleType +from typing import Any, Callable, Collection, Dict, List, Tuple, Type, Union, get_type_hints import polars as pl -from hamilton import base +from hamilton import base, node, registry +from hamilton.function_modifiers.expanders import extract_columns +from hamilton.function_modifiers.recursive import ( + _default_inject_parameter, + subdag, + with_columns_base, +) +from hamilton.plugins.polars_lazyframe_extensions import DATAFRAME_TYPE class PolarsLazyFrameResult(base.ResultMixin): @@ -45,3 +53,214 @@ def build_result( def output_type(self) -> Type: return pl.LazyFrame + + +class with_columns(with_columns_base): + """Initializes a with_columns decorator for polars. + + This allows you to efficiently run groups of map operations on a dataframe. We support + both eager and lazy mode in polars. For lazy execution, use pl.LazyFrame and the subsequent + operations should be typed as pl.Expr. See examples/polars/with_columns for a practical + implementation in both variations. + + The lazy execution would be: + + .. code-block:: python + + # my_module.py + def a_b_average(a: pl.Expr, b: pl.Expr) -> pl.Expr: + return (a + b) / 2 + + + .. code-block:: python + + # with_columns_module.py + def a_plus_b(a: pl.Expr, b: pl.Expr) -> pl.Expr: + return a + b + + + # the with_columns call + @with_columns( + *[my_module], # Load from any module + *[a_plus_b], # or list operations directly + columns_to_pass=["a_from_df", "b_from_df"], # The columns to pass from the dataframe to + # the subdag + select=["a_plus_b", "a_b_average"], # The columns to append to the dataframe + ) + def final_df(initial_df: pl.LazyFrame) -> pl.LazyFrame: + # process, or just return unprocessed + ... + + Note that the operation is "append", meaning that the columns that are selected are appended + onto the dataframe. + + If the function takes multiple dataframes, the dataframe input to process will always be + the first argument. This will be passed to the subdag, transformed, and passed back to the function. + This follows the hamilton rule of reference by parameter name. To demonstarte this, in the code + above, the dataframe that is passed to the subdag is `initial_df`. That is transformed + by the subdag, and then returned as the final dataframe. + + You can read it as: + + "final_df is a function that transforms the upstream dataframe initial_df, running the transformations + from my_module. It starts with the columns a_from_df and b_from_df, and then adds the columns + a, b, and a_plus_b to the dataframe. It then returns the dataframe, and does some processing on it." + + In case you need more flexibility you can alternatively use ``on_input``, for example, + + .. code-block:: python + + # with_columns_module.py + def a_from_df() -> pl.Expr: + return pl.col(a).alias("a") / 100 + + def b_from_df() -> pd.Expr: + return pl.col(a).alias("b") / 100 + + + # the with_columns call + @with_columns( + *[my_module], + on_input="initial_df", + select=["a_from_df", "b_from_df", "a_plus_b", "a_b_average"], + ) + def final_df(initial_df: pl.LazyFrame) -> pl.LazyFrame: + # process, or just return unprocessed + ... + + the above would output a dataframe where the two columns ``a`` and ``b`` get + overwritten. + """ + + def __init__( + self, + *load_from: Union[Callable, ModuleType], + columns_to_pass: List[str] = None, + pass_dataframe_as: str = None, + on_input: str = None, + select: List[str] = None, + namespace: str = None, + config_required: List[str] = None, + ): + """Instantiates a ``@with_columns`` decorator. + + :param load_from: The functions or modules that will be used to generate the group of map operations. + :param columns_to_pass: The initial schema of the dataframe. This is used to determine which + upstream inputs should be taken from the dataframe, and which shouldn't. Note that, if this is + left empty (and external_inputs is as well), we will assume that all dependencies come + from the dataframe. This cannot be used in conjunction with on_input. + :param on_input: The name of the dataframe that we're modifying, as known to the subdag. + If you pass this in, you are responsible for extracting columns out. If not provided, you have + to pass columns_to_pass in, and we will extract the columns out on the first parameter for you. + :param select: The end nodes that represent columns to be appended to the original dataframe + via with_columns. Existing columns will be overridden. The selected nodes need to have the + corresponding column type, in this case pl.Expr, to be appended to the original dataframe. + :param namespace: The namespace of the nodes, so they don't clash with the global namespace + and so this can be reused. If its left out, there will be no namespace (in which case you'll want + to be careful about repeating it/reusing the nodes in other parts of the DAG.) + :param config_required: the list of config keys that are required to resolve any functions. Pass in None\ + if you want the functions/modules to have access to all possible config. + """ + + if pass_dataframe_as is not None: + raise NotImplementedError( + "We currently do not support pass_dataframe_as for pandas. Please reach out if you need this " + "functionality." + ) + + super().__init__( + *load_from, + columns_to_pass=columns_to_pass, + on_input=on_input, + select=select, + namespace=namespace, + config_required=config_required, + dataframe_type=DATAFRAME_TYPE, + ) + + def _create_column_nodes( + self, fn: Callable, inject_parameter: str, params: Dict[str, Type[Type]] + ) -> List[node.Node]: + output_type = params[inject_parameter] + + def temp_fn(**kwargs) -> Any: + return kwargs[inject_parameter] + + # We recreate the df node to use extract columns + temp_node = node.Node( + name=inject_parameter, + typ=output_type, + callabl=temp_fn, + input_types={inject_parameter: output_type}, + ) + + extract_columns_decorator = extract_columns(*self.initial_schema) + + out_nodes = extract_columns_decorator.transform_node(temp_node, config={}, fn=temp_fn) + return out_nodes[1:] + + def get_initial_nodes( + self, fn: Callable, params: Dict[str, Type[Type]] + ) -> Tuple[str, Collection[node.Node]]: + """Selects the correct dataframe and optionally extracts out columns.""" + inject_parameter = _default_inject_parameter(fn=fn, target_dataframe=self.target_dataframe) + + with_columns_base.validate_dataframe( + fn=fn, + inject_parameter=inject_parameter, + params=params, + required_type=self.dataframe_type, + ) + + initial_nodes = ( + [] + if self.target_dataframe is not None + else self._create_column_nodes(fn=fn, inject_parameter=inject_parameter, params=params) + ) + + return inject_parameter, initial_nodes + + def get_subdag_nodes(self, fn: Callable, config: Dict[str, Any]) -> Collection[node.Node]: + return subdag.collect_nodes(config, self.subdag_functions) + + def chain_subdag_nodes( + self, fn: Callable, inject_parameter: str, generated_nodes: Collection[node.Node] + ) -> node.Node: + "Node that adds to / overrides columns for the original dataframe based on selected output." + + if self.select is None: + self.select = [ + sink_node.name + for sink_node in generated_nodes + if sink_node.type == registry.get_column_type_from_df_type(self.dataframe_type) + ] + + def new_callable(**kwargs) -> Any: + df = kwargs[inject_parameter] + columns_to_append = {} + for column in self.select: + columns_to_append[column] = kwargs[column] + + return df.with_columns(**columns_to_append) + + column_type = registry.get_column_type_from_df_type(self.dataframe_type) + input_map = {column: column_type for column in self.select} + input_map[inject_parameter] = self.dataframe_type + merge_node = node.Node( + name="_append", + typ=self.dataframe_type, + callabl=new_callable, + input_types=input_map, + ) + output_nodes = generated_nodes + [merge_node] + return output_nodes, merge_node.name + + def validate(self, fn: Callable): + inject_parameter = _default_inject_parameter(fn=fn, target_dataframe=self.target_dataframe) + params = get_type_hints(fn) + with_columns_base.validate_dataframe( + fn=fn, + inject_parameter=inject_parameter, + params=params, + required_type=self.dataframe_type, + ) diff --git a/plugin_tests/h_polars/__init__.py b/plugin_tests/h_polars/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/plugin_tests/h_polars/conftest.py b/plugin_tests/h_polars/conftest.py new file mode 100644 index 000000000..bc5ef5b5a --- /dev/null +++ b/plugin_tests/h_polars/conftest.py @@ -0,0 +1,4 @@ +from hamilton import telemetry + +# disable telemetry for all tests! +telemetry.disable_telemetry() diff --git a/plugin_tests/h_polars/resources/__init__.py b/plugin_tests/h_polars/resources/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/plugin_tests/h_polars/resources/with_columns_end_to_end.py b/plugin_tests/h_polars/resources/with_columns_end_to_end.py new file mode 100644 index 000000000..a893818fc --- /dev/null +++ b/plugin_tests/h_polars/resources/with_columns_end_to_end.py @@ -0,0 +1,68 @@ +import polars as pl + +from hamilton.function_modifiers import config +from hamilton.plugins.h_polars import with_columns + + +def upstream_factor() -> int: + return 3 + + +def initial_df() -> pl.DataFrame: + return pl.DataFrame({"col_1": [1, 2, 3, 4], "col_2": [11, 12, 13, 14], "col_3": [1, 1, 1, 1]}) + + +def subtract_1_from_2(col_1: pl.Series, col_2: pl.Series) -> pl.Series: + return col_2 - col_1 + + +@config.when(factor=5) +def multiply_3__by_5(col_3: pl.Series) -> pl.Series: + return col_3 * 5 + + +@config.when(factor=7) +def multiply_3__by_7(col_3: pl.Series) -> pl.Series: + return col_3 * 7 + + +def add_1_by_user_adjustment_factor(col_1: pl.Series, user_factor: int) -> pl.Series: + return col_1 + user_factor + + +def multiply_2_by_upstream_3(col_2: pl.Series, upstream_factor: int) -> pl.Series: + return col_2 * upstream_factor + + +@with_columns( + subtract_1_from_2, + multiply_3__by_5, + multiply_3__by_7, + add_1_by_user_adjustment_factor, + multiply_2_by_upstream_3, + columns_to_pass=["col_1", "col_2", "col_3"], + select=[ + "subtract_1_from_2", + "multiply_3", + "add_1_by_user_adjustment_factor", + "multiply_2_by_upstream_3", + ], + namespace="some_subdag", +) +def final_df(initial_df: pl.DataFrame) -> pl.DataFrame: + return initial_df + + +def col_3(initial_df: pl.DataFrame) -> pl.Series: + return pl.Series([0, 2, 4, 6]) + + +@with_columns( + col_3, + multiply_3__by_5, + multiply_3__by_7, + on_input="initial_df", + select=["col_3", "multiply_3"], +) +def final_df_2(initial_df: pl.DataFrame) -> pl.DataFrame: + return initial_df diff --git a/plugin_tests/h_polars/resources/with_columns_end_to_end_lazy.py b/plugin_tests/h_polars/resources/with_columns_end_to_end_lazy.py new file mode 100644 index 000000000..367cfacf4 --- /dev/null +++ b/plugin_tests/h_polars/resources/with_columns_end_to_end_lazy.py @@ -0,0 +1,80 @@ +import polars as pl + +from hamilton.function_modifiers import config +from hamilton.plugins.h_polars_lazyframe import with_columns + + +def upstream_factor() -> int: + return 3 + + +def initial_df() -> pl.LazyFrame: + return pl.DataFrame( + {"col_1": [1, 2, 3, 4], "col_2": [11, 12, 13, 14], "col_3": [1, 1, 1, 1]} + ).lazy() + + +def subtract_1_from_2(col_1: pl.Expr, col_2: pl.Expr) -> pl.Expr: + return col_2 - col_1 + + +@config.when(factor=5) +def multiply_3__by_5(col_3: pl.Expr) -> pl.Expr: + return col_3 * 5 + + +@config.when(factor=7) +def multiply_3__by_7(col_3: pl.Expr) -> pl.Expr: + return col_3 * 7 + + +def add_1_by_user_adjustment_factor(col_1: pl.Expr, user_factor: int) -> pl.Expr: + return col_1 + user_factor + + +def multiply_2_by_upstream_3(col_2: pl.Expr, upstream_factor: int) -> pl.Expr: + return col_2 * upstream_factor + + +@with_columns( + subtract_1_from_2, + multiply_3__by_5, + multiply_3__by_7, + add_1_by_user_adjustment_factor, + multiply_2_by_upstream_3, + columns_to_pass=["col_1", "col_2", "col_3"], + select=[ + "subtract_1_from_2", + "multiply_3", + "add_1_by_user_adjustment_factor", + "multiply_2_by_upstream_3", + ], + namespace="some_subdag", +) +def final_df(initial_df: pl.LazyFrame) -> pl.LazyFrame: + return initial_df + + +def col_1(initial_df: pl.LazyFrame) -> pl.Expr: + return pl.col("col_1") + + +@config.when(factor=5) +def multiply_1__by_5(col_1: pl.Expr) -> pl.Expr: + return col_1 * 5 + + +@config.when_not(factor=5) +def multiply_1__by_1(col_1: pl.Expr) -> pl.Expr: + return col_1 * 1 + + +@with_columns( + col_1, + multiply_1__by_5, + multiply_1__by_1, + on_input="initial_df", + select=["col_1", "multiply_1"], +) +def final_df_2(initial_df: pl.LazyFrame) -> pl.LazyFrame: + return initial_df diff --git a/plugin_tests/h_polars/test_with_columns.py b/plugin_tests/h_polars/test_with_columns.py new file mode 100644 index 000000000..151347fb7 --- /dev/null +++ b/plugin_tests/h_polars/test_with_columns.py @@ -0,0 +1,265 @@ +import polars as pl +import pytest +from polars.testing import assert_frame_equal + +from hamilton import driver, node +from hamilton.function_modifiers.base import NodeInjector +from hamilton.plugins.h_polars import with_columns + +from .resources import with_columns_end_to_end + + +def test_create_column_nodes_pass_dataframe(): + def dummy_fn_with_columns(col_1: pl.Series) -> pl.Series: + return col_1 + 100 + + def target_fn(some_var: int, upstream_df: pl.DataFrame) -> pl.DataFrame: + return upstream_df + + dummy_node = node.Node.from_fn(target_fn) + + decorator = with_columns( + dummy_fn_with_columns, on_input="upstream_df", select=["dummy_fn_with_columns"] + ) + + injectable_params = NodeInjector.find_injectable_params([dummy_node]) + inject_parameter, initial_nodes = decorator.get_initial_nodes( + fn=target_fn, params=injectable_params + ) + + assert inject_parameter == "upstream_df" + assert len(initial_nodes) == 0 + + +def test_create_column_nodes_extract_single_columns(): + def dummy_fn_with_columns(col_1: pl.Series) -> pl.Series: + return col_1 + 100 + + def dummy_df() -> pl.DataFrame: + return pl.DataFrame({"col_1": [1, 2, 3, 4], "col_2": [11, 12, 13, 14]}) + + def target_fn(upstream_df: pl.DataFrame) -> pl.DataFrame: + return upstream_df + + dummy_node = node.Node.from_fn(target_fn) + + decorator = with_columns( + dummy_fn_with_columns, columns_to_pass=["col_1"], select=["dummy_fn_with_columns"] + ) + injectable_params = NodeInjector.find_injectable_params([dummy_node]) + + inject_parameter, initial_nodes = decorator.get_initial_nodes( + fn=target_fn, params=injectable_params + ) + + assert inject_parameter == "upstream_df" + assert len(initial_nodes) == 1 + assert initial_nodes[0].name == "col_1" + assert initial_nodes[0].type == pl.Series + pl.testing.assert_series_equal( + initial_nodes[0].callable(upstream_df=dummy_df()), + pl.Series([1, 2, 3, 4]), + check_names=False, + ) + + +def test_create_column_nodes_extract_multiple_columns(): + def dummy_fn_with_columns(col_1: pl.Series) -> pl.Series: + return col_1 + 100 + + def dummy_df() -> pl.DataFrame: + return pl.DataFrame({"col_1": [1, 2, 3, 4], "col_2": [11, 12, 13, 14]}) + + def target_fn(upstream_df: pl.DataFrame) -> pl.DataFrame: + return upstream_df + + dummy_node = node.Node.from_fn(target_fn) + + decorator = with_columns( + dummy_fn_with_columns, columns_to_pass=["col_1", "col_2"], select=["dummy_fn_with_columns"] + ) + injectable_params = NodeInjector.find_injectable_params([dummy_node]) + + inject_parameter, initial_nodes = decorator.get_initial_nodes( + fn=target_fn, params=injectable_params + ) + + assert inject_parameter == "upstream_df" + assert len(initial_nodes) == 2 + assert initial_nodes[0].name == "col_1" + assert initial_nodes[1].name == "col_2" + assert initial_nodes[0].type == pl.Series + assert initial_nodes[1].type == pl.Series + pl.testing.assert_series_equal( + initial_nodes[0].callable(upstream_df=dummy_df()), + pl.Series([1, 2, 3, 4]), + check_names=False, + ) + pl.testing.assert_series_equal( + initial_nodes[1].callable(upstream_df=dummy_df()), + pl.Series([11, 12, 13, 14]), + check_names=False, + ) + + +def test_no_matching_select_column_error(): + def dummy_fn_with_columns(col_1: pl.Series) -> pl.Series: + return col_1 + 100 + + def target_fn(upstream_df: pl.DataFrame) -> pl.DataFrame: + return upstream_df + + dummy_node = node.Node.from_fn(target_fn) + select = "wrong_column" + + decorator = with_columns( + dummy_fn_with_columns, columns_to_pass=["col_1", "col_2"], select=select + ) + injectable_params = NodeInjector.find_injectable_params([dummy_node]) + + with pytest.raises(ValueError): + decorator.inject_nodes(injectable_params, {}, fn=target_fn) + + +def test_append_into_original_df(): + def dummy_fn_with_columns(col_1: pl.Series) -> pl.Series: + return col_1 + 100 + + def dummy_df() -> pl.DataFrame: + return pl.DataFrame({"col_1": [1, 2, 3, 4], "col_2": [11, 12, 13, 14]}) + + def target_fn(upstream_df: pl.DataFrame) -> pl.DataFrame: + return upstream_df + + decorator = with_columns( + dummy_fn_with_columns, columns_to_pass=["col_1", "col_2"], select=["dummy_fn_with_columns"] + ) + + output_nodes, _ = decorator.chain_subdag_nodes( + fn=target_fn, inject_parameter="upstream_df", generated_nodes=[] + ) + merge_node = output_nodes[-1] + + output_df = merge_node.callable( + upstream_df=dummy_df(), + dummy_fn_with_columns=dummy_fn_with_columns(col_1=pl.Series([1, 2, 3, 4])), + ) + assert merge_node.name == "__append" + assert merge_node.type == pl.DataFrame + + pl.testing.assert_series_equal(output_df["col_1"], pl.Series([1, 2, 3, 4]), check_names=False) + pl.testing.assert_series_equal( + output_df["col_2"], pl.Series([11, 12, 13, 14]), check_names=False + ) + pl.testing.assert_series_equal( + output_df["dummy_fn_with_columns"], pl.Series([101, 102, 103, 104]), check_names=False + ) + + +def test_override_original_column_in_df(): + def dummy_df() -> pl.DataFrame: + return pl.DataFrame({"col_1": [1, 2, 3, 4], "col_2": [11, 12, 13, 14]}) + + def target_fn(upstream_df: pl.DataFrame) -> pl.DataFrame: + return upstream_df + + def col_1() -> pl.Series: + return pl.col("col_1") * 100 + + decorator = with_columns(col_1, on_input="upstream_df", select=["col_1"]) + + output_nodes, _ = decorator.chain_subdag_nodes( + fn=target_fn, inject_parameter="upstream_df", generated_nodes=[] + ) + merge_node = output_nodes[-1] + + output_df = merge_node.callable(upstream_df=dummy_df(), col_1=col_1()) + assert merge_node.name == "__append" + assert merge_node.type == pl.DataFrame + + pl.testing.assert_series_equal( + output_df["col_1"], pl.Series([100, 200, 300, 400]), check_names=False + ) + pl.testing.assert_series_equal( + output_df["col_2"], pl.Series([11, 12, 13, 14]), check_names=False + ) + + +def test_assign_custom_namespace_with_columns(): + def dummy_fn_with_columns(col_1: pl.Series) -> pl.Series: + return col_1 + 100 + + def target_fn(upstream_df: pl.DataFrame) -> pl.DataFrame: + return upstream_df + + dummy_node = node.Node.from_fn(target_fn) + decorator = with_columns( + dummy_fn_with_columns, + columns_to_pass=["col_1", "col_2"], + select=["dummy_fn_with_columns"], + namespace="dummy_namespace", + ) + nodes_ = decorator.transform_dag([dummy_node], {}, target_fn) + + assert nodes_[0].name == "target_fn" + assert nodes_[1].name == "dummy_namespace.dummy_fn_with_columns" + assert nodes_[2].name == "dummy_namespace.col_1" + assert nodes_[3].name == "dummy_namespace.__append" + + +def test_end_to_end_with_columns_automatic_extract(): + config_5 = { + "factor": 5, + } + dr = driver.Builder().with_modules(with_columns_end_to_end).with_config(config_5).build() + result = dr.execute(final_vars=["final_df"], inputs={"user_factor": 1000})["final_df"] + + expected_df = pl.DataFrame( + { + "col_1": [1, 2, 3, 4], + "col_2": [11, 12, 13, 14], + "col_3": [1, 1, 1, 1], + "subtract_1_from_2": [10, 10, 10, 10], + "multiply_3": [5, 5, 5, 5], + "add_1_by_user_adjustment_factor": [1001, 1002, 1003, 1004], + "multiply_2_by_upstream_3": [33, 36, 39, 42], + } + ) + pl.testing.assert_frame_equal(result, expected_df) + + config_7 = { + "factor": 7, + } + dr = driver.Builder().with_modules(with_columns_end_to_end).with_config(config_7).build() + result = dr.execute(final_vars=["final_df"], inputs={"user_factor": 1000})["final_df"] + + expected_df = pl.DataFrame( + { + "col_1": [1, 2, 3, 4], + "col_2": [11, 12, 13, 14], + "col_3": [1, 1, 1, 1], + "subtract_1_from_2": [10, 10, 10, 10], + "multiply_3": [7, 7, 7, 7], + "add_1_by_user_adjustment_factor": [1001, 1002, 1003, 1004], + "multiply_2_by_upstream_3": [33, 36, 39, 42], + } + ) + assert_frame_equal(result, expected_df) + + +def test_end_to_end_with_columns_pass_dataframe(): + config_5 = { + "factor": 5, + } + dr = driver.Builder().with_modules(with_columns_end_to_end).with_config(config_5).build() + + result = dr.execute(final_vars=["final_df_2"])["final_df_2"] + expected_df = pl.DataFrame( + { + "col_1": [1, 2, 3, 4], + "col_2": [11, 12, 13, 14], + "col_3": [0, 2, 4, 6], + "multiply_3": [0, 10, 20, 30], + } + ) + assert_frame_equal(result, expected_df) diff --git a/plugin_tests/h_polars/test_with_columns_lazy.py b/plugin_tests/h_polars/test_with_columns_lazy.py new file mode 100644 index 000000000..2cb52c4db --- /dev/null +++ b/plugin_tests/h_polars/test_with_columns_lazy.py @@ -0,0 +1,64 @@ +import polars as pl +from polars.testing import assert_frame_equal + +from hamilton import driver + +from .resources import with_columns_end_to_end_lazy + + +def test_end_to_end_with_columns_automatic_extract_lazy(): + config_5 = { + "factor": 5, + } + dr = driver.Builder().with_modules(with_columns_end_to_end_lazy).with_config(config_5).build() + result = dr.execute(final_vars=["final_df"], inputs={"user_factor": 1000})["final_df"] + + expected_df = pl.DataFrame( + { + "col_1": [1, 2, 3, 4], + "col_2": [11, 12, 13, 14], + "col_3": [1, 1, 1, 1], + "subtract_1_from_2": [10, 10, 10, 10], + "multiply_3": [5, 5, 5, 5], + "add_1_by_user_adjustment_factor": [1001, 1002, 1003, 1004], + "multiply_2_by_upstream_3": [33, 36, 39, 42], + } + ) + pl.testing.assert_frame_equal(result.collect(), expected_df) + + config_7 = { + "factor": 7, + } + dr = driver.Builder().with_modules(with_columns_end_to_end_lazy).with_config(config_7).build() + result = dr.execute(final_vars=["final_df"], inputs={"user_factor": 1000})["final_df"] + + expected_df = pl.DataFrame( + { + "col_1": [1, 2, 3, 4], + "col_2": [11, 12, 13, 14], + "col_3": [1, 1, 1, 1], + "subtract_1_from_2": [10, 10, 10, 10], + "multiply_3": [7, 7, 7, 7], + "add_1_by_user_adjustment_factor": [1001, 1002, 1003, 1004], + "multiply_2_by_upstream_3": [33, 36, 39, 42], + } + ) + assert_frame_equal(result.collect(), expected_df) + + +def test_end_to_end_with_columns_pass_dataframe_lazy(): + config_5 = { + "factor": 5, + } + dr = driver.Builder().with_modules(with_columns_end_to_end_lazy).with_config(config_5).build() + + result = dr.execute(final_vars=["final_df_2"])["final_df_2"] + expected_df = pl.DataFrame( + { + "col_1": [1, 2, 3, 4], + "col_2": [11, 12, 13, 14], + "col_3": [1, 1, 1, 1], + "multiply_1": [5, 10, 15, 20], + } + ) + assert_frame_equal(result.collect(), expected_df) From 40b0f842baf1fe0993d8099a3143416dfadf7a77 Mon Sep 17 00:00:00 2001 From: jernejfrank Date: Sun, 24 Nov 2024 11:12:51 +0800 Subject: [PATCH 6/6] Update docs for with_columns Add docs for new with_columns implementations. --- docs/reference/decorators/with_columns.rst | 24 +++++++++++++++++++--- examples/pandas/with_columns/README | 2 +- examples/polars/with_columns/README | 4 ++-- hamilton/function_modifiers/README | 4 +++- 4 files changed, 27 insertions(+), 7 deletions(-) diff --git a/docs/reference/decorators/with_columns.rst b/docs/reference/decorators/with_columns.rst index 9dbbb7b1f..fd9918714 100644 --- a/docs/reference/decorators/with_columns.rst +++ b/docs/reference/decorators/with_columns.rst @@ -2,10 +2,10 @@ with_columns ======================= -Pandas --------------- +We support the `with_columns` operation that appends the results as new columns to the original dataframe for several libraries: -We have a ``with_columns`` option to run operations on columns of a Pandas dataframe and append the results as new columns. +Pandas +----------------------- **Reference Documentation** @@ -13,6 +13,24 @@ We have a ``with_columns`` option to run operations on columns of a Pandas dataf :special-members: __init__ +Polar (Eager) +----------------------- + +**Reference Documentation** + +.. autoclass:: hamilton.plugins.h_polars.with_columns + :special-members: __init__ + + +Polars (Lazy) +----------------------- + +**Reference Documentation** + +.. autoclass:: hamilton.plugins.h_polars_lazyframe.with_columns + :special-members: __init__ + + PySpark -------------- diff --git a/examples/pandas/with_columns/README b/examples/pandas/with_columns/README index 95cad3cfe..53a422d5a 100644 --- a/examples/pandas/with_columns/README +++ b/examples/pandas/with_columns/README @@ -2,6 +2,6 @@ We show the ability to use the familiar `with_columns` from either `pyspark` or `polars` on a Pandas dataframe. -To see the example look at the notebook. +To see the example look at the [notebook](notebook.ipynb). ![image info](./dag.png) diff --git a/examples/polars/with_columns/README b/examples/polars/with_columns/README index 86db77204..385ef5fb7 100644 --- a/examples/polars/with_columns/README +++ b/examples/polars/with_columns/README @@ -1,8 +1,8 @@ # Using with_columns with Polars -We show the ability to use the familiar `with_columns` from `polars`. Supported for both `pl.DataFrame` and `pl.LazyFrame`. +We show the ability to use the familiar `with_columns` from `polars`. Supported for both: `pl.DataFrame` and `pl.LazyFrame`. -To see the example look at the notebook. +To see the example look at the [notebook](notebook.ipynb). ![image info](./DAG_DataFrame.png) ![image info](./DAG_lazy.png) diff --git a/hamilton/function_modifiers/README b/hamilton/function_modifiers/README index 30cb9607b..d826e29e9 100644 --- a/hamilton/function_modifiers/README +++ b/hamilton/function_modifiers/README @@ -1,6 +1,8 @@ # with_columns_base -Documenting the current design flow for the `with_columns` decorator. It belongs to the `NodeInjector` lifecycle. +Documenting the current design flow for the `with_columns` decorator. + +For now, it belongs to the `NodeInjector` lifecycle since it still runs the decorated function as a node but injects the dataframe with columns appended columns as one of the parameters. The `with_columns` consists of three parts that are represented in the corresponding three abstract methods in `with_columns_base`: