Conversation
|
Could I please be also given write access so I wouldn't need to create the fork? 🙏 |
georyetti
left a comment
There was a problem hiding this comment.
Some comments:
- Keras layer can contain more params to make it more flexible. We can set these as fixed from Spark side
- I think this can return booleans and the user can set output dtypes for auto casting to floats
- Can we use the Spark array helper functions to support nested arrays
| raise ValueError(f"Expected 2 inputs, got {len(inputs)} inputs instead.") | ||
|
|
||
| array, value = inputs | ||
| any_match = ops.any(ops.equal(array, value), axis=-1, keepdims=True) |
There was a problem hiding this comment.
Can we make axis a param of this layer? Then its more useful for a user that just reuses keras layers directly? We can set axis=-1 from Spark side
There was a problem hiding this comment.
Same for keepdims too pls
| output_col = ( | ||
| F.when(F.array_contains(F.col(arr_c), F.col(val_c)), F.lit(1.0)) | ||
| .otherwise(F.lit(0.0)) | ||
| .cast(DoubleType()) | ||
| ) |
There was a problem hiding this comment.
Can we reuse the helper methods we have for array computation here? Then it would support nested arrays also in Spark.
| "int8", | ||
| "uint8", | ||
| "int16", | ||
| "uint16", | ||
| "int32", | ||
| "uint32", | ||
| "int64", | ||
| "uint64", |
There was a problem hiding this comment.
Does this work for int values? Or just int arrays? If so can we add a test please. All tests currently are just with float values
There was a problem hiding this comment.
Yeah should work for both arrays and scalars, added a test
|
|
||
| array, value = inputs | ||
| any_match = ops.any(ops.equal(array, value), axis=-1, keepdims=True) | ||
| return ops.cast(any_match, "float32") |
There was a problem hiding this comment.
Is it expected that array contains returns a float32? I would expect a boolean. The user can set output_dtype="float32" to get this behaviour so I would say we should preserve booleans here
5583b8b to
8133b18
Compare
georyetti
left a comment
There was a problem hiding this comment.
Two comments:
- Pedantic one about using helpers, you have used some more internal ones, we have an easier wrapper for this.
- Do we want to allow a pattern where the scalar value is just a normal constant. Like we do with the Divide/Multiply transformers?
| nesting_level, elem_t = get_array_nesting_level_and_element_dtype(arr_t) | ||
| if not isinstance(elem_t, _NUMERIC_TYPES): | ||
| raise TypeError(f"arrayCol '{arr_c}' element must be numeric, got {elem_t}") | ||
|
|
||
| if not isinstance(val_t, _NUMERIC_TYPES): | ||
| raise TypeError(f"valueCol '{val_c}' must be numeric, got {val_t}") | ||
|
|
||
| # Apply array_contains at the innermost level | ||
| contains_func = nested_transform( | ||
| func=lambda x: F.array_contains(x, F.col(val_c)), | ||
| nest_level=nesting_level - 1, | ||
| ) | ||
| output_col = contains_func(F.col(arr_c)) |
There was a problem hiding this comment.
We have a helper for this that makes it a bit simpler, can we use this? single_input_single_output_array_transform
Also there is no need to check for numeric types as this is done by the BaseTransformer using compatible_dtypes
| inputCols: Optional[List[str]] = None, | ||
| outputCol: Optional[str] = None, | ||
| inputDtype: Optional[str] = None, | ||
| outputDtype: Optional[str] = None, | ||
| layerName: Optional[str] = None, | ||
| ) -> None: | ||
| """ | ||
| Initializes an ArrayContainsTransformer transformer. | ||
|
|
||
| :param inputCols: Input column names, given as `[arrayCol, valueCol]`. |
There was a problem hiding this comment.
Do we want to allow a single input col and a constant? So we can check if array_contains(x, -1) for example?
There was a problem hiding this comment.
Fair idea, generalised it
Description
Adds an
ArrayContainstransformer and paired Keras layer that check whether a scalar value is contained in an array feature, outputting1.0if present and0.0otherwise.Keras Layer Checklist
_callmethod has been implemented in the new layer.compatible_dtypesproperty is defined in the new layer.@tf.keras.utils.register_keras_serializable(package=kamae.__name__).name,input_dtype, andoutput_dtypeas arguments to the constructor and that this is passed to the super constructor.get_configmethod.layersdirectory.Spark Transformer/Estimator Checklist
__init__andsetParamsmethods.Paramsclass here.compatible_dtypesproperty has been implemented to specify the input/output data types that my transformer/estimator supports.get_tf_layermethod.transformers/estimatorsdirectory.Readme Checklist