Spenserrrr commented on code in PR #57836:
URL: https://github.com/apache/spark/pull/57836#discussion_r3756798335


##########
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:
   I built the jars locally and checked what from_pandas does with missing 
values: a NaN and a null in a float column both come back as the same Spark 
value (isNull = true, typeof = double). So there's one case this can't get 
right. If a user has a nullable Float64 column with a real <NA>, pandas' 
np.copysign propagates the null, but here it returns |x|, because after 
from_pandas that <NA> looks identical to a plain NaN. I think treating it as 
NaN is reasonable for the common (default float64) path. Probably we need to 
document somewhere that a nullable Float64 <NA> can't be distinguished from NaN 
here and is therefore treated as NaN?



-- 
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