Yicong-Huang commented on code in PR #57836:
URL: https://github.com/apache/spark/pull/57836#discussion_r3833993072


##########
python/pyspark/pandas/tests/test_numpy_compat.py:
##########
@@ -262,6 +262,50 @@ def test_np_fmax_fmin(self):
                 expected = np_func(pdf.x1, pdf.x2)
                 self.assert_eq(result, expected, almost=True)
 
+    def test_np_copysign(self):
+        for pdf in (
+            pd.DataFrame(
+                {
+                    "x1": [-64, -2, -1, 0, 1, 2, 64],
+                    "x2": [2, -3, -2, -3, 3, -1, 2],
+                }
+            ),
+            pd.DataFrame(
+                {
+                    "x1": [-np.inf, -64.0, -2.0, -0.0, 0.0, 2.0, 64.0, np.inf, 
np.nan, 1.0],
+                    "x2": [2.0, -3.0, -2.0, 0.0, -0.0, -1.0, np.inf, -np.inf, 
2.0, np.nan],
+                }
+            ),
+            pd.DataFrame(
+                {
+                    "x1": pd.array([1, -2, 3, None, None], dtype="Int64"),
+                    "x2": pd.array([-2, 3, None, 2, None], dtype="Int64"),
+                }
+            ),
+        ):
+            psdf = ps.from_pandas(pdf)
+            result = np.copysign(psdf.x1, psdf.x2)
+            expected = np.copysign(pdf.x1, pdf.x2)
+            self.assert_eq(result, expected, almost=True)
+            # copysign only differs from |x| in the sign bit, so assert on 
signbit
+            # explicitly -- 0.0 == -0.0 numerically and would hide a wrong 
sign.
+            self.assert_eq(np.signbit(result.to_pandas()), 
np.signbit(expected))
+
+    def test_np_copysign_signed_zero(self):
+        # np.copysign takes the sign from y's IEEE-754 sign bit, not from y < 
0:
+        # copysign(1.0, -0.0) == -1.0 and copysign(1.0, 0.0) == 1.0.
+        pdf = pd.DataFrame(
+            {
+                "x1": [1.0, 1.0, -0.0, -0.0, 3.0],
+                "x2": [0.0, -0.0, 0.0, -0.0, -0.0],
+            }
+        )
+        psdf = ps.from_pandas(pdf)

Review Comment:
   Good catch, and thanks for building it locally to confirm. You're right that 
a nullable Float64 <NA> is indistinguishable from a NaN once from_pandas 
collapses both to a Spark NULL (isNull=true, typeof=double), so it's treated as 
NaN and returns |x| instead of propagating. Worth noting this isn't new 
behavior here: the previous pandas_udf returned |x| for that case too (the <NA> 
reaches the UDF as a plain NaN), so it's a pre-existing pandas-on-Spark 
representation limitation rather than a change introduced by this PR. I've 
added a note in the code documenting it.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to