@@ -429,7 +429,10 @@ def typeof(self) -> ir.StringValue:
429
429
return ops .TypeOf (self ).to_expr ()
430
430
431
431
def fill_null (self , fill_value : Scalar , / ) -> Value :
432
- """Replace any null values with the indicated fill value.
432
+ """Replace `NULL`s with the given value. Does NOT affect `NaN` and `inf` values.
433
+
434
+ This only replaces genuine `NULL` values, it does NOT affect
435
+ `NaN` and `inf` values for floating point types.
433
436
434
437
Parameters
435
438
----------
@@ -440,36 +443,45 @@ def fill_null(self, fill_value: Scalar, /) -> Value:
440
443
--------
441
444
[`Value.coalesce()`](./expression-generic.qmd#ibis.expr.types.generic.Value.coalesce)
442
445
[`ibis.coalesce()`](./expression-generic.qmd#ibis.coalesce)
446
+ [`Value.isnull()`](./expression-generic.qmd#ibis.expr.types.generic.Value.isnull)
447
+ [`FloatingValue.isnan()`](./expression-numeric.qmd#ibis.expr.types.numeric.FloatingValue.isnan)
448
+ [`FloatingValue.isinf()`](./expression-numeric.qmd#ibis.expr.types.numeric.FloatingValue.isinf)
443
449
444
450
Examples
445
451
--------
446
452
>>> import ibis
447
453
>>> ibis.options.interactive = True
448
- >>> t = ibis.examples.penguins.fetch().limit(5)
449
- >>> t.sex
450
- ┏━━━━━━━━┓
451
- ┃ sex ┃
452
- ┡━━━━━━━━┩
453
- │ string │
454
- ├────────┤
455
- │ male │
456
- │ female │
457
- │ female │
458
- │ NULL │
459
- │ female │
460
- └────────┘
461
- >>> t.sex.fill_null("unrecorded").name("sex")
462
- ┏━━━━━━━━━━━━┓
463
- ┃ sex ┃
464
- ┡━━━━━━━━━━━━┩
465
- │ string │
466
- ├────────────┤
467
- │ male │
468
- │ female │
469
- │ female │
470
- │ unrecorded │
471
- │ female │
472
- └────────────┘
454
+ >>> t = ibis.memtable({"f": [None, "-inf", "3.0", "inf", "nan"]})
455
+ >>> t = t.mutate(f=ibis._.f.cast(float))
456
+ >>> t = t.mutate(filled=t.f.fill_null(99))
457
+ >>> t
458
+ ┏━━━━━━━━━┳━━━━━━━━━┓
459
+ ┃ f ┃ filled ┃
460
+ ┡━━━━━━━━━╇━━━━━━━━━┩
461
+ │ float64 │ float64 │
462
+ ├─────────┼─────────┤
463
+ │ NULL │ 99.0 │
464
+ │ -inf │ -inf │
465
+ │ 3.0 │ 3.0 │
466
+ │ inf │ inf │
467
+ │ nan │ nan │
468
+ └─────────┴─────────┘
469
+
470
+ If you want to fill all `NaN` and `inf` values as well, use something like
471
+ the following:
472
+
473
+ >>> t.mutate(filled2=ibis.or_(t.f.isnull(), t.f.isnan(), t.f.isinf()).ifelse(99, t.f))
474
+ ┏━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━┓
475
+ ┃ f ┃ filled ┃ filled2 ┃
476
+ ┡━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━┩
477
+ │ float64 │ float64 │ float64 │
478
+ ├─────────┼─────────┼─────────┤
479
+ │ NULL │ 99.0 │ 99.0 │
480
+ │ -inf │ -inf │ 99.0 │
481
+ │ 3.0 │ 3.0 │ 3.0 │
482
+ │ inf │ inf │ 99.0 │
483
+ │ nan │ nan │ 99.0 │
484
+ └─────────┴─────────┴─────────┘
473
485
474
486
Returns
475
487
-------
@@ -480,7 +492,7 @@ def fill_null(self, fill_value: Scalar, /) -> Value:
480
492
481
493
@deprecated (as_of = "9.1" , instead = "use fill_null instead" )
482
494
def fillna (self , fill_value : Scalar , / ) -> Value :
483
- """DEPRECATED: use `fill_null` instead."""
495
+ """DEPRECATED: use `fill_null` instead, which acts exactly the same ."""
484
496
return self .fill_null (fill_value )
485
497
486
498
def nullif (self , null_if_expr : Value , / ) -> Value :
@@ -879,37 +891,39 @@ def bind(table):
879
891
return bind (_ )
880
892
881
893
def isnull (self ) -> ir .BooleanValue :
882
- """Return whether this expression is NULL.
894
+ """Whether this expression is `NULL`. Does NOT detect `NaN` and `inf` values.
895
+
896
+ For FloatingValue types, use [`FloatingValue.isnan()`](./expression-numeric.qmd#ibis.expr.types.numeric.FloatingValue.isnan)
897
+ and [`FloatingValue.isinf()`](./expression-numeric.qmd#ibis.expr.types.numeric.FloatingValue.isinf) to detect `NaN` and `inf` values.
898
+
899
+ See Also
900
+ --------
901
+ [`Value.fill_null()`](./expression-generic.qmd#ibis.expr.types.generic.Value.fill_null)
902
+ [`FloatingValue.isnan()`](./expression-numeric.qmd#ibis.expr.types.numeric.FloatingValue.isnan)
903
+ [`FloatingValue.isinf()`](./expression-numeric.qmd#ibis.expr.types.numeric.FloatingValue.isinf)
883
904
884
905
Examples
885
906
--------
886
907
>>> import ibis
887
908
>>> ibis.options.interactive = True
888
- >>> t = ibis.examples.penguins.fetch().limit(5)
889
- >>> t.bill_depth_mm
890
- ┏━━━━━━━━━━━━━━━┓
891
- ┃ bill_depth_mm ┃
892
- ┡━━━━━━━━━━━━━━━┩
893
- │ float64 │
894
- ├───────────────┤
895
- │ 18.7 │
896
- │ 17.4 │
897
- │ 18.0 │
898
- │ NULL │
899
- │ 19.3 │
900
- └───────────────┘
901
- >>> t.bill_depth_mm.isnull()
902
- ┏━━━━━━━━━━━━━━━━━━━━━━━┓
903
- ┃ IsNull(bill_depth_mm) ┃
904
- ┡━━━━━━━━━━━━━━━━━━━━━━━┩
905
- │ boolean │
906
- ├───────────────────────┤
907
- │ False │
908
- │ False │
909
- │ False │
910
- │ True │
911
- │ False │
912
- └───────────────────────┘
909
+ >>> t = ibis.memtable({"f": [None, "-inf", "3.0", "inf", "nan"]})
910
+ >>> t = t.mutate(f=ibis._.f.cast(float))
911
+ >>> t.mutate(
912
+ ... isnull=t.f.isnull(),
913
+ ... isnan=t.f.isnan(),
914
+ ... isinf=t.f.isinf(),
915
+ ... )
916
+ ┏━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━┓
917
+ ┃ f ┃ isnull ┃ isnan ┃ isinf ┃
918
+ ┡━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━┩
919
+ │ float64 │ boolean │ boolean │ boolean │
920
+ ├─────────┼─────────┼─────────┼─────────┤
921
+ │ NULL │ True │ NULL │ NULL │
922
+ │ -inf │ False │ False │ True │
923
+ │ 3.0 │ False │ False │ False │
924
+ │ inf │ False │ False │ True │
925
+ │ nan │ False │ True │ False │
926
+ └─────────┴─────────┴─────────┴─────────┘
913
927
"""
914
928
return ops .IsNull (self ).to_expr ()
915
929
0 commit comments