diff --git a/common/workflow-operator/src/main/scala/org/apache/texera/amber/operator/huggingFace/HuggingFaceIrisLogisticRegressionOpDesc.scala b/common/workflow-operator/src/main/scala/org/apache/texera/amber/operator/huggingFace/HuggingFaceIrisLogisticRegressionOpDesc.scala index 9a9ac563250..951971b3fbc 100644 --- a/common/workflow-operator/src/main/scala/org/apache/texera/amber/operator/huggingFace/HuggingFaceIrisLogisticRegressionOpDesc.scala +++ b/common/workflow-operator/src/main/scala/org/apache/texera/amber/operator/huggingFace/HuggingFaceIrisLogisticRegressionOpDesc.scala @@ -91,6 +91,15 @@ class HuggingFaceIrisLogisticRegressionOpDesc extends PythonOperatorDescriptor { | training_features_stds = [1.72528903, 0.73788937] | length = tuple_[$petalLengthCmAttribute] | width = tuple_[$petalWidthCmAttribute] + | # An empty cell arrives as None, which numpy carries as an object the + | # standardization cannot subtract from. Keep the row and leave the + | # prediction empty rather than ending the run over a measurement the + | # model was never given. + | if length is None or width is None: + | tuple_[$predictionClassName] = None + | tuple_[$predictionProbabilityName] = None + | yield tuple_ + | return | features = np.array([[length, width]]) | features = ((features - training_features_means) / training_features_stds) | features = torch.from_numpy(features).float() diff --git a/common/workflow-operator/src/test/scala/org/apache/texera/amber/operator/huggingFace/HuggingFaceIrisLogisticRegressionOpDescSpec.scala b/common/workflow-operator/src/test/scala/org/apache/texera/amber/operator/huggingFace/HuggingFaceIrisLogisticRegressionOpDescSpec.scala index 1c3701b4d66..fb45227194d 100644 --- a/common/workflow-operator/src/test/scala/org/apache/texera/amber/operator/huggingFace/HuggingFaceIrisLogisticRegressionOpDescSpec.scala +++ b/common/workflow-operator/src/test/scala/org/apache/texera/amber/operator/huggingFace/HuggingFaceIrisLogisticRegressionOpDescSpec.scala @@ -105,6 +105,16 @@ class HuggingFaceIrisLogisticRegressionOpDescSpec extends AnyFlatSpec with Match carries(code, "species") shouldBe true } + // An empty cell reaches the standardization as a None, which numpy cannot + // subtract from, so the row is answered rather than ending the run. + it should "leave the prediction empty when a measurement is missing" in { + val d = configured() + val code = d.generatePythonCode() + code should include("if length is None or width is None:") + code should include("yield tuple_") + code should include("return") + } + "HuggingFaceIrisLogisticRegressionOpDesc.getPhysicalOp" should "wire an OpExecWithCode python executor carrying the operator's ports" in { val d = configured()