This is an automated email from the ASF dual-hosted git repository.

zhengruifeng pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/spark.git


The following commit(s) were added to refs/heads/master by this push:
     new 168a1b5feca5 [MINOR][PS][DOC] Correct the null-handling comment on the 
numpy signbit mapping
168a1b5feca5 is described below

commit 168a1b5feca5e40989eb103544dac18a6dc4d267
Author: Spenser Sun <[email protected]>
AuthorDate: Tue Aug 25 08:41:04 2026 +0800

    [MINOR][PS][DOC] Correct the null-handling comment on the numpy signbit 
mapping
    
    ### What changes were proposed in this pull request?
    
    Comment-only: corrects and completes the null-handling comment on the 
`signbit` entry in `unary_np_spark_mappings`, which named fewer cases than 
actually reach its floating-null branch.
    
    While fixing it I looked again at the case the comment documents as 
unmatched, and I think it can be fixed. `from_pandas` sends both a `NaN` and a 
genuine missing value to Spark as a null, so the expression cannot tell which 
of the two it has:
    
    - **`float64` / `float32` (default):** a null is always a `NaN`, so the 
current answer (`False`) is right.
    - **`Float64` / `Float32` (nullable):** a null is an `<NA>` and should 
propagate, but it is treated as a `NaN` too -- `np.signbit` on `pd.Series([1.0, 
None, -2.0], dtype="Float64")` returns `[False, False, True]` where pandas 
returns `[False, <NA>, True]`.
    
    **Proposed fix:** choose the answer for a null from the pandas dtype rather 
than from `F.typeof(c)`. `typeof` cannot separate the two dtypes because both 
map to `double`, but the dtype is still available in 
`maybe_dispatch_ufunc_to_spark_func` before the Column is built, and it settles 
the question exactly: a null in a nullable float column can only be an `<NA>` 
(propagate), and in a default float column only a `NaN` (`False`). The entry 
itself then reduces to the sign test and the `t [...]
    
    **Out of this fix's reach:** the `NaN` *sign*. Spark cannot expose it (`NaN 
< 0` is false, and the string cast yields `"NaN"`), so that half of the comment 
stands regardless.
    
    Would value your input on whether this is worth pursuing -- happy to do it 
under a separate JIRA, or to fold it in here.
    
    ### Why are the changes needed?
    
    The comment is the only place this behavior is written down, and it named 
fewer cases than land in that branch -- a reader trusting it would expect a 
nullable `Float32` `<NA>` to propagate, and a negative `NaN` to be reported as 
negative. Neither is true.
    
    ### Does this PR introduce _any_ user-facing change?
    
    No. Comment-only.
    
    ### How was this patch tested?
    
    No tests added -- the diff is comment-only, so behavior is unchanged. Ran 
`ruff check` / `ruff format --check` on the changed file and 
`test_numpy_compat.py` (`test_np_signbit` passes).
    
    ### Was this patch authored or co-authored using generative AI tooling?
    
    Generated-by: Claude Code (Claude Opus 5)
    
    Closes #58263 from Spenserrrr/numpy-signbit-null-comment.
    
    Authored-by: Spenser Sun <[email protected]>
    Signed-off-by: Ruifeng Zheng <[email protected]>
---
 python/pyspark/pandas/numpy_compat.py | 14 +++++++++-----
 1 file changed, 9 insertions(+), 5 deletions(-)

diff --git a/python/pyspark/pandas/numpy_compat.py 
b/python/pyspark/pandas/numpy_compat.py
index c27aa0225e3f..55a12aae853d 100644
--- a/python/pyspark/pandas/numpy_compat.py
+++ b/python/pyspark/pandas/numpy_compat.py
@@ -89,11 +89,15 @@ unary_np_spark_mappings = {
     "rint": lambda c: F.rint(c.cast("double")),
     "sign": F.signum,
     "signbit": lambda c: F.when(
-        # A genuine <NA> from a nullable dtype (e.g. Int64) arrives as a 
non-double
-        # null and must propagate. A NaN from a default (numpy-backed) dtype 
arrives
-        # as a double null and must map to False (np.signbit(nan) is False); 
it falls
-        # through to otherwise(False) below. A nullable Float64 <NA> is also a 
double
-        # null, indistinguishable from a NaN after from_pandas, so it cannot 
propagate.
+        # A genuine <NA> from a nullable dtype (e.g. Int64) arrives as a 
non-floating null
+        # and must propagate. A NaN from a default (numpy-backed) dtype 
arrives as a floating
+        # null and must map to False (np.signbit(nan) is False); it falls 
through to
+        # otherwise(False) below. Two cases this expression cannot match, 
seeing only the Spark
+        # value and not the pandas dtype: a nullable float dtype's <NA> 
(Float32 or Float64) is
+        # also a floating null, indistinguishable from a NaN after 
from_pandas, so it reads False
+        # instead of propagating; and the sign of a NaN never reaches here 
(from_pandas nulls a
+        # NaN, and a NaN computed in Spark arrives as +NaN), so a negative NaN 
reads False where
+        # np.signbit reports True.
         c.isNull() & ~F.typeof(c).isin("float", "double"),
         F.lit(None).cast("boolean"),
     )


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

Reply via email to