polars-df 0.20.0-x86_64-darwin → 0.21.1-x86_64-darwin

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +27 -0
  3. data/Cargo.lock +192 -186
  4. data/LICENSE-THIRD-PARTY.txt +1431 -1810
  5. data/LICENSE.txt +1 -1
  6. data/lib/polars/3.2/polars.bundle +0 -0
  7. data/lib/polars/3.3/polars.bundle +0 -0
  8. data/lib/polars/3.4/polars.bundle +0 -0
  9. data/lib/polars/array_expr.rb +382 -3
  10. data/lib/polars/array_name_space.rb +281 -0
  11. data/lib/polars/binary_expr.rb +67 -0
  12. data/lib/polars/binary_name_space.rb +43 -0
  13. data/lib/polars/cat_expr.rb +224 -0
  14. data/lib/polars/cat_name_space.rb +130 -32
  15. data/lib/polars/catalog/unity/catalog_info.rb +20 -0
  16. data/lib/polars/catalog/unity/column_info.rb +31 -0
  17. data/lib/polars/catalog/unity/namespace_info.rb +21 -0
  18. data/lib/polars/catalog/unity/table_info.rb +50 -0
  19. data/lib/polars/catalog.rb +448 -0
  20. data/lib/polars/config.rb +2 -2
  21. data/lib/polars/convert.rb +12 -2
  22. data/lib/polars/data_frame.rb +834 -48
  23. data/lib/polars/data_type_expr.rb +52 -0
  24. data/lib/polars/data_types.rb +61 -5
  25. data/lib/polars/date_time_expr.rb +251 -0
  26. data/lib/polars/date_time_name_space.rb +299 -0
  27. data/lib/polars/exceptions.rb +7 -2
  28. data/lib/polars/expr.rb +1247 -211
  29. data/lib/polars/functions/col.rb +6 -5
  30. data/lib/polars/functions/datatype.rb +21 -0
  31. data/lib/polars/functions/lazy.rb +127 -15
  32. data/lib/polars/functions/repeat.rb +4 -0
  33. data/lib/polars/io/csv.rb +19 -1
  34. data/lib/polars/io/json.rb +16 -0
  35. data/lib/polars/io/ndjson.rb +13 -0
  36. data/lib/polars/io/parquet.rb +70 -66
  37. data/lib/polars/io/scan_options.rb +47 -0
  38. data/lib/polars/lazy_frame.rb +1099 -95
  39. data/lib/polars/list_expr.rb +400 -11
  40. data/lib/polars/list_name_space.rb +321 -5
  41. data/lib/polars/meta_expr.rb +71 -22
  42. data/lib/polars/name_expr.rb +36 -0
  43. data/lib/polars/scan_cast_options.rb +64 -0
  44. data/lib/polars/schema.rb +84 -3
  45. data/lib/polars/selector.rb +210 -0
  46. data/lib/polars/selectors.rb +932 -203
  47. data/lib/polars/series.rb +1083 -63
  48. data/lib/polars/string_expr.rb +435 -9
  49. data/lib/polars/string_name_space.rb +729 -45
  50. data/lib/polars/struct_expr.rb +103 -0
  51. data/lib/polars/struct_name_space.rb +19 -1
  52. data/lib/polars/utils/parse.rb +40 -0
  53. data/lib/polars/utils/various.rb +18 -1
  54. data/lib/polars/utils.rb +9 -1
  55. data/lib/polars/version.rb +1 -1
  56. data/lib/polars.rb +10 -0
  57. metadata +12 -2
data/lib/polars/expr.rb CHANGED
@@ -26,56 +26,59 @@ module Polars
26
26
  #
27
27
  # @return [Expr]
28
28
  def ^(other)
29
- _from_rbexpr(_rbexpr._xor(_to_rbexpr(other)))
29
+ other = Utils.parse_into_expression(other)
30
+ wrap_expr(_rbexpr.xor_(other))
30
31
  end
31
32
 
32
33
  # Bitwise AND.
33
34
  #
34
35
  # @return [Expr]
35
36
  def &(other)
36
- _from_rbexpr(_rbexpr._and(_to_rbexpr(other)))
37
+ other = Utils.parse_into_expression(other)
38
+ wrap_expr(_rbexpr.and_(other))
37
39
  end
38
40
 
39
41
  # Bitwise OR.
40
42
  #
41
43
  # @return [Expr]
42
44
  def |(other)
43
- _from_rbexpr(_rbexpr._or(_to_rbexpr(other)))
45
+ other = Utils.parse_into_expression(other)
46
+ wrap_expr(_rbexpr.or_(other))
44
47
  end
45
48
 
46
49
  # Performs addition.
47
50
  #
48
51
  # @return [Expr]
49
52
  def +(other)
50
- _from_rbexpr(_rbexpr + _to_rbexpr(other))
53
+ wrap_expr(_rbexpr + _to_rbexpr(other))
51
54
  end
52
55
 
53
56
  # Performs subtraction.
54
57
  #
55
58
  # @return [Expr]
56
59
  def -(other)
57
- _from_rbexpr(_rbexpr - _to_rbexpr(other))
60
+ wrap_expr(_rbexpr - _to_rbexpr(other))
58
61
  end
59
62
 
60
63
  # Performs multiplication.
61
64
  #
62
65
  # @return [Expr]
63
66
  def *(other)
64
- _from_rbexpr(_rbexpr * _to_rbexpr(other))
67
+ wrap_expr(_rbexpr * _to_rbexpr(other))
65
68
  end
66
69
 
67
70
  # Performs division.
68
71
  #
69
72
  # @return [Expr]
70
73
  def /(other)
71
- _from_rbexpr(_rbexpr / _to_rbexpr(other))
74
+ wrap_expr(_rbexpr / _to_rbexpr(other))
72
75
  end
73
76
 
74
77
  # Returns the modulo.
75
78
  #
76
79
  # @return [Expr]
77
80
  def %(other)
78
- _from_rbexpr(_rbexpr % _to_rbexpr(other))
81
+ wrap_expr(_rbexpr % _to_rbexpr(other))
79
82
  end
80
83
 
81
84
  # Raises to the power of exponent.
@@ -83,49 +86,49 @@ module Polars
83
86
  # @return [Expr]
84
87
  def **(power)
85
88
  exponent = Utils.parse_into_expression(power)
86
- _from_rbexpr(_rbexpr.pow(exponent))
89
+ wrap_expr(_rbexpr.pow(exponent))
87
90
  end
88
91
 
89
92
  # Greater than or equal.
90
93
  #
91
94
  # @return [Expr]
92
95
  def >=(other)
93
- _from_rbexpr(_rbexpr.gt_eq(_to_expr(other)._rbexpr))
96
+ wrap_expr(_rbexpr.gt_eq(_to_expr(other)._rbexpr))
94
97
  end
95
98
 
96
99
  # Less than or equal.
97
100
  #
98
101
  # @return [Expr]
99
102
  def <=(other)
100
- _from_rbexpr(_rbexpr.lt_eq(_to_expr(other)._rbexpr))
103
+ wrap_expr(_rbexpr.lt_eq(_to_expr(other)._rbexpr))
101
104
  end
102
105
 
103
106
  # Equal.
104
107
  #
105
108
  # @return [Expr]
106
109
  def ==(other)
107
- _from_rbexpr(_rbexpr.eq(_to_expr(other)._rbexpr))
110
+ wrap_expr(_rbexpr.eq(_to_expr(other)._rbexpr))
108
111
  end
109
112
 
110
113
  # Not equal.
111
114
  #
112
115
  # @return [Expr]
113
116
  def !=(other)
114
- _from_rbexpr(_rbexpr.neq(_to_expr(other)._rbexpr))
117
+ wrap_expr(_rbexpr.neq(_to_expr(other)._rbexpr))
115
118
  end
116
119
 
117
120
  # Less than.
118
121
  #
119
122
  # @return [Expr]
120
123
  def <(other)
121
- _from_rbexpr(_rbexpr.lt(_to_expr(other)._rbexpr))
124
+ wrap_expr(_rbexpr.lt(_to_expr(other)._rbexpr))
122
125
  end
123
126
 
124
127
  # Greater than.
125
128
  #
126
129
  # @return [Expr]
127
130
  def >(other)
128
- _from_rbexpr(_rbexpr.gt(_to_expr(other)._rbexpr))
131
+ wrap_expr(_rbexpr.gt(_to_expr(other)._rbexpr))
129
132
  end
130
133
 
131
134
  # Performs boolean not.
@@ -134,12 +137,13 @@ module Polars
134
137
  def !
135
138
  is_not
136
139
  end
140
+ alias_method :~, :!
137
141
 
138
142
  # Performs negation.
139
143
  #
140
144
  # @return [Expr]
141
145
  def -@
142
- _from_rbexpr(_rbexpr.neg)
146
+ wrap_expr(_rbexpr.neg)
143
147
  end
144
148
 
145
149
  # Cast to physical representation of the logical dtype.
@@ -176,7 +180,7 @@ module Polars
176
180
  # # │ a ┆ 0 │
177
181
  # # └──────┴───────────────┘
178
182
  def to_physical
179
- _from_rbexpr(_rbexpr.to_physical)
183
+ wrap_expr(_rbexpr.to_physical)
180
184
  end
181
185
 
182
186
  # Check if any boolean value in a Boolean column is `true`.
@@ -196,7 +200,7 @@ module Polars
196
200
  # # │ true ┆ false │
197
201
  # # └──────┴───────┘
198
202
  def any(drop_nulls: true)
199
- _from_rbexpr(_rbexpr.any(drop_nulls))
203
+ wrap_expr(_rbexpr.any(drop_nulls))
200
204
  end
201
205
 
202
206
  # Check if all boolean values in a Boolean column are `true`.
@@ -221,7 +225,33 @@ module Polars
221
225
  # # │ true ┆ false ┆ false │
222
226
  # # └──────┴───────┴───────┘
223
227
  def all(drop_nulls: true)
224
- _from_rbexpr(_rbexpr.all(drop_nulls))
228
+ wrap_expr(_rbexpr.all(drop_nulls))
229
+ end
230
+
231
+ # Return indices where expression evaluates `true`.
232
+ #
233
+ # @return [Expr]
234
+ #
235
+ # @note
236
+ # Modifies number of rows returned, so will fail in combination with other
237
+ # expressions. Use as only expression in `select` / `with_columns`.
238
+ #
239
+ # @example
240
+ # df = Polars::DataFrame.new({"a" => [1, 1, 2, 1]})
241
+ # df.select((Polars.col("a") == 1).arg_true)
242
+ # # =>
243
+ # # shape: (3, 1)
244
+ # # ┌─────┐
245
+ # # │ a │
246
+ # # │ --- │
247
+ # # │ u32 │
248
+ # # ╞═════╡
249
+ # # │ 0 │
250
+ # # │ 1 │
251
+ # # │ 3 │
252
+ # # └─────┘
253
+ def arg_true
254
+ wrap_expr(Plr.arg_where(_rbexpr))
225
255
  end
226
256
 
227
257
  # Compute the square root of the elements.
@@ -243,7 +273,29 @@ module Polars
243
273
  # # │ 2.0 │
244
274
  # # └──────────┘
245
275
  def sqrt
246
- self**0.5
276
+ wrap_expr(_rbexpr.sqrt)
277
+ end
278
+
279
+ # Compute the cube root of the elements.
280
+ #
281
+ # @return [Expr]
282
+ #
283
+ # @example
284
+ # df = Polars::DataFrame.new({"values" => [1.0, 2.0, 4.0]})
285
+ # df.select(Polars.col("values").cbrt)
286
+ # # =>
287
+ # # shape: (3, 1)
288
+ # # ┌──────────┐
289
+ # # │ values │
290
+ # # │ --- │
291
+ # # │ f64 │
292
+ # # ╞══════════╡
293
+ # # │ 1.0 │
294
+ # # │ 1.259921 │
295
+ # # │ 1.587401 │
296
+ # # └──────────┘
297
+ def cbrt
298
+ wrap_expr(_rbexpr.cbrt)
247
299
  end
248
300
 
249
301
  # Compute the base 10 logarithm of the input array, element-wise.
@@ -287,7 +339,7 @@ module Polars
287
339
  # # │ 54.59815 │
288
340
  # # └──────────┘
289
341
  def exp
290
- _from_rbexpr(_rbexpr.exp)
342
+ wrap_expr(_rbexpr.exp)
291
343
  end
292
344
 
293
345
  # Rename the output of an expression.
@@ -322,7 +374,7 @@ module Polars
322
374
  # # │ 3 ┆ null │
323
375
  # # └─────┴──────┘
324
376
  def alias(name)
325
- _from_rbexpr(_rbexpr._alias(name))
377
+ wrap_expr(_rbexpr._alias(name))
326
378
  end
327
379
 
328
380
  # TODO support symbols for exclude
@@ -333,12 +385,11 @@ module Polars
333
385
  # with `$`.
334
386
  #
335
387
  # @param columns [Object]
336
- # Column(s) to exclude from selection.
337
- # This can be:
338
- #
339
- # - a column name, or multiple column names
340
- # - a regular expression starting with `^` and ending with `$`
341
- # - a dtype or multiple dtypes
388
+ # The name or datatype of the column(s) to exclude. Accepts regular expression
389
+ # input. Regular expressions should start with `^` and end with `$`.
390
+ # @param more_columns [Array]
391
+ # Additional names or datatypes of columns to exclude, specified as positional
392
+ # arguments.
342
393
  #
343
394
  # @return [Expr]
344
395
  #
@@ -362,24 +413,8 @@ module Polars
362
413
  # # │ 2 ┆ 2.5 │
363
414
  # # │ 3 ┆ 1.5 │
364
415
  # # └─────┴──────┘
365
- def exclude(columns)
366
- if columns.is_a?(::String)
367
- columns = [columns]
368
- return _from_rbexpr(_rbexpr.exclude(columns))
369
- elsif !columns.is_a?(::Array)
370
- columns = [columns]
371
- return _from_rbexpr(_rbexpr.exclude_dtype(columns))
372
- end
373
-
374
- if !columns.all? { |a| a.is_a?(::String) } || !columns.all? { |a| Utils.is_polars_dtype(a) }
375
- raise ArgumentError, "input should be all string or all DataType"
376
- end
377
-
378
- if columns[0].is_a?(::String)
379
- _from_rbexpr(_rbexpr.exclude(columns))
380
- else
381
- _from_rbexpr(_rbexpr.exclude_dtype(columns))
382
- end
416
+ def exclude(columns, *more_columns)
417
+ meta.as_selector.exclude(columns, *more_columns).as_expr
383
418
  end
384
419
 
385
420
  # Keep the original root name of the expression.
@@ -527,7 +562,7 @@ module Polars
527
562
  # # │ true │
528
563
  # # └───────┘
529
564
  def is_not
530
- _from_rbexpr(_rbexpr.not_)
565
+ wrap_expr(_rbexpr.not_)
531
566
  end
532
567
  alias_method :not_, :is_not
533
568
 
@@ -557,7 +592,7 @@ module Polars
557
592
  # # │ 5 ┆ 5.0 ┆ false ┆ false │
558
593
  # # └──────┴─────┴──────────┴──────────┘
559
594
  def is_null
560
- _from_rbexpr(_rbexpr.is_null)
595
+ wrap_expr(_rbexpr.is_null)
561
596
  end
562
597
 
563
598
  # Returns a boolean Series indicating which values are not null.
@@ -586,7 +621,7 @@ module Polars
586
621
  # # │ 5 ┆ 5.0 ┆ true ┆ true │
587
622
  # # └──────┴─────┴────────────┴────────────┘
588
623
  def is_not_null
589
- _from_rbexpr(_rbexpr.is_not_null)
624
+ wrap_expr(_rbexpr.is_not_null)
590
625
  end
591
626
 
592
627
  # Returns a boolean Series indicating which values are finite.
@@ -612,7 +647,7 @@ module Polars
612
647
  # # │ true ┆ false │
613
648
  # # └──────┴───────┘
614
649
  def is_finite
615
- _from_rbexpr(_rbexpr.is_finite)
650
+ wrap_expr(_rbexpr.is_finite)
616
651
  end
617
652
 
618
653
  # Returns a boolean Series indicating which values are infinite.
@@ -638,7 +673,7 @@ module Polars
638
673
  # # │ false ┆ true │
639
674
  # # └───────┴───────┘
640
675
  def is_infinite
641
- _from_rbexpr(_rbexpr.is_infinite)
676
+ wrap_expr(_rbexpr.is_infinite)
642
677
  end
643
678
 
644
679
  # Returns a boolean Series indicating which values are NaN.
@@ -671,7 +706,7 @@ module Polars
671
706
  # # │ 5 ┆ 5.0 ┆ false │
672
707
  # # └──────┴─────┴─────────┘
673
708
  def is_nan
674
- _from_rbexpr(_rbexpr.is_nan)
709
+ wrap_expr(_rbexpr.is_nan)
675
710
  end
676
711
 
677
712
  # Returns a boolean Series indicating which values are not NaN.
@@ -704,7 +739,7 @@ module Polars
704
739
  # # │ 5 ┆ 5.0 ┆ true │
705
740
  # # └──────┴─────┴──────────────┘
706
741
  def is_not_nan
707
- _from_rbexpr(_rbexpr.is_not_nan)
742
+ wrap_expr(_rbexpr.is_not_nan)
708
743
  end
709
744
 
710
745
  # Get the group indexes of the group by operation.
@@ -739,7 +774,7 @@ module Polars
739
774
  # # │ two ┆ [3, 4, 5] │
740
775
  # # └───────┴───────────┘
741
776
  def agg_groups
742
- _from_rbexpr(_rbexpr.agg_groups)
777
+ wrap_expr(_rbexpr.agg_groups)
743
778
  end
744
779
 
745
780
  # Count the number of values in this expression.
@@ -759,7 +794,7 @@ module Polars
759
794
  # # │ 3 ┆ 2 │
760
795
  # # └─────┴─────┘
761
796
  def count
762
- _from_rbexpr(_rbexpr.count)
797
+ wrap_expr(_rbexpr.count)
763
798
  end
764
799
 
765
800
  # Count the number of values in this expression.
@@ -779,7 +814,7 @@ module Polars
779
814
  # # │ 3 ┆ 3 │
780
815
  # # └─────┴─────┘
781
816
  def len
782
- _from_rbexpr(_rbexpr.len)
817
+ wrap_expr(_rbexpr.len)
783
818
  end
784
819
  alias_method :length, :len
785
820
 
@@ -818,7 +853,7 @@ module Polars
818
853
  if !length.is_a?(Expr)
819
854
  length = Polars.lit(length)
820
855
  end
821
- _from_rbexpr(_rbexpr.slice(offset._rbexpr, length._rbexpr))
856
+ wrap_expr(_rbexpr.slice(offset._rbexpr, length._rbexpr))
822
857
  end
823
858
 
824
859
  # Append expressions.
@@ -852,7 +887,7 @@ module Polars
852
887
  # # └─────┴──────┘
853
888
  def append(other, upcast: true)
854
889
  other = Utils.parse_into_expression(other)
855
- _from_rbexpr(_rbexpr.append(other, upcast))
890
+ wrap_expr(_rbexpr.append(other, upcast))
856
891
  end
857
892
 
858
893
  # Create a single chunk of memory for this Series.
@@ -877,7 +912,7 @@ module Polars
877
912
  # # │ 2 │
878
913
  # # └────────┘
879
914
  def rechunk
880
- _from_rbexpr(_rbexpr.rechunk)
915
+ wrap_expr(_rbexpr.rechunk)
881
916
  end
882
917
 
883
918
  # Drop null values.
@@ -904,7 +939,7 @@ module Polars
904
939
  # # │ NaN │
905
940
  # # └─────┘
906
941
  def drop_nulls
907
- _from_rbexpr(_rbexpr.drop_nulls)
942
+ wrap_expr(_rbexpr.drop_nulls)
908
943
  end
909
944
 
910
945
  # Drop floating point NaN values.
@@ -931,7 +966,7 @@ module Polars
931
966
  # # │ 4.0 │
932
967
  # # └──────┘
933
968
  def drop_nans
934
- _from_rbexpr(_rbexpr.drop_nans)
969
+ wrap_expr(_rbexpr.drop_nans)
935
970
  end
936
971
 
937
972
  # Get an array with the cumulative sum computed at every element.
@@ -966,7 +1001,7 @@ module Polars
966
1001
  # # │ 10 ┆ 4 │
967
1002
  # # └─────┴───────────┘
968
1003
  def cum_sum(reverse: false)
969
- _from_rbexpr(_rbexpr.cum_sum(reverse))
1004
+ wrap_expr(_rbexpr.cum_sum(reverse))
970
1005
  end
971
1006
  alias_method :cumsum, :cum_sum
972
1007
 
@@ -1002,7 +1037,7 @@ module Polars
1002
1037
  # # │ 24 ┆ 4 │
1003
1038
  # # └─────┴───────────┘
1004
1039
  def cum_prod(reverse: false)
1005
- _from_rbexpr(_rbexpr.cum_prod(reverse))
1040
+ wrap_expr(_rbexpr.cum_prod(reverse))
1006
1041
  end
1007
1042
  alias_method :cumprod, :cum_prod
1008
1043
 
@@ -1034,7 +1069,7 @@ module Polars
1034
1069
  # # │ 1 ┆ 4 │
1035
1070
  # # └─────┴───────────┘
1036
1071
  def cum_min(reverse: false)
1037
- _from_rbexpr(_rbexpr.cum_min(reverse))
1072
+ wrap_expr(_rbexpr.cum_min(reverse))
1038
1073
  end
1039
1074
  alias_method :cummin, :cum_min
1040
1075
 
@@ -1066,7 +1101,7 @@ module Polars
1066
1101
  # # │ 4 ┆ 4 │
1067
1102
  # # └─────┴───────────┘
1068
1103
  def cum_max(reverse: false)
1069
- _from_rbexpr(_rbexpr.cum_max(reverse))
1104
+ wrap_expr(_rbexpr.cum_max(reverse))
1070
1105
  end
1071
1106
  alias_method :cummax, :cum_max
1072
1107
 
@@ -1100,7 +1135,7 @@ module Polars
1100
1135
  # # │ d ┆ 3 ┆ 1 │
1101
1136
  # # └──────┴───────────┴───────────────────┘
1102
1137
  def cum_count(reverse: false)
1103
- _from_rbexpr(_rbexpr.cum_count(reverse))
1138
+ wrap_expr(_rbexpr.cum_count(reverse))
1104
1139
  end
1105
1140
  alias_method :cumcount, :cum_count
1106
1141
 
@@ -1126,7 +1161,7 @@ module Polars
1126
1161
  # # │ 1.0 │
1127
1162
  # # └─────┘
1128
1163
  def floor
1129
- _from_rbexpr(_rbexpr.floor)
1164
+ wrap_expr(_rbexpr.floor)
1130
1165
  end
1131
1166
 
1132
1167
  # Rounds up to the nearest integer value.
@@ -1151,13 +1186,20 @@ module Polars
1151
1186
  # # │ 2.0 │
1152
1187
  # # └─────┘
1153
1188
  def ceil
1154
- _from_rbexpr(_rbexpr.ceil)
1189
+ wrap_expr(_rbexpr.ceil)
1155
1190
  end
1156
1191
 
1157
1192
  # Round underlying floating point data by `decimals` digits.
1158
1193
  #
1159
1194
  # @param decimals [Integer]
1160
1195
  # Number of decimals to round by.
1196
+ # @param mode ['half_to_even', 'half_away_from_zero']
1197
+ # RoundMode.
1198
+ #
1199
+ # * *half_to_even*
1200
+ # round to the nearest even number
1201
+ # * *half_away_from_zero*
1202
+ # round to the nearest number away from zero
1161
1203
  #
1162
1204
  # @return [Expr]
1163
1205
  #
@@ -1177,7 +1219,32 @@ module Polars
1177
1219
  # # │ 1.2 │
1178
1220
  # # └─────┘
1179
1221
  def round(decimals = 0, mode: "half_to_even")
1180
- _from_rbexpr(_rbexpr.round(decimals, mode))
1222
+ wrap_expr(_rbexpr.round(decimals, mode))
1223
+ end
1224
+
1225
+ # Round to a number of significant figures.
1226
+ #
1227
+ # @param digits [Integer]
1228
+ # Number of significant figures to round to.
1229
+ #
1230
+ # @return [Expr]
1231
+ #
1232
+ # @example
1233
+ # df = Polars::DataFrame.new({"a" => [0.01234, 3.333, 1234.0]})
1234
+ # df.with_columns(Polars.col("a").round_sig_figs(2).alias("round_sig_figs"))
1235
+ # # =>
1236
+ # # shape: (3, 2)
1237
+ # # ┌─────────┬────────────────┐
1238
+ # # │ a ┆ round_sig_figs │
1239
+ # # │ --- ┆ --- │
1240
+ # # │ f64 ┆ f64 │
1241
+ # # ╞═════════╪════════════════╡
1242
+ # # │ 0.01234 ┆ 0.012 │
1243
+ # # │ 3.333 ┆ 3.3 │
1244
+ # # │ 1234.0 ┆ 1200.0 │
1245
+ # # └─────────┴────────────────┘
1246
+ def round_sig_figs(digits)
1247
+ wrap_expr(_rbexpr.round_sig_figs(digits))
1181
1248
  end
1182
1249
 
1183
1250
  # Compute the dot/inner product between two Expressions.
@@ -1206,7 +1273,7 @@ module Polars
1206
1273
  # # └─────┘
1207
1274
  def dot(other)
1208
1275
  other = Utils.parse_into_expression(other, str_as_lit: false)
1209
- _from_rbexpr(_rbexpr.dot(other))
1276
+ wrap_expr(_rbexpr.dot(other))
1210
1277
  end
1211
1278
 
1212
1279
  # Compute the most occurring value(s).
@@ -1234,7 +1301,7 @@ module Polars
1234
1301
  # # │ 1 ┆ 2 │
1235
1302
  # # └─────┴─────┘
1236
1303
  def mode
1237
- _from_rbexpr(_rbexpr.mode)
1304
+ wrap_expr(_rbexpr.mode)
1238
1305
  end
1239
1306
 
1240
1307
  # Cast between data types.
@@ -1273,7 +1340,7 @@ module Polars
1273
1340
  # # └─────┴─────┘
1274
1341
  def cast(dtype, strict: true)
1275
1342
  dtype = Utils.rb_type_to_dtype(dtype)
1276
- _from_rbexpr(_rbexpr.cast(dtype, strict))
1343
+ wrap_expr(_rbexpr.cast(dtype, strict))
1277
1344
  end
1278
1345
 
1279
1346
  # Sort this column. In projection/ selection context the whole column is sorted.
@@ -1348,7 +1415,7 @@ module Polars
1348
1415
  # # │ one ┆ [1, 2, 98] │
1349
1416
  # # └───────┴────────────┘
1350
1417
  def sort(reverse: false, nulls_last: false)
1351
- _from_rbexpr(_rbexpr.sort_with(reverse, nulls_last))
1418
+ wrap_expr(_rbexpr.sort_with(reverse, nulls_last))
1352
1419
  end
1353
1420
 
1354
1421
  # Return the `k` largest elements.
@@ -1387,7 +1454,113 @@ module Polars
1387
1454
  # # └───────┴──────────┘
1388
1455
  def top_k(k: 5)
1389
1456
  k = Utils.parse_into_expression(k)
1390
- _from_rbexpr(_rbexpr.top_k(k))
1457
+ wrap_expr(_rbexpr.top_k(k))
1458
+ end
1459
+
1460
+ # Return the elements corresponding to the `k` largest elements of the `by` column(s).
1461
+ #
1462
+ # Non-null elements are always preferred over null elements, regardless of
1463
+ # the value of `reverse`. The output is not guaranteed to be in any
1464
+ # particular order, call :func:`sort` after this function if you wish the
1465
+ # output to be sorted.
1466
+ #
1467
+ # @param by [Object]
1468
+ # Column(s) used to determine the largest elements.
1469
+ # Accepts expression input. Strings are parsed as column names.
1470
+ # @param k [Integer]
1471
+ # Number of elements to return.
1472
+ # @param reverse [Object]
1473
+ # Consider the `k` smallest elements of the `by` column(s) (instead of the `k`
1474
+ # largest). This can be specified per column by passing a sequence of
1475
+ # booleans.
1476
+ #
1477
+ # @return [Expr]
1478
+ #
1479
+ # @example
1480
+ # df = Polars::DataFrame.new(
1481
+ # {
1482
+ # "a" => [1, 2, 3, 4, 5, 6],
1483
+ # "b" => [6, 5, 4, 3, 2, 1],
1484
+ # "c" => ["Apple", "Orange", "Apple", "Apple", "Banana", "Banana"]
1485
+ # }
1486
+ # )
1487
+ # # =>
1488
+ # # shape: (6, 3)
1489
+ # # ┌─────┬─────┬────────┐
1490
+ # # │ a ┆ b ┆ c │
1491
+ # # │ --- ┆ --- ┆ --- │
1492
+ # # │ i64 ┆ i64 ┆ str │
1493
+ # # ╞═════╪═════╪════════╡
1494
+ # # │ 1 ┆ 6 ┆ Apple │
1495
+ # # │ 2 ┆ 5 ┆ Orange │
1496
+ # # │ 3 ┆ 4 ┆ Apple │
1497
+ # # │ 4 ┆ 3 ┆ Apple │
1498
+ # # │ 5 ┆ 2 ┆ Banana │
1499
+ # # │ 6 ┆ 1 ┆ Banana │
1500
+ # # └─────┴─────┴────────┘
1501
+ #
1502
+ # @example Get the top 2 rows by column `a` or `b`.
1503
+ # df.select(
1504
+ # Polars.all.top_k_by("a", k: 2).name.suffix("_top_by_a"),
1505
+ # Polars.all.top_k_by("b", k: 2).name.suffix("_top_by_b")
1506
+ # )
1507
+ # # =>
1508
+ # # shape: (2, 6)
1509
+ # # ┌────────────┬────────────┬────────────┬────────────┬────────────┬────────────┐
1510
+ # # │ a_top_by_a ┆ b_top_by_a ┆ c_top_by_a ┆ a_top_by_b ┆ b_top_by_b ┆ c_top_by_b │
1511
+ # # │ --- ┆ --- ┆ --- ┆ --- ┆ --- ┆ --- │
1512
+ # # │ i64 ┆ i64 ┆ str ┆ i64 ┆ i64 ┆ str │
1513
+ # # ╞════════════╪════════════╪════════════╪════════════╪════════════╪════════════╡
1514
+ # # │ 6 ┆ 1 ┆ Banana ┆ 1 ┆ 6 ┆ Apple │
1515
+ # # │ 5 ┆ 2 ┆ Banana ┆ 2 ┆ 5 ┆ Orange │
1516
+ # # └────────────┴────────────┴────────────┴────────────┴────────────┴────────────┘
1517
+ #
1518
+ # @example Get the top 2 rows by multiple columns with given order.
1519
+ # df.select(
1520
+ # Polars.all
1521
+ # .top_k_by(["c", "a"], k: 2, reverse: [false, true])
1522
+ # .name.suffix("_by_ca"),
1523
+ # Polars.all
1524
+ # .top_k_by(["c", "b"], k: 2, reverse: [false, true])
1525
+ # .name.suffix("_by_cb")
1526
+ # )
1527
+ # # =>
1528
+ # # shape: (2, 6)
1529
+ # # ┌─────────┬─────────┬─────────┬─────────┬─────────┬─────────┐
1530
+ # # │ a_by_ca ┆ b_by_ca ┆ c_by_ca ┆ a_by_cb ┆ b_by_cb ┆ c_by_cb │
1531
+ # # │ --- ┆ --- ┆ --- ┆ --- ┆ --- ┆ --- │
1532
+ # # │ i64 ┆ i64 ┆ str ┆ i64 ┆ i64 ┆ str │
1533
+ # # ╞═════════╪═════════╪═════════╪═════════╪═════════╪═════════╡
1534
+ # # │ 2 ┆ 5 ┆ Orange ┆ 2 ┆ 5 ┆ Orange │
1535
+ # # │ 5 ┆ 2 ┆ Banana ┆ 6 ┆ 1 ┆ Banana │
1536
+ # # └─────────┴─────────┴─────────┴─────────┴─────────┴─────────┘
1537
+ #
1538
+ # @example Get the top 2 rows by column `a` in each group.
1539
+ # df.group_by("c", maintain_order: true)
1540
+ # .agg(Polars.all.top_k_by("a", k: 2))
1541
+ # .explode(Polars.all.exclude("c"))
1542
+ # # =>
1543
+ # # shape: (5, 3)
1544
+ # # ┌────────┬─────┬─────┐
1545
+ # # │ c ┆ a ┆ b │
1546
+ # # │ --- ┆ --- ┆ --- │
1547
+ # # │ str ┆ i64 ┆ i64 │
1548
+ # # ╞════════╪═════╪═════╡
1549
+ # # │ Apple ┆ 4 ┆ 3 │
1550
+ # # │ Apple ┆ 3 ┆ 4 │
1551
+ # # │ Orange ┆ 2 ┆ 5 │
1552
+ # # │ Banana ┆ 6 ┆ 1 │
1553
+ # # │ Banana ┆ 5 ┆ 2 │
1554
+ # # └────────┴─────┴─────┘
1555
+ def top_k_by(
1556
+ by,
1557
+ k: 5,
1558
+ reverse: false
1559
+ )
1560
+ k = Utils.parse_into_expression(k)
1561
+ by = Utils.parse_into_list_of_expressions(by)
1562
+ reverse = Utils.extend_bool(reverse, by.length, "reverse", "by")
1563
+ wrap_expr(_rbexpr.top_k_by(by, k, reverse))
1391
1564
  end
1392
1565
 
1393
1566
  # Return the `k` smallest elements.
@@ -1426,7 +1599,113 @@ module Polars
1426
1599
  # # └───────┴──────────┘
1427
1600
  def bottom_k(k: 5)
1428
1601
  k = Utils.parse_into_expression(k)
1429
- _from_rbexpr(_rbexpr.bottom_k(k))
1602
+ wrap_expr(_rbexpr.bottom_k(k))
1603
+ end
1604
+
1605
+ # Return the elements corresponding to the `k` smallest elements of the `by` column(s).
1606
+ #
1607
+ # Non-null elements are always preferred over null elements, regardless of
1608
+ # the value of `reverse`. The output is not guaranteed to be in any
1609
+ # particular order, call :func:`sort` after this function if you wish the
1610
+ # output to be sorted.
1611
+ #
1612
+ # @param by [Object]
1613
+ # Column(s) used to determine the smallest elements.
1614
+ # Accepts expression input. Strings are parsed as column names.
1615
+ # @param k [Integer]
1616
+ # Number of elements to return.
1617
+ # @param reverse [Object]
1618
+ # Consider the `k` largest elements of the `by` column(s) (instead of the `k`
1619
+ # smallest). This can be specified per column by passing a sequence of
1620
+ # booleans.
1621
+ #
1622
+ # @return [Expr]
1623
+ #
1624
+ # @example
1625
+ # df = Polars::DataFrame.new(
1626
+ # {
1627
+ # "a" => [1, 2, 3, 4, 5, 6],
1628
+ # "b" => [6, 5, 4, 3, 2, 1],
1629
+ # "c" => ["Apple", "Orange", "Apple", "Apple", "Banana", "Banana"],
1630
+ # }
1631
+ # )
1632
+ # # =>
1633
+ # # shape: (6, 3)
1634
+ # # ┌─────┬─────┬────────┐
1635
+ # # │ a ┆ b ┆ c │
1636
+ # # │ --- ┆ --- ┆ --- │
1637
+ # # │ i64 ┆ i64 ┆ str │
1638
+ # # ╞═════╪═════╪════════╡
1639
+ # # │ 1 ┆ 6 ┆ Apple │
1640
+ # # │ 2 ┆ 5 ┆ Orange │
1641
+ # # │ 3 ┆ 4 ┆ Apple │
1642
+ # # │ 4 ┆ 3 ┆ Apple │
1643
+ # # │ 5 ┆ 2 ┆ Banana │
1644
+ # # │ 6 ┆ 1 ┆ Banana │
1645
+ # # └─────┴─────┴────────┘
1646
+ #
1647
+ # @example Get the bottom 2 rows by column `a` or `b`.
1648
+ # df.select(
1649
+ # Polars.all.bottom_k_by("a", k: 2).name.suffix("_btm_by_a"),
1650
+ # Polars.all.bottom_k_by("b", k: 2).name.suffix("_btm_by_b")
1651
+ # )
1652
+ # # =>
1653
+ # # shape: (2, 6)
1654
+ # # ┌────────────┬────────────┬────────────┬────────────┬────────────┬────────────┐
1655
+ # # │ a_btm_by_a ┆ b_btm_by_a ┆ c_btm_by_a ┆ a_btm_by_b ┆ b_btm_by_b ┆ c_btm_by_b │
1656
+ # # │ --- ┆ --- ┆ --- ┆ --- ┆ --- ┆ --- │
1657
+ # # │ i64 ┆ i64 ┆ str ┆ i64 ┆ i64 ┆ str │
1658
+ # # ╞════════════╪════════════╪════════════╪════════════╪════════════╪════════════╡
1659
+ # # │ 1 ┆ 6 ┆ Apple ┆ 6 ┆ 1 ┆ Banana │
1660
+ # # │ 2 ┆ 5 ┆ Orange ┆ 5 ┆ 2 ┆ Banana │
1661
+ # # └────────────┴────────────┴────────────┴────────────┴────────────┴────────────┘
1662
+ #
1663
+ # @example Get the bottom 2 rows by multiple columns with given order.
1664
+ # df.select(
1665
+ # Polars.all
1666
+ # .bottom_k_by(["c", "a"], k: 2, reverse: [false, true])
1667
+ # .name.suffix("_by_ca"),
1668
+ # Polars.all
1669
+ # .bottom_k_by(["c", "b"], k: 2, reverse: [false, true])
1670
+ # .name.suffix("_by_cb"),
1671
+ # )
1672
+ # # =>
1673
+ # # shape: (2, 6)
1674
+ # # ┌─────────┬─────────┬─────────┬─────────┬─────────┬─────────┐
1675
+ # # │ a_by_ca ┆ b_by_ca ┆ c_by_ca ┆ a_by_cb ┆ b_by_cb ┆ c_by_cb │
1676
+ # # │ --- ┆ --- ┆ --- ┆ --- ┆ --- ┆ --- │
1677
+ # # │ i64 ┆ i64 ┆ str ┆ i64 ┆ i64 ┆ str │
1678
+ # # ╞═════════╪═════════╪═════════╪═════════╪═════════╪═════════╡
1679
+ # # │ 4 ┆ 3 ┆ Apple ┆ 1 ┆ 6 ┆ Apple │
1680
+ # # │ 3 ┆ 4 ┆ Apple ┆ 3 ┆ 4 ┆ Apple │
1681
+ # # └─────────┴─────────┴─────────┴─────────┴─────────┴─────────┘
1682
+ #
1683
+ # @example Get the bottom 2 rows by column `a` in each group.
1684
+ # df.group_by("c", maintain_order: true)
1685
+ # .agg(Polars.all.bottom_k_by("a", k: 2))
1686
+ # .explode(Polars.all.exclude("c"))
1687
+ # # =>
1688
+ # # shape: (5, 3)
1689
+ # # ┌────────┬─────┬─────┐
1690
+ # # │ c ┆ a ┆ b │
1691
+ # # │ --- ┆ --- ┆ --- │
1692
+ # # │ str ┆ i64 ┆ i64 │
1693
+ # # ╞════════╪═════╪═════╡
1694
+ # # │ Apple ┆ 1 ┆ 6 │
1695
+ # # │ Apple ┆ 3 ┆ 4 │
1696
+ # # │ Orange ┆ 2 ┆ 5 │
1697
+ # # │ Banana ┆ 5 ┆ 2 │
1698
+ # # │ Banana ┆ 6 ┆ 1 │
1699
+ # # └────────┴─────┴─────┘
1700
+ def bottom_k_by(
1701
+ by,
1702
+ k: 5,
1703
+ reverse: false
1704
+ )
1705
+ k = Utils.parse_into_expression(k)
1706
+ by = Utils.parse_into_list_of_expressions(by)
1707
+ reverse = Utils.extend_bool(reverse, by.length, "reverse", "by")
1708
+ wrap_expr(_rbexpr.bottom_k_by(by, k, reverse))
1430
1709
  end
1431
1710
 
1432
1711
  # Get the index values that would sort this column.
@@ -1457,7 +1736,7 @@ module Polars
1457
1736
  # # │ 2 │
1458
1737
  # # └─────┘
1459
1738
  def arg_sort(reverse: false, nulls_last: false)
1460
- _from_rbexpr(_rbexpr.arg_sort(reverse, nulls_last))
1739
+ wrap_expr(_rbexpr.arg_sort(reverse, nulls_last))
1461
1740
  end
1462
1741
 
1463
1742
  # Get the index of the maximal value.
@@ -1481,7 +1760,7 @@ module Polars
1481
1760
  # # │ 2 │
1482
1761
  # # └─────┘
1483
1762
  def arg_max
1484
- _from_rbexpr(_rbexpr.arg_max)
1763
+ wrap_expr(_rbexpr.arg_max)
1485
1764
  end
1486
1765
 
1487
1766
  # Get the index of the minimal value.
@@ -1505,7 +1784,37 @@ module Polars
1505
1784
  # # │ 1 │
1506
1785
  # # └─────┘
1507
1786
  def arg_min
1508
- _from_rbexpr(_rbexpr.arg_min)
1787
+ wrap_expr(_rbexpr.arg_min)
1788
+ end
1789
+
1790
+ # Get the index of the first occurrence of a value, or ``None`` if it's not found.
1791
+ #
1792
+ # @param element [Object]
1793
+ # Value to find.
1794
+ #
1795
+ # @return [Expr]
1796
+ #
1797
+ # @example
1798
+ # df = Polars::DataFrame.new({"a" => [1, nil, 17]})
1799
+ # df.select(
1800
+ # [
1801
+ # Polars.col("a").index_of(17).alias("seventeen"),
1802
+ # Polars.col("a").index_of(nil).alias("null"),
1803
+ # Polars.col("a").index_of(55).alias("fiftyfive")
1804
+ # ]
1805
+ # )
1806
+ # # =>
1807
+ # # shape: (1, 3)
1808
+ # # ┌───────────┬──────┬───────────┐
1809
+ # # │ seventeen ┆ null ┆ fiftyfive │
1810
+ # # │ --- ┆ --- ┆ --- │
1811
+ # # │ u32 ┆ u32 ┆ u32 │
1812
+ # # ╞═══════════╪══════╪═══════════╡
1813
+ # # │ 2 ┆ 1 ┆ null │
1814
+ # # └───────────┴──────┴───────────┘
1815
+ def index_of(element)
1816
+ element = Utils.parse_into_expression(element, str_as_lit: true)
1817
+ wrap_expr(_rbexpr.index_of(element))
1509
1818
  end
1510
1819
 
1511
1820
  # Find indices where elements should be inserted to maintain order.
@@ -1546,7 +1855,7 @@ module Polars
1546
1855
  # # └──────┴───────┴─────┘
1547
1856
  def search_sorted(element, side: "any", descending: false)
1548
1857
  element = Utils.parse_into_expression(element, str_as_lit: false)
1549
- _from_rbexpr(_rbexpr.search_sorted(element, side, descending))
1858
+ wrap_expr(_rbexpr.search_sorted(element, side, descending))
1550
1859
  end
1551
1860
 
1552
1861
  # Sort this column by the ordering of another column, or multiple other columns.
@@ -1556,9 +1865,18 @@ module Polars
1556
1865
  #
1557
1866
  # @param by [Object]
1558
1867
  # The column(s) used for sorting.
1868
+ # @param more_by [Array]
1869
+ # Additional columns to sort by, specified as positional arguments.
1559
1870
  # @param reverse [Boolean]
1560
1871
  # false -> order from small to large.
1561
1872
  # true -> order from large to small.
1873
+ # @param nulls_last [Boolean]
1874
+ # Place null values last; can specify a single boolean applying to all columns
1875
+ # or a sequence of booleans for per-column control.
1876
+ # @param multithreaded [Boolean]
1877
+ # Sort using multiple threads.
1878
+ # @param maintain_order [Boolean]
1879
+ # Whether the order should be maintained if elements are equal.
1562
1880
  #
1563
1881
  # @return [Expr]
1564
1882
  #
@@ -1595,7 +1913,7 @@ module Polars
1595
1913
  by = Utils.parse_into_list_of_expressions(by, *more_by)
1596
1914
  reverse = Utils.extend_bool(reverse, by.length, "reverse", "by")
1597
1915
  nulls_last = Utils.extend_bool(nulls_last, by.length, "nulls_last", "by")
1598
- _from_rbexpr(
1916
+ wrap_expr(
1599
1917
  _rbexpr.sort_by(
1600
1918
  by, reverse, nulls_last, multithreaded, maintain_order
1601
1919
  )
@@ -1640,7 +1958,7 @@ module Polars
1640
1958
  else
1641
1959
  indices_lit = Utils.parse_into_expression(indices, str_as_lit: false)
1642
1960
  end
1643
- _from_rbexpr(_rbexpr.gather(indices_lit))
1961
+ wrap_expr(_rbexpr.gather(indices_lit))
1644
1962
  end
1645
1963
  alias_method :take, :gather
1646
1964
 
@@ -1678,7 +1996,7 @@ module Polars
1678
1996
  # # └───────┴───────┘
1679
1997
  def get(index)
1680
1998
  index_lit = Utils.parse_into_expression(index)
1681
- _from_rbexpr(_rbexpr.get(index_lit))
1999
+ wrap_expr(_rbexpr.get(index_lit))
1682
2000
  end
1683
2001
 
1684
2002
  # Shift the values by a given period.
@@ -1710,7 +2028,7 @@ module Polars
1710
2028
  fill_value = Utils.parse_into_expression(fill_value, str_as_lit: true)
1711
2029
  end
1712
2030
  n = Utils.parse_into_expression(n)
1713
- _from_rbexpr(_rbexpr.shift(n, fill_value))
2031
+ wrap_expr(_rbexpr.shift(n, fill_value))
1714
2032
  end
1715
2033
 
1716
2034
  # Shift the values by a given period and fill the resulting null values.
@@ -1813,9 +2131,9 @@ module Polars
1813
2131
 
1814
2132
  if !value.nil?
1815
2133
  value = Utils.parse_into_expression(value, str_as_lit: true)
1816
- _from_rbexpr(_rbexpr.fill_null(value))
2134
+ wrap_expr(_rbexpr.fill_null(value))
1817
2135
  else
1818
- _from_rbexpr(_rbexpr.fill_null_with_strategy(strategy, limit))
2136
+ wrap_expr(_rbexpr.fill_null_with_strategy(strategy, limit))
1819
2137
  end
1820
2138
  end
1821
2139
 
@@ -1844,7 +2162,7 @@ module Polars
1844
2162
  # # └──────┴──────┘
1845
2163
  def fill_nan(fill_value)
1846
2164
  fill_value = Utils.parse_into_expression(fill_value, str_as_lit: true)
1847
- _from_rbexpr(_rbexpr.fill_nan(fill_value))
2165
+ wrap_expr(_rbexpr.fill_nan(fill_value))
1848
2166
  end
1849
2167
 
1850
2168
  # Fill missing values with the latest seen values.
@@ -1940,7 +2258,7 @@ module Polars
1940
2258
  # # │ 5 ┆ banana ┆ 1 ┆ beetle ┆ 1 ┆ banana ┆ 5 ┆ beetle │
1941
2259
  # # └─────┴────────┴─────┴────────┴───────────┴────────────────┴───────────┴──────────────┘
1942
2260
  def reverse
1943
- _from_rbexpr(_rbexpr.reverse)
2261
+ wrap_expr(_rbexpr.reverse)
1944
2262
  end
1945
2263
 
1946
2264
  # Get standard deviation.
@@ -1963,7 +2281,7 @@ module Polars
1963
2281
  # # │ 1.0 │
1964
2282
  # # └─────┘
1965
2283
  def std(ddof: 1)
1966
- _from_rbexpr(_rbexpr.std(ddof))
2284
+ wrap_expr(_rbexpr.std(ddof))
1967
2285
  end
1968
2286
 
1969
2287
  # Get variance.
@@ -1986,7 +2304,7 @@ module Polars
1986
2304
  # # │ 1.0 │
1987
2305
  # # └─────┘
1988
2306
  def var(ddof: 1)
1989
- _from_rbexpr(_rbexpr.var(ddof))
2307
+ wrap_expr(_rbexpr.var(ddof))
1990
2308
  end
1991
2309
 
1992
2310
  # Get maximum value.
@@ -2006,7 +2324,7 @@ module Polars
2006
2324
  # # │ 1.0 │
2007
2325
  # # └─────┘
2008
2326
  def max
2009
- _from_rbexpr(_rbexpr.max)
2327
+ wrap_expr(_rbexpr.max)
2010
2328
  end
2011
2329
 
2012
2330
  # Get minimum value.
@@ -2026,7 +2344,7 @@ module Polars
2026
2344
  # # │ -1.0 │
2027
2345
  # # └──────┘
2028
2346
  def min
2029
- _from_rbexpr(_rbexpr.min)
2347
+ wrap_expr(_rbexpr.min)
2030
2348
  end
2031
2349
 
2032
2350
  # Get maximum value, but propagate/poison encountered NaN values.
@@ -2046,7 +2364,7 @@ module Polars
2046
2364
  # # │ NaN │
2047
2365
  # # └─────┘
2048
2366
  def nan_max
2049
- _from_rbexpr(_rbexpr.nan_max)
2367
+ wrap_expr(_rbexpr.nan_max)
2050
2368
  end
2051
2369
 
2052
2370
  # Get minimum value, but propagate/poison encountered NaN values.
@@ -2066,7 +2384,7 @@ module Polars
2066
2384
  # # │ NaN │
2067
2385
  # # └─────┘
2068
2386
  def nan_min
2069
- _from_rbexpr(_rbexpr.nan_min)
2387
+ wrap_expr(_rbexpr.nan_min)
2070
2388
  end
2071
2389
 
2072
2390
  # Get sum value.
@@ -2090,7 +2408,7 @@ module Polars
2090
2408
  # # │ 0 │
2091
2409
  # # └─────┘
2092
2410
  def sum
2093
- _from_rbexpr(_rbexpr.sum)
2411
+ wrap_expr(_rbexpr.sum)
2094
2412
  end
2095
2413
 
2096
2414
  # Get mean value.
@@ -2110,7 +2428,7 @@ module Polars
2110
2428
  # # │ 0.0 │
2111
2429
  # # └─────┘
2112
2430
  def mean
2113
- _from_rbexpr(_rbexpr.mean)
2431
+ wrap_expr(_rbexpr.mean)
2114
2432
  end
2115
2433
 
2116
2434
  # Get median value using linear interpolation.
@@ -2130,7 +2448,7 @@ module Polars
2130
2448
  # # │ 0.0 │
2131
2449
  # # └─────┘
2132
2450
  def median
2133
- _from_rbexpr(_rbexpr.median)
2451
+ wrap_expr(_rbexpr.median)
2134
2452
  end
2135
2453
 
2136
2454
  # Compute the product of an expression.
@@ -2150,7 +2468,7 @@ module Polars
2150
2468
  # # │ 6 │
2151
2469
  # # └─────┘
2152
2470
  def product
2153
- _from_rbexpr(_rbexpr.product)
2471
+ wrap_expr(_rbexpr.product)
2154
2472
  end
2155
2473
 
2156
2474
  # Count unique values.
@@ -2170,7 +2488,7 @@ module Polars
2170
2488
  # # │ 2 │
2171
2489
  # # └─────┘
2172
2490
  def n_unique
2173
- _from_rbexpr(_rbexpr.n_unique)
2491
+ wrap_expr(_rbexpr.n_unique)
2174
2492
  end
2175
2493
 
2176
2494
  # Approx count unique values.
@@ -2192,7 +2510,7 @@ module Polars
2192
2510
  # # │ 2 │
2193
2511
  # # └─────┘
2194
2512
  def approx_n_unique
2195
- _from_rbexpr(_rbexpr.approx_n_unique)
2513
+ wrap_expr(_rbexpr.approx_n_unique)
2196
2514
  end
2197
2515
  alias_method :approx_unique, :approx_n_unique
2198
2516
 
@@ -2218,7 +2536,33 @@ module Polars
2218
2536
  # # │ 2 ┆ 0 │
2219
2537
  # # └─────┴─────┘
2220
2538
  def null_count
2221
- _from_rbexpr(_rbexpr.null_count)
2539
+ wrap_expr(_rbexpr.null_count)
2540
+ end
2541
+
2542
+ # Check whether the expression contains one or more null values.
2543
+ #
2544
+ # @return [Expr]
2545
+ #
2546
+ # @example
2547
+ # df = Polars::DataFrame.new(
2548
+ # {
2549
+ # "a" => [nil, 1, nil],
2550
+ # "b" => [10, nil, 300],
2551
+ # "c" => [350, 650, 850]
2552
+ # }
2553
+ # )
2554
+ # df.select(Polars.all.has_nulls)
2555
+ # # =>
2556
+ # # shape: (1, 3)
2557
+ # # ┌──────┬──────┬───────┐
2558
+ # # │ a ┆ b ┆ c │
2559
+ # # │ --- ┆ --- ┆ --- │
2560
+ # # │ bool ┆ bool ┆ bool │
2561
+ # # ╞══════╪══════╪═══════╡
2562
+ # # │ true ┆ true ┆ false │
2563
+ # # └──────┴──────┴───────┘
2564
+ def has_nulls
2565
+ null_count > 0
2222
2566
  end
2223
2567
 
2224
2568
  # Get index of first unique value.
@@ -2258,7 +2602,7 @@ module Polars
2258
2602
  # # │ 1 │
2259
2603
  # # └─────┘
2260
2604
  def arg_unique
2261
- _from_rbexpr(_rbexpr.arg_unique)
2605
+ wrap_expr(_rbexpr.arg_unique)
2262
2606
  end
2263
2607
 
2264
2608
  # Get unique values of this expression.
@@ -2283,9 +2627,9 @@ module Polars
2283
2627
  # # └─────┘
2284
2628
  def unique(maintain_order: false)
2285
2629
  if maintain_order
2286
- _from_rbexpr(_rbexpr.unique_stable)
2630
+ wrap_expr(_rbexpr.unique_stable)
2287
2631
  else
2288
- _from_rbexpr(_rbexpr.unique)
2632
+ wrap_expr(_rbexpr.unique)
2289
2633
  end
2290
2634
  end
2291
2635
 
@@ -2306,7 +2650,7 @@ module Polars
2306
2650
  # # │ 1 │
2307
2651
  # # └─────┘
2308
2652
  def first
2309
- _from_rbexpr(_rbexpr.first)
2653
+ wrap_expr(_rbexpr.first)
2310
2654
  end
2311
2655
 
2312
2656
  # Get the last value.
@@ -2326,7 +2670,7 @@ module Polars
2326
2670
  # # │ 2 │
2327
2671
  # # └─────┘
2328
2672
  def last
2329
- _from_rbexpr(_rbexpr.last)
2673
+ wrap_expr(_rbexpr.last)
2330
2674
  end
2331
2675
 
2332
2676
  # Apply window function over a subgroup.
@@ -2390,7 +2734,110 @@ module Polars
2390
2734
  # # └────────┘
2391
2735
  def over(expr)
2392
2736
  rbexprs = Utils.parse_into_list_of_expressions(expr)
2393
- _from_rbexpr(_rbexpr.over(rbexprs))
2737
+ wrap_expr(_rbexpr.over(rbexprs))
2738
+ end
2739
+
2740
+ # Create rolling groups based on a temporal or integer column.
2741
+ #
2742
+ # If you have a time series `<t_0, t_1, ..., t_n>`, then by default the
2743
+ # windows created will be
2744
+ #
2745
+ # * (t_0 - period, t_0]
2746
+ # * (t_1 - period, t_1]
2747
+ # * ...
2748
+ # * (t_n - period, t_n]
2749
+ #
2750
+ # whereas if you pass a non-default `offset`, then the windows will be
2751
+ #
2752
+ # * (t_0 + offset, t_0 + offset + period]
2753
+ # * (t_1 + offset, t_1 + offset + period]
2754
+ # * ...
2755
+ # * (t_n + offset, t_n + offset + period]
2756
+ #
2757
+ # The `period` and `offset` arguments are created either from a timedelta, or
2758
+ # by using the following string language:
2759
+ #
2760
+ # - 1ns (1 nanosecond)
2761
+ # - 1us (1 microsecond)
2762
+ # - 1ms (1 millisecond)
2763
+ # - 1s (1 second)
2764
+ # - 1m (1 minute)
2765
+ # - 1h (1 hour)
2766
+ # - 1d (1 calendar day)
2767
+ # - 1w (1 calendar week)
2768
+ # - 1mo (1 calendar month)
2769
+ # - 1q (1 calendar quarter)
2770
+ # - 1y (1 calendar year)
2771
+ # - 1i (1 index count)
2772
+ #
2773
+ # Or combine them:
2774
+ # "3d12h4m25s" # 3 days, 12 hours, 4 minutes, and 25 seconds
2775
+ #
2776
+ # By "calendar day", we mean the corresponding time on the next day (which may
2777
+ # not be 24 hours, due to daylight savings). Similarly for "calendar week",
2778
+ # "calendar month", "calendar quarter", and "calendar year".
2779
+ #
2780
+ # @param index_column [Object]
2781
+ # Column used to group based on the time window.
2782
+ # Often of type Date/Datetime.
2783
+ # This column must be sorted in ascending order.
2784
+ # In case of a rolling group by on indices, dtype needs to be one of
2785
+ # \\\\{UInt32, UInt64, Int32, Int64}. Note that the first three get temporarily
2786
+ # cast to Int64, so if performance matters use an Int64 column.
2787
+ # @param period [Object]
2788
+ # Length of the window - must be non-negative.
2789
+ # @param offset [Object]
2790
+ # Offset of the window. Default is `-period`.
2791
+ # @param closed ['right', 'left', 'both', 'none']
2792
+ # Define which sides of the temporal interval are closed (inclusive).
2793
+ #
2794
+ # @return [Expr]
2795
+ #
2796
+ # @example
2797
+ # dates = [
2798
+ # "2020-01-01 13:45:48",
2799
+ # "2020-01-01 16:42:13",
2800
+ # "2020-01-01 16:45:09",
2801
+ # "2020-01-02 18:12:48",
2802
+ # "2020-01-03 19:45:32",
2803
+ # "2020-01-08 23:16:43"
2804
+ # ]
2805
+ # df = Polars::DataFrame.new({"dt" => dates, "a": [3, 7, 5, 9, 2, 1]}).with_columns(
2806
+ # Polars.col("dt").str.strptime(Polars::Datetime).set_sorted
2807
+ # )
2808
+ # df.with_columns(
2809
+ # sum_a: Polars.sum("a").rolling(index_column: "dt", period: "2d"),
2810
+ # min_a: Polars.min("a").rolling(index_column: "dt", period: "2d"),
2811
+ # max_a: Polars.max("a").rolling(index_column: "dt", period: "2d")
2812
+ # )
2813
+ # # =>
2814
+ # # shape: (6, 5)
2815
+ # # ┌─────────────────────┬─────┬───────┬───────┬───────┐
2816
+ # # │ dt ┆ a ┆ sum_a ┆ min_a ┆ max_a │
2817
+ # # │ --- ┆ --- ┆ --- ┆ --- ┆ --- │
2818
+ # # │ datetime[μs] ┆ i64 ┆ i64 ┆ i64 ┆ i64 │
2819
+ # # ╞═════════════════════╪═════╪═══════╪═══════╪═══════╡
2820
+ # # │ 2020-01-01 13:45:48 ┆ 3 ┆ 3 ┆ 3 ┆ 3 │
2821
+ # # │ 2020-01-01 16:42:13 ┆ 7 ┆ 10 ┆ 3 ┆ 7 │
2822
+ # # │ 2020-01-01 16:45:09 ┆ 5 ┆ 15 ┆ 3 ┆ 7 │
2823
+ # # │ 2020-01-02 18:12:48 ┆ 9 ┆ 24 ┆ 3 ┆ 9 │
2824
+ # # │ 2020-01-03 19:45:32 ┆ 2 ┆ 11 ┆ 2 ┆ 9 │
2825
+ # # │ 2020-01-08 23:16:43 ┆ 1 ┆ 1 ┆ 1 ┆ 1 │
2826
+ # # └─────────────────────┴─────┴───────┴───────┴───────┘
2827
+ def rolling(
2828
+ index_column:,
2829
+ period:,
2830
+ offset: nil,
2831
+ closed: "right"
2832
+ )
2833
+ if offset.nil?
2834
+ offset = Utils.negate_duration_string(Utils.parse_as_duration_string(period))
2835
+ end
2836
+
2837
+ period = Utils.parse_as_duration_string(period)
2838
+ offset = Utils.parse_as_duration_string(offset)
2839
+
2840
+ wrap_expr(_rbexpr.rolling(index_column, period, offset, closed))
2394
2841
  end
2395
2842
 
2396
2843
  # Get mask of unique values.
@@ -2412,7 +2859,7 @@ module Polars
2412
2859
  # # │ true │
2413
2860
  # # └───────┘
2414
2861
  def is_unique
2415
- _from_rbexpr(_rbexpr.is_unique)
2862
+ wrap_expr(_rbexpr.is_unique)
2416
2863
  end
2417
2864
 
2418
2865
  # Get a mask of the first unique value.
@@ -2440,10 +2887,34 @@ module Polars
2440
2887
  # # │ 5 ┆ true │
2441
2888
  # # └─────┴──────────┘
2442
2889
  def is_first_distinct
2443
- _from_rbexpr(_rbexpr.is_first_distinct)
2890
+ wrap_expr(_rbexpr.is_first_distinct)
2444
2891
  end
2445
2892
  alias_method :is_first, :is_first_distinct
2446
2893
 
2894
+ # Return a boolean mask indicating the last occurrence of each distinct value.
2895
+ #
2896
+ # @return [Expr]
2897
+ #
2898
+ # @example
2899
+ # df = Polars::DataFrame.new({"a" => [1, 1, 2, 3, 2]})
2900
+ # df.with_columns(Polars.col("a").is_last_distinct.alias("last"))
2901
+ # # =>
2902
+ # # shape: (5, 2)
2903
+ # # ┌─────┬───────┐
2904
+ # # │ a ┆ last │
2905
+ # # │ --- ┆ --- │
2906
+ # # │ i64 ┆ bool │
2907
+ # # ╞═════╪═══════╡
2908
+ # # │ 1 ┆ false │
2909
+ # # │ 1 ┆ true │
2910
+ # # │ 2 ┆ false │
2911
+ # # │ 3 ┆ true │
2912
+ # # │ 2 ┆ true │
2913
+ # # └─────┴───────┘
2914
+ def is_last_distinct
2915
+ wrap_expr(_rbexpr.is_last_distinct)
2916
+ end
2917
+
2447
2918
  # Get mask of duplicated values.
2448
2919
  #
2449
2920
  # @return [Expr]
@@ -2463,7 +2934,7 @@ module Polars
2463
2934
  # # │ false │
2464
2935
  # # └───────┘
2465
2936
  def is_duplicated
2466
- _from_rbexpr(_rbexpr.is_duplicated)
2937
+ wrap_expr(_rbexpr.is_duplicated)
2467
2938
  end
2468
2939
 
2469
2940
  # Get a boolean mask of the local maximum peaks.
@@ -2487,7 +2958,7 @@ module Polars
2487
2958
  # # │ true │
2488
2959
  # # └───────┘
2489
2960
  def peak_max
2490
- _from_rbexpr(_rbexpr.peak_max)
2961
+ wrap_expr(_rbexpr.peak_max)
2491
2962
  end
2492
2963
 
2493
2964
  # Get a boolean mask of the local minimum peaks.
@@ -2511,7 +2982,7 @@ module Polars
2511
2982
  # # │ false │
2512
2983
  # # └───────┘
2513
2984
  def peak_min
2514
- _from_rbexpr(_rbexpr.peak_min)
2985
+ wrap_expr(_rbexpr.peak_min)
2515
2986
  end
2516
2987
 
2517
2988
  # Get quantile value.
@@ -2585,7 +3056,7 @@ module Polars
2585
3056
  # # └─────┘
2586
3057
  def quantile(quantile, interpolation: "nearest")
2587
3058
  quantile = Utils.parse_into_expression(quantile, str_as_lit: false)
2588
- _from_rbexpr(_rbexpr.quantile(quantile, interpolation))
3059
+ wrap_expr(_rbexpr.quantile(quantile, interpolation))
2589
3060
  end
2590
3061
 
2591
3062
  # Bin continuous values into discrete categories.
@@ -2641,7 +3112,7 @@ module Polars
2641
3112
  # # │ 2 ┆ inf ┆ (1, inf] │
2642
3113
  # # └─────┴────────────┴────────────┘
2643
3114
  def cut(breaks, labels: nil, left_closed: false, include_breaks: false)
2644
- _from_rbexpr(_rbexpr.cut(breaks, labels, left_closed, include_breaks))
3115
+ wrap_expr(_rbexpr.cut(breaks, labels, left_closed, include_breaks))
2645
3116
  end
2646
3117
 
2647
3118
  # Bin continuous values into discrete categories based on their quantiles.
@@ -2732,7 +3203,7 @@ module Polars
2732
3203
  )
2733
3204
  end
2734
3205
 
2735
- _from_rbexpr(rbexpr)
3206
+ wrap_expr(rbexpr)
2736
3207
  end
2737
3208
 
2738
3209
  # Get the lengths of runs of identical values.
@@ -2757,7 +3228,7 @@ module Polars
2757
3228
  # # │ 2 ┆ 3 │
2758
3229
  # # └─────┴───────┘
2759
3230
  def rle
2760
- _from_rbexpr(_rbexpr.rle)
3231
+ wrap_expr(_rbexpr.rle)
2761
3232
  end
2762
3233
 
2763
3234
  # Map values to run IDs.
@@ -2785,7 +3256,7 @@ module Polars
2785
3256
  # # │ 1 ┆ y ┆ 2 ┆ 3 │
2786
3257
  # # └─────┴──────┴─────┴──────┘
2787
3258
  def rle_id
2788
- _from_rbexpr(_rbexpr.rle_id)
3259
+ wrap_expr(_rbexpr.rle_id)
2789
3260
  end
2790
3261
 
2791
3262
  # Filter a single column.
@@ -2824,7 +3295,7 @@ module Polars
2824
3295
  # # │ g2 ┆ 0 ┆ 3 │
2825
3296
  # # └───────────┴─────┴─────┘
2826
3297
  def filter(predicate)
2827
- _from_rbexpr(_rbexpr.filter(predicate._rbexpr))
3298
+ wrap_expr(_rbexpr.filter(predicate._rbexpr))
2828
3299
  end
2829
3300
 
2830
3301
  # Filter a single column.
@@ -2905,7 +3376,7 @@ module Polars
2905
3376
  # if !return_dtype.nil?
2906
3377
  # return_dtype = Utils.rb_type_to_dtype(return_dtype)
2907
3378
  # end
2908
- # _from_rbexpr(
3379
+ # wrap_expr(
2909
3380
  # _rbexpr.map_batches(
2910
3381
  # # TODO _map_batches_wrapper
2911
3382
  # f,
@@ -3037,7 +3508,7 @@ module Polars
3037
3508
  # # │ b ┆ [2, 3, 4] │
3038
3509
  # # └───────┴───────────┘
3039
3510
  def flatten
3040
- _from_rbexpr(_rbexpr.explode)
3511
+ wrap_expr(_rbexpr.explode)
3041
3512
  end
3042
3513
 
3043
3514
  # Explode a list or utf8 Series.
@@ -3064,7 +3535,7 @@ module Polars
3064
3535
  # # │ 6 │
3065
3536
  # # └─────┘
3066
3537
  def explode
3067
- _from_rbexpr(_rbexpr.explode)
3538
+ wrap_expr(_rbexpr.explode)
3068
3539
  end
3069
3540
 
3070
3541
  # Take every nth value in the Series and return as a new Series.
@@ -3086,7 +3557,7 @@ module Polars
3086
3557
  # # │ 7 │
3087
3558
  # # └─────┘
3088
3559
  def gather_every(n, offset = 0)
3089
- _from_rbexpr(_rbexpr.gather_every(n, offset))
3560
+ wrap_expr(_rbexpr.gather_every(n, offset))
3090
3561
  end
3091
3562
  alias_method :take_every, :gather_every
3092
3563
 
@@ -3112,7 +3583,7 @@ module Polars
3112
3583
  # # │ 3 │
3113
3584
  # # └─────┘
3114
3585
  def head(n = 10)
3115
- _from_rbexpr(_rbexpr.head(n))
3586
+ wrap_expr(_rbexpr.head(n))
3116
3587
  end
3117
3588
 
3118
3589
  # Get the last `n` rows.
@@ -3137,7 +3608,7 @@ module Polars
3137
3608
  # # │ 7 │
3138
3609
  # # └─────┘
3139
3610
  def tail(n = 10)
3140
- _from_rbexpr(_rbexpr.tail(n))
3611
+ wrap_expr(_rbexpr.tail(n))
3141
3612
  end
3142
3613
 
3143
3614
  # Get the first `n` rows.
@@ -3167,6 +3638,89 @@ module Polars
3167
3638
  head(n)
3168
3639
  end
3169
3640
 
3641
+ # Method equivalent of bitwise "and" operator `expr & other & ...`.
3642
+ #
3643
+ # @param others [Array]
3644
+ # One or more integer or boolean expressions to evaluate/combine.
3645
+ #
3646
+ # @return [Expr]
3647
+ #
3648
+ # @example
3649
+ # df = Polars::DataFrame.new(
3650
+ # {
3651
+ # "x" => [5, 6, 7, 4, 8],
3652
+ # "y" => [1.5, 2.5, 1.0, 4.0, -5.75],
3653
+ # "z" => [-9, 2, -1, 4, 8]
3654
+ # }
3655
+ # )
3656
+ # df.select(
3657
+ # (Polars.col("x") >= Polars.col("z"))
3658
+ # .and_(
3659
+ # Polars.col("y") >= Polars.col("z"),
3660
+ # Polars.col("y") == Polars.col("y"),
3661
+ # Polars.col("z") <= Polars.col("x"),
3662
+ # Polars.col("y") != Polars.col("x"),
3663
+ # )
3664
+ # .alias("all")
3665
+ # )
3666
+ # # =>
3667
+ # # shape: (5, 1)
3668
+ # # ┌───────┐
3669
+ # # │ all │
3670
+ # # │ --- │
3671
+ # # │ bool │
3672
+ # # ╞═══════╡
3673
+ # # │ true │
3674
+ # # │ true │
3675
+ # # │ true │
3676
+ # # │ false │
3677
+ # # │ false │
3678
+ # # └───────┘
3679
+ def and_(*others)
3680
+ ([self] + others).reduce(:&)
3681
+ end
3682
+
3683
+ # Method equivalent of bitwise "or" operator `expr | other | ...`.
3684
+ #
3685
+ # @param others [Array]
3686
+ # One or more integer or boolean expressions to evaluate/combine.
3687
+ #
3688
+ # @return [Expr]
3689
+ #
3690
+ # @example
3691
+ # df = Polars::DataFrame.new(
3692
+ # {
3693
+ # "x" => [5, 6, 7, 4, 8],
3694
+ # "y" => [1.5, 2.5, 1.0, 4.0, -5.75],
3695
+ # "z" => [-9, 2, -1, 4, 8]
3696
+ # }
3697
+ # )
3698
+ # df.select(
3699
+ # (Polars.col("x") == Polars.col("y"))
3700
+ # .or_(
3701
+ # Polars.col("x") == Polars.col("y"),
3702
+ # Polars.col("y") == Polars.col("z"),
3703
+ # Polars.col("y").cast(Integer) == Polars.col("z"),
3704
+ # )
3705
+ # .alias("any")
3706
+ # )
3707
+ # # =>
3708
+ # # shape: (5, 1)
3709
+ # # ┌───────┐
3710
+ # # │ any │
3711
+ # # │ --- │
3712
+ # # │ bool │
3713
+ # # ╞═══════╡
3714
+ # # │ false │
3715
+ # # │ true │
3716
+ # # │ false │
3717
+ # # │ true │
3718
+ # # │ false │
3719
+ # # └───────┘
3720
+ def or_(*others)
3721
+ ([self] + others).reduce(:|)
3722
+ end
3723
+
3170
3724
  # Method equivalent of equality operator `expr == other`.
3171
3725
  #
3172
3726
  # @param other [Object]
@@ -3199,7 +3753,7 @@ module Polars
3199
3753
  self == other
3200
3754
  end
3201
3755
 
3202
- # Method equivalent of equality operator `expr == other` where `None == None`.
3756
+ # Method equivalent of equality operator `expr == other` where `nil == nil`.
3203
3757
  #
3204
3758
  # This differs from default `eq` where null values are propagated.
3205
3759
  #
@@ -3235,7 +3789,7 @@ module Polars
3235
3789
  # # └──────┴──────┴────────┴────────────────┘
3236
3790
  def eq_missing(other)
3237
3791
  other = Utils.parse_into_expression(other, str_as_lit: true)
3238
- _from_rbexpr(_rbexpr.eq_missing(other))
3792
+ wrap_expr(_rbexpr.eq_missing(other))
3239
3793
  end
3240
3794
 
3241
3795
  # Method equivalent of "greater than or equal" operator `expr >= other`.
@@ -3403,7 +3957,7 @@ module Polars
3403
3957
  self != other
3404
3958
  end
3405
3959
 
3406
- # Method equivalent of equality operator `expr != other` where `None == None`.
3960
+ # Method equivalent of equality operator `expr != other` where `nil == nil`.
3407
3961
  #
3408
3962
  # This differs from default `ne` where null values are propagated.
3409
3963
  #
@@ -3439,7 +3993,7 @@ module Polars
3439
3993
  # # └──────┴──────┴────────┴────────────────┘
3440
3994
  def ne_missing(other)
3441
3995
  other = Utils.parse_into_expression(other, str_as_lit: true)
3442
- _from_rbexpr(_rbexpr.neq_missing(other))
3996
+ wrap_expr(_rbexpr.neq_missing(other))
3443
3997
  end
3444
3998
 
3445
3999
  # Method equivalent of addition operator `expr + other`.
@@ -3516,7 +4070,7 @@ module Polars
3516
4070
  # # │ 5 ┆ 2.5 ┆ 2 │
3517
4071
  # # └─────┴─────┴──────┘
3518
4072
  def floordiv(other)
3519
- _from_rbexpr(_rbexpr.floordiv(_to_rbexpr(other)))
4073
+ wrap_expr(_rbexpr.floordiv(_to_rbexpr(other)))
3520
4074
  end
3521
4075
 
3522
4076
  # Method equivalent of modulus operator `expr % other`.
@@ -3742,7 +4296,7 @@ module Polars
3742
4296
  # # └───────────┴──────────────────┴──────────┘
3743
4297
  def is_in(other, nulls_equal: false)
3744
4298
  other = Utils.parse_into_expression(other)
3745
- _from_rbexpr(_rbexpr.is_in(other, nulls_equal))
4299
+ wrap_expr(_rbexpr.is_in(other, nulls_equal))
3746
4300
  end
3747
4301
  alias_method :in?, :is_in
3748
4302
 
@@ -3778,7 +4332,7 @@ module Polars
3778
4332
  # # └─────────────────┘
3779
4333
  def repeat_by(by)
3780
4334
  by = Utils.parse_into_expression(by, str_as_lit: false)
3781
- _from_rbexpr(_rbexpr.repeat_by(by))
4335
+ wrap_expr(_rbexpr.repeat_by(by))
3782
4336
  end
3783
4337
 
3784
4338
  # Check if this expression is between start and end.
@@ -3851,11 +4405,48 @@ module Polars
3851
4405
  lower_bound = Utils.parse_into_expression(lower_bound)
3852
4406
  upper_bound = Utils.parse_into_expression(upper_bound)
3853
4407
 
3854
- _from_rbexpr(
4408
+ wrap_expr(
3855
4409
  _rbexpr.is_between(lower_bound, upper_bound, closed)
3856
4410
  )
3857
4411
  end
3858
4412
 
4413
+ # Check if this expression is close, i.e. almost equal, to the other expression.
4414
+ #
4415
+ # @param abs_tol [Float]
4416
+ # Absolute tolerance. This is the maximum allowed absolute difference between
4417
+ # two values. Must be non-negative.
4418
+ # @param rel_tol [Float]
4419
+ # Relative tolerance. This is the maximum allowed difference between two
4420
+ # values, relative to the larger absolute value. Must be in the range [0, 1).
4421
+ # @param nans_equal [Boolean]
4422
+ # Whether NaN values should be considered equal.
4423
+ #
4424
+ # @return [Expr]
4425
+ #
4426
+ # @example
4427
+ # df = Polars::DataFrame.new({"a" => [1.5, 2.0, 2.5], "b" => [1.55, 2.2, 3.0]})
4428
+ # df.with_columns(Polars.col("a").is_close("b", abs_tol: 0.1).alias("is_close"))
4429
+ # # =>
4430
+ # # shape: (3, 3)
4431
+ # # ┌─────┬──────┬──────────┐
4432
+ # # │ a ┆ b ┆ is_close │
4433
+ # # │ --- ┆ --- ┆ --- │
4434
+ # # │ f64 ┆ f64 ┆ bool │
4435
+ # # ╞═════╪══════╪══════════╡
4436
+ # # │ 1.5 ┆ 1.55 ┆ true │
4437
+ # # │ 2.0 ┆ 2.2 ┆ false │
4438
+ # # │ 2.5 ┆ 3.0 ┆ false │
4439
+ # # └─────┴──────┴──────────┘
4440
+ def is_close(
4441
+ other,
4442
+ abs_tol: 0.0,
4443
+ rel_tol: 1e-09,
4444
+ nans_equal: false
4445
+ )
4446
+ other = Utils.parse_into_expression(other)
4447
+ wrap_expr(_rbexpr.is_close(other, abs_tol, rel_tol, nans_equal))
4448
+ end
4449
+
3859
4450
  # Hash the elements in the selection.
3860
4451
  #
3861
4452
  # The hash value is of type `:u64`.
@@ -3895,7 +4486,7 @@ module Polars
3895
4486
  k1 = seed_1.nil? ? seed : seed_1
3896
4487
  k2 = seed_2.nil? ? seed : seed_2
3897
4488
  k3 = seed_3.nil? ? seed : seed_3
3898
- _from_rbexpr(_rbexpr._hash(k0, k1, k2, k3))
4489
+ wrap_expr(_rbexpr._hash(k0, k1, k2, k3))
3899
4490
  end
3900
4491
 
3901
4492
  # Reinterpret the underlying bits as a signed/unsigned integer.
@@ -3929,7 +4520,7 @@ module Polars
3929
4520
  # # │ 2 ┆ 2 │
3930
4521
  # # └───────────────┴──────────┘
3931
4522
  def reinterpret(signed: false)
3932
- _from_rbexpr(_rbexpr.reinterpret(signed))
4523
+ wrap_expr(_rbexpr.reinterpret(signed))
3933
4524
  end
3934
4525
 
3935
4526
  # Print the value that this expression evaluates to and pass on the value.
@@ -3992,7 +4583,7 @@ module Polars
3992
4583
  # # │ 3.0 ┆ 3.0 │
3993
4584
  # # └─────┴─────┘
3994
4585
  def interpolate(method: "linear")
3995
- _from_rbexpr(_rbexpr.interpolate(method))
4586
+ wrap_expr(_rbexpr.interpolate(method))
3996
4587
  end
3997
4588
 
3998
4589
  # Fill null values using interpolation based on another column.
@@ -4023,7 +4614,7 @@ module Polars
4023
4614
  # # └──────┴─────┴────────────────┘
4024
4615
  def interpolate_by(by)
4025
4616
  by = Utils.parse_into_expression(by)
4026
- _from_rbexpr(_rbexpr.interpolate_by(by))
4617
+ wrap_expr(_rbexpr.interpolate_by(by))
4027
4618
  end
4028
4619
 
4029
4620
  # Apply a rolling min based on another column.
@@ -4124,7 +4715,7 @@ module Polars
4124
4715
  )
4125
4716
  window_size = _prepare_rolling_by_window_args(window_size)
4126
4717
  by = Utils.parse_into_expression(by)
4127
- _from_rbexpr(
4718
+ wrap_expr(
4128
4719
  _rbexpr.rolling_min_by(by, window_size, min_periods, closed)
4129
4720
  )
4130
4721
  end
@@ -4253,7 +4844,7 @@ module Polars
4253
4844
  )
4254
4845
  window_size = _prepare_rolling_by_window_args(window_size)
4255
4846
  by = Utils.parse_into_expression(by)
4256
- _from_rbexpr(
4847
+ wrap_expr(
4257
4848
  _rbexpr.rolling_max_by(by, window_size, min_periods, closed)
4258
4849
  )
4259
4850
  end
@@ -4384,7 +4975,7 @@ module Polars
4384
4975
  )
4385
4976
  window_size = _prepare_rolling_by_window_args(window_size)
4386
4977
  by = Utils.parse_into_expression(by)
4387
- _from_rbexpr(
4978
+ wrap_expr(
4388
4979
  _rbexpr.rolling_mean_by(
4389
4980
  by,
4390
4981
  window_size,
@@ -4518,7 +5109,7 @@ module Polars
4518
5109
  )
4519
5110
  window_size = _prepare_rolling_by_window_args(window_size)
4520
5111
  by = Utils.parse_into_expression(by)
4521
- _from_rbexpr(
5112
+ wrap_expr(
4522
5113
  _rbexpr.rolling_sum_by(by, window_size, min_periods, closed)
4523
5114
  )
4524
5115
  end
@@ -4650,7 +5241,7 @@ module Polars
4650
5241
  )
4651
5242
  window_size = _prepare_rolling_by_window_args(window_size)
4652
5243
  by = Utils.parse_into_expression(by)
4653
- _from_rbexpr(
5244
+ wrap_expr(
4654
5245
  _rbexpr.rolling_std_by(
4655
5246
  by,
4656
5247
  window_size,
@@ -4788,7 +5379,7 @@ module Polars
4788
5379
  )
4789
5380
  window_size = _prepare_rolling_by_window_args(window_size)
4790
5381
  by = Utils.parse_into_expression(by)
4791
- _from_rbexpr(
5382
+ wrap_expr(
4792
5383
  _rbexpr.rolling_var_by(
4793
5384
  by,
4794
5385
  window_size,
@@ -4899,7 +5490,7 @@ module Polars
4899
5490
  )
4900
5491
  window_size = _prepare_rolling_by_window_args(window_size)
4901
5492
  by = Utils.parse_into_expression(by)
4902
- _from_rbexpr(
5493
+ wrap_expr(
4903
5494
  _rbexpr.rolling_median_by(by, window_size, min_periods, closed)
4904
5495
  )
4905
5496
  end
@@ -4908,10 +5499,6 @@ module Polars
4908
5499
  #
4909
5500
  # @param by [String]
4910
5501
  # This column must be of dtype Datetime or Date.
4911
- # @param quantile [Float]
4912
- # Quantile between 0.0 and 1.0.
4913
- # @param interpolation ['nearest', 'higher', 'lower', 'midpoint', 'linear']
4914
- # Interpolation method.
4915
5502
  # @param window_size [String]
4916
5503
  # The length of the window. Can be a dynamic
4917
5504
  # temporal size indicated by a timedelta or the following string language:
@@ -4932,6 +5519,10 @@ module Polars
4932
5519
  # (which may not be 24 hours, due to daylight savings). Similarly for
4933
5520
  # "calendar week", "calendar month", "calendar quarter", and
4934
5521
  # "calendar year".
5522
+ # @param quantile [Float]
5523
+ # Quantile between 0.0 and 1.0.
5524
+ # @param interpolation ['nearest', 'higher', 'lower', 'midpoint', 'linear']
5525
+ # Interpolation method.
4935
5526
  # @param min_periods [Integer]
4936
5527
  # The number of values in the window that should be non-null before computing
4937
5528
  # a result.
@@ -5010,7 +5601,7 @@ module Polars
5010
5601
  )
5011
5602
  window_size = _prepare_rolling_by_window_args(window_size)
5012
5603
  by = Utils.parse_into_expression(by)
5013
- _from_rbexpr(
5604
+ wrap_expr(
5014
5605
  _rbexpr.rolling_quantile_by(
5015
5606
  by,
5016
5607
  quantile,
@@ -5051,7 +5642,7 @@ module Polars
5051
5642
  # elementwise with the values in the window.
5052
5643
  # @param min_periods [Integer]
5053
5644
  # The number of values in the window that should be non-null before computing
5054
- # a result. If None, it will be set equal to window size.
5645
+ # a result. If nil, it will be set equal to window size.
5055
5646
  # @param center [Boolean]
5056
5647
  # Set the labels at the center of the window
5057
5648
  #
@@ -5093,7 +5684,7 @@ module Polars
5093
5684
  min_periods: nil,
5094
5685
  center: false
5095
5686
  )
5096
- _from_rbexpr(
5687
+ wrap_expr(
5097
5688
  _rbexpr.rolling_min(
5098
5689
  window_size, weights, min_periods, center
5099
5690
  )
@@ -5129,7 +5720,7 @@ module Polars
5129
5720
  # elementwise with the values in the window.
5130
5721
  # @param min_periods [Integer]
5131
5722
  # The number of values in the window that should be non-null before computing
5132
- # a result. If None, it will be set equal to window size.
5723
+ # a result. If nil, it will be set equal to window size.
5133
5724
  # @param center [Boolean]
5134
5725
  # Set the labels at the center of the window
5135
5726
  #
@@ -5171,7 +5762,7 @@ module Polars
5171
5762
  min_periods: nil,
5172
5763
  center: false
5173
5764
  )
5174
- _from_rbexpr(
5765
+ wrap_expr(
5175
5766
  _rbexpr.rolling_max(
5176
5767
  window_size, weights, min_periods, center
5177
5768
  )
@@ -5207,7 +5798,7 @@ module Polars
5207
5798
  # elementwise with the values in the window.
5208
5799
  # @param min_periods [Integer]
5209
5800
  # The number of values in the window that should be non-null before computing
5210
- # a result. If None, it will be set equal to window size.
5801
+ # a result. If nil, it will be set equal to window size.
5211
5802
  # @param center [Boolean]
5212
5803
  # Set the labels at the center of the window
5213
5804
  #
@@ -5249,7 +5840,7 @@ module Polars
5249
5840
  min_periods: nil,
5250
5841
  center: false
5251
5842
  )
5252
- _from_rbexpr(
5843
+ wrap_expr(
5253
5844
  _rbexpr.rolling_mean(
5254
5845
  window_size, weights, min_periods, center
5255
5846
  )
@@ -5285,7 +5876,7 @@ module Polars
5285
5876
  # elementwise with the values in the window.
5286
5877
  # @param min_periods [Integer]
5287
5878
  # The number of values in the window that should be non-null before computing
5288
- # a result. If None, it will be set equal to window size.
5879
+ # a result. If nil, it will be set equal to window size.
5289
5880
  # @param center [Boolean]
5290
5881
  # Set the labels at the center of the window
5291
5882
  #
@@ -5327,7 +5918,7 @@ module Polars
5327
5918
  min_periods: nil,
5328
5919
  center: false
5329
5920
  )
5330
- _from_rbexpr(
5921
+ wrap_expr(
5331
5922
  _rbexpr.rolling_sum(
5332
5923
  window_size, weights, min_periods, center
5333
5924
  )
@@ -5363,9 +5954,11 @@ module Polars
5363
5954
  # elementwise with the values in the window.
5364
5955
  # @param min_periods [Integer]
5365
5956
  # The number of values in the window that should be non-null before computing
5366
- # a result. If None, it will be set equal to window size.
5957
+ # a result. If nil, it will be set equal to window size.
5367
5958
  # @param center [Boolean]
5368
5959
  # Set the labels at the center of the window
5960
+ # @param ddof [Integer]
5961
+ # "Delta Degrees of Freedom": The divisor for a length N window is N - ddof
5369
5962
  #
5370
5963
  # @note
5371
5964
  # This functionality is experimental and may change without it being considered a
@@ -5406,7 +5999,7 @@ module Polars
5406
5999
  center: false,
5407
6000
  ddof: 1
5408
6001
  )
5409
- _from_rbexpr(
6002
+ wrap_expr(
5410
6003
  _rbexpr.rolling_std(
5411
6004
  window_size, weights, min_periods, center, ddof
5412
6005
  )
@@ -5442,9 +6035,11 @@ module Polars
5442
6035
  # elementwise with the values in the window.
5443
6036
  # @param min_periods [Integer]
5444
6037
  # The number of values in the window that should be non-null before computing
5445
- # a result. If None, it will be set equal to window size.
6038
+ # a result. If nil, it will be set equal to window size.
5446
6039
  # @param center [Boolean]
5447
6040
  # Set the labels at the center of the window
6041
+ # @param ddof [Integer]
6042
+ # "Delta Degrees of Freedom": The divisor for a length N window is N - ddof
5448
6043
  #
5449
6044
  # @note
5450
6045
  # This functionality is experimental and may change without it being considered a
@@ -5485,7 +6080,7 @@ module Polars
5485
6080
  center: false,
5486
6081
  ddof: 1
5487
6082
  )
5488
- _from_rbexpr(
6083
+ wrap_expr(
5489
6084
  _rbexpr.rolling_var(
5490
6085
  window_size, weights, min_periods, center, ddof
5491
6086
  )
@@ -5517,7 +6112,7 @@ module Polars
5517
6112
  # elementwise with the values in the window.
5518
6113
  # @param min_periods [Integer]
5519
6114
  # The number of values in the window that should be non-null before computing
5520
- # a result. If None, it will be set equal to window size.
6115
+ # a result. If nil, it will be set equal to window size.
5521
6116
  # @param center [Boolean]
5522
6117
  # Set the labels at the center of the window
5523
6118
  #
@@ -5559,7 +6154,7 @@ module Polars
5559
6154
  min_periods: nil,
5560
6155
  center: false
5561
6156
  )
5562
- _from_rbexpr(
6157
+ wrap_expr(
5563
6158
  _rbexpr.rolling_median(
5564
6159
  window_size, weights, min_periods, center
5565
6160
  )
@@ -5595,7 +6190,7 @@ module Polars
5595
6190
  # elementwise with the values in the window.
5596
6191
  # @param min_periods [Integer]
5597
6192
  # The number of values in the window that should be non-null before computing
5598
- # a result. If None, it will be set equal to window size.
6193
+ # a result. If nil, it will be set equal to window size.
5599
6194
  # @param center [Boolean]
5600
6195
  # Set the labels at the center of the window
5601
6196
  #
@@ -5626,10 +6221,10 @@ module Polars
5626
6221
  # # ╞══════╡
5627
6222
  # # │ null │
5628
6223
  # # │ null │
5629
- # # │ 1.0 │
5630
6224
  # # │ 2.0 │
5631
6225
  # # │ 3.0 │
5632
6226
  # # │ 4.0 │
6227
+ # # │ 6.0 │
5633
6228
  # # └──────┘
5634
6229
  def rolling_quantile(
5635
6230
  quantile,
@@ -5639,7 +6234,7 @@ module Polars
5639
6234
  min_periods: nil,
5640
6235
  center: false
5641
6236
  )
5642
- _from_rbexpr(
6237
+ wrap_expr(
5643
6238
  _rbexpr.rolling_quantile(
5644
6239
  quantile, interpolation, window_size, weights, min_periods, center
5645
6240
  )
@@ -5703,7 +6298,7 @@ module Polars
5703
6298
  # if min_periods.nil?
5704
6299
  # min_periods = window_size
5705
6300
  # end
5706
- # _from_rbexpr(
6301
+ # wrap_expr(
5707
6302
  # _rbexpr.rolling_apply(
5708
6303
  # function, window_size, weights, min_periods, center
5709
6304
  # )
@@ -5740,7 +6335,64 @@ module Polars
5740
6335
  # # │ 0.47033 │
5741
6336
  # # └──────────┘
5742
6337
  def rolling_skew(window_size, bias: true, min_samples: nil, center: false)
5743
- _from_rbexpr(_rbexpr.rolling_skew(window_size, bias, min_samples, center))
6338
+ wrap_expr(_rbexpr.rolling_skew(window_size, bias, min_samples, center))
6339
+ end
6340
+
6341
+ # Compute a rolling kurtosis.
6342
+ #
6343
+ # @note
6344
+ # This functionality is considered **unstable**. It may be changed
6345
+ # at any point without it being considered a breaking change.
6346
+ #
6347
+ # The window at a given row will include the row itself, and the `window_size - 1`
6348
+ # elements before it.
6349
+ #
6350
+ # @param window_size [Integer]
6351
+ # Integer size of the rolling window.
6352
+ # @param fisher [Boolean]
6353
+ # If true, Fisher's definition is used (normal ==> 0.0). If false,
6354
+ # Pearson's definition is used (normal ==> 3.0).
6355
+ # @param bias [Boolean]
6356
+ # If false, the calculations are corrected for statistical bias.
6357
+ # @param min_samples [Integer]
6358
+ # The number of values in the window that should be non-null before computing
6359
+ # a result. If set to `nil` (default), it will be set equal to `window_size`.
6360
+ # @param center
6361
+ # Set the labels at the center of the window.
6362
+ #
6363
+ # @return [Expr]
6364
+ #
6365
+ # @example
6366
+ # df = Polars::DataFrame.new({"a" => [1, 4, 2, 9]})
6367
+ # df.select(Polars.col("a").rolling_kurtosis(3))
6368
+ # # =>
6369
+ # # shape: (4, 1)
6370
+ # # ┌──────┐
6371
+ # # │ a │
6372
+ # # │ --- │
6373
+ # # │ f64 │
6374
+ # # ╞══════╡
6375
+ # # │ null │
6376
+ # # │ null │
6377
+ # # │ -1.5 │
6378
+ # # │ -1.5 │
6379
+ # # └──────┘
6380
+ def rolling_kurtosis(
6381
+ window_size,
6382
+ fisher: true,
6383
+ bias: true,
6384
+ min_samples: nil,
6385
+ center: false
6386
+ )
6387
+ wrap_expr(
6388
+ _rbexpr.rolling_kurtosis(
6389
+ window_size,
6390
+ fisher,
6391
+ bias,
6392
+ min_samples,
6393
+ center
6394
+ )
6395
+ )
5744
6396
  end
5745
6397
 
5746
6398
  # Compute absolute values.
@@ -5767,7 +6419,7 @@ module Polars
5767
6419
  # # │ 2.0 │
5768
6420
  # # └─────┘
5769
6421
  def abs
5770
- _from_rbexpr(_rbexpr.abs)
6422
+ wrap_expr(_rbexpr.abs)
5771
6423
  end
5772
6424
 
5773
6425
  # Get the index values that would sort this column.
@@ -5864,7 +6516,7 @@ module Polars
5864
6516
  # # │ 5 │
5865
6517
  # # └─────┘
5866
6518
  def rank(method: "average", reverse: false, seed: nil)
5867
- _from_rbexpr(_rbexpr.rank(method, reverse, seed))
6519
+ wrap_expr(_rbexpr.rank(method, reverse, seed))
5868
6520
  end
5869
6521
 
5870
6522
  # Calculate the n-th discrete difference.
@@ -5896,7 +6548,7 @@ module Polars
5896
6548
  # # └──────┘
5897
6549
  def diff(n: 1, null_behavior: "ignore")
5898
6550
  n = Utils.parse_into_expression(n)
5899
- _from_rbexpr(_rbexpr.diff(n, null_behavior))
6551
+ wrap_expr(_rbexpr.diff(n, null_behavior))
5900
6552
  end
5901
6553
 
5902
6554
  # Computes percentage change between values.
@@ -5933,7 +6585,7 @@ module Polars
5933
6585
  # # └──────┴────────────┘
5934
6586
  def pct_change(n: 1)
5935
6587
  n = Utils.parse_into_expression(n)
5936
- _from_rbexpr(_rbexpr.pct_change(n))
6588
+ wrap_expr(_rbexpr.pct_change(n))
5937
6589
  end
5938
6590
 
5939
6591
  # Compute the sample skewness of a data set.
@@ -5962,7 +6614,7 @@ module Polars
5962
6614
  # # │ 0.343622 │
5963
6615
  # # └──────────┘
5964
6616
  def skew(bias: true)
5965
- _from_rbexpr(_rbexpr.skew(bias))
6617
+ wrap_expr(_rbexpr.skew(bias))
5966
6618
  end
5967
6619
 
5968
6620
  # Compute the kurtosis (Fisher or Pearson) of a dataset.
@@ -5994,7 +6646,7 @@ module Polars
5994
6646
  # # │ -1.153061 │
5995
6647
  # # └───────────┘
5996
6648
  def kurtosis(fisher: true, bias: true)
5997
- _from_rbexpr(_rbexpr.kurtosis(fisher, bias))
6649
+ wrap_expr(_rbexpr.kurtosis(fisher, bias))
5998
6650
  end
5999
6651
 
6000
6652
  # Set values outside the given boundaries to the boundary value.
@@ -6031,7 +6683,7 @@ module Polars
6031
6683
  if !upper_bound.nil?
6032
6684
  upper_bound = Utils.parse_into_expression(upper_bound)
6033
6685
  end
6034
- _from_rbexpr(_rbexpr.clip(lower_bound, upper_bound))
6686
+ wrap_expr(_rbexpr.clip(lower_bound, upper_bound))
6035
6687
  end
6036
6688
 
6037
6689
  # Clip (limit) the values in an array to a `min` boundary.
@@ -6116,7 +6768,7 @@ module Polars
6116
6768
  # # │ -9223372036854775808 │
6117
6769
  # # └──────────────────────┘
6118
6770
  def lower_bound
6119
- _from_rbexpr(_rbexpr.lower_bound)
6771
+ wrap_expr(_rbexpr.lower_bound)
6120
6772
  end
6121
6773
 
6122
6774
  # Calculate the upper bound.
@@ -6139,7 +6791,7 @@ module Polars
6139
6791
  # # │ 9223372036854775807 │
6140
6792
  # # └─────────────────────┘
6141
6793
  def upper_bound
6142
- _from_rbexpr(_rbexpr.upper_bound)
6794
+ wrap_expr(_rbexpr.upper_bound)
6143
6795
  end
6144
6796
 
6145
6797
  # Compute the element-wise indication of the sign.
@@ -6163,7 +6815,7 @@ module Polars
6163
6815
  # # │ null │
6164
6816
  # # └──────┘
6165
6817
  def sign
6166
- _from_rbexpr(_rbexpr.sign)
6818
+ wrap_expr(_rbexpr.sign)
6167
6819
  end
6168
6820
 
6169
6821
  # Compute the element-wise value for the sine.
@@ -6183,7 +6835,7 @@ module Polars
6183
6835
  # # │ 0.0 │
6184
6836
  # # └─────┘
6185
6837
  def sin
6186
- _from_rbexpr(_rbexpr.sin)
6838
+ wrap_expr(_rbexpr.sin)
6187
6839
  end
6188
6840
 
6189
6841
  # Compute the element-wise value for the cosine.
@@ -6203,7 +6855,7 @@ module Polars
6203
6855
  # # │ 1.0 │
6204
6856
  # # └─────┘
6205
6857
  def cos
6206
- _from_rbexpr(_rbexpr.cos)
6858
+ wrap_expr(_rbexpr.cos)
6207
6859
  end
6208
6860
 
6209
6861
  # Compute the element-wise value for the tangent.
@@ -6223,7 +6875,27 @@ module Polars
6223
6875
  # # │ 1.557408 │
6224
6876
  # # └──────────┘
6225
6877
  def tan
6226
- _from_rbexpr(_rbexpr.tan)
6878
+ wrap_expr(_rbexpr.tan)
6879
+ end
6880
+
6881
+ # Compute the element-wise value for the cotangent.
6882
+ #
6883
+ # @return [Expr]
6884
+ #
6885
+ # @example
6886
+ # df = Polars::DataFrame.new({"a" => [1.0]})
6887
+ # df.select(Polars.col("a").cot.round(2))
6888
+ # # =>
6889
+ # # shape: (1, 1)
6890
+ # # ┌──────┐
6891
+ # # │ a │
6892
+ # # │ --- │
6893
+ # # │ f64 │
6894
+ # # ╞══════╡
6895
+ # # │ 0.64 │
6896
+ # # └──────┘
6897
+ def cot
6898
+ wrap_expr(_rbexpr.cot)
6227
6899
  end
6228
6900
 
6229
6901
  # Compute the element-wise value for the inverse sine.
@@ -6243,7 +6915,7 @@ module Polars
6243
6915
  # # │ 1.570796 │
6244
6916
  # # └──────────┘
6245
6917
  def arcsin
6246
- _from_rbexpr(_rbexpr.arcsin)
6918
+ wrap_expr(_rbexpr.arcsin)
6247
6919
  end
6248
6920
 
6249
6921
  # Compute the element-wise value for the inverse cosine.
@@ -6263,7 +6935,7 @@ module Polars
6263
6935
  # # │ 1.570796 │
6264
6936
  # # └──────────┘
6265
6937
  def arccos
6266
- _from_rbexpr(_rbexpr.arccos)
6938
+ wrap_expr(_rbexpr.arccos)
6267
6939
  end
6268
6940
 
6269
6941
  # Compute the element-wise value for the inverse tangent.
@@ -6283,7 +6955,7 @@ module Polars
6283
6955
  # # │ 0.785398 │
6284
6956
  # # └──────────┘
6285
6957
  def arctan
6286
- _from_rbexpr(_rbexpr.arctan)
6958
+ wrap_expr(_rbexpr.arctan)
6287
6959
  end
6288
6960
 
6289
6961
  # Compute the element-wise value for the hyperbolic sine.
@@ -6303,7 +6975,7 @@ module Polars
6303
6975
  # # │ 1.175201 │
6304
6976
  # # └──────────┘
6305
6977
  def sinh
6306
- _from_rbexpr(_rbexpr.sinh)
6978
+ wrap_expr(_rbexpr.sinh)
6307
6979
  end
6308
6980
 
6309
6981
  # Compute the element-wise value for the hyperbolic cosine.
@@ -6323,7 +6995,7 @@ module Polars
6323
6995
  # # │ 1.543081 │
6324
6996
  # # └──────────┘
6325
6997
  def cosh
6326
- _from_rbexpr(_rbexpr.cosh)
6998
+ wrap_expr(_rbexpr.cosh)
6327
6999
  end
6328
7000
 
6329
7001
  # Compute the element-wise value for the hyperbolic tangent.
@@ -6343,7 +7015,7 @@ module Polars
6343
7015
  # # │ 0.761594 │
6344
7016
  # # └──────────┘
6345
7017
  def tanh
6346
- _from_rbexpr(_rbexpr.tanh)
7018
+ wrap_expr(_rbexpr.tanh)
6347
7019
  end
6348
7020
 
6349
7021
  # Compute the element-wise value for the inverse hyperbolic sine.
@@ -6363,7 +7035,7 @@ module Polars
6363
7035
  # # │ 0.881374 │
6364
7036
  # # └──────────┘
6365
7037
  def arcsinh
6366
- _from_rbexpr(_rbexpr.arcsinh)
7038
+ wrap_expr(_rbexpr.arcsinh)
6367
7039
  end
6368
7040
 
6369
7041
  # Compute the element-wise value for the inverse hyperbolic cosine.
@@ -6383,7 +7055,7 @@ module Polars
6383
7055
  # # │ 0.0 │
6384
7056
  # # └─────┘
6385
7057
  def arccosh
6386
- _from_rbexpr(_rbexpr.arccosh)
7058
+ wrap_expr(_rbexpr.arccosh)
6387
7059
  end
6388
7060
 
6389
7061
  # Compute the element-wise value for the inverse hyperbolic tangent.
@@ -6403,7 +7075,63 @@ module Polars
6403
7075
  # # │ inf │
6404
7076
  # # └─────┘
6405
7077
  def arctanh
6406
- _from_rbexpr(_rbexpr.arctanh)
7078
+ wrap_expr(_rbexpr.arctanh)
7079
+ end
7080
+
7081
+ # Convert from radians to degrees.
7082
+ #
7083
+ # @return [Expr]
7084
+ #
7085
+ # @example
7086
+ # df = Polars::DataFrame.new({"a" => (-4...5).map { |x| x * Math::PI }})
7087
+ # df.select(Polars.col("a").degrees)
7088
+ # # =>
7089
+ # # shape: (9, 1)
7090
+ # # ┌────────┐
7091
+ # # │ a │
7092
+ # # │ --- │
7093
+ # # │ f64 │
7094
+ # # ╞════════╡
7095
+ # # │ -720.0 │
7096
+ # # │ -540.0 │
7097
+ # # │ -360.0 │
7098
+ # # │ -180.0 │
7099
+ # # │ 0.0 │
7100
+ # # │ 180.0 │
7101
+ # # │ 360.0 │
7102
+ # # │ 540.0 │
7103
+ # # │ 720.0 │
7104
+ # # └────────┘
7105
+ def degrees
7106
+ wrap_expr(_rbexpr.degrees)
7107
+ end
7108
+
7109
+ # Convert from degrees to radians.
7110
+ #
7111
+ # @return [Expr]
7112
+ #
7113
+ # @example
7114
+ # df = Polars::DataFrame.new({"a" => [-720, -540, -360, -180, 0, 180, 360, 540, 720]})
7115
+ # df.select(Polars.col("a").radians)
7116
+ # # =>
7117
+ # # shape: (9, 1)
7118
+ # # ┌────────────┐
7119
+ # # │ a │
7120
+ # # │ --- │
7121
+ # # │ f64 │
7122
+ # # ╞════════════╡
7123
+ # # │ -12.566371 │
7124
+ # # │ -9.424778 │
7125
+ # # │ -6.283185 │
7126
+ # # │ -3.141593 │
7127
+ # # │ 0.0 │
7128
+ # # │ 3.141593 │
7129
+ # # │ 6.283185 │
7130
+ # # │ 9.424778 │
7131
+ # # │ 12.566371 │
7132
+ # # └────────────┘
7133
+ def radians
7134
+ wrap_expr(_rbexpr.radians)
6407
7135
  end
6408
7136
 
6409
7137
  # Reshape this Expr to a flat Series or a Series of Lists.
@@ -6449,13 +7177,13 @@ module Polars
6449
7177
  # # │ 9 │
6450
7178
  # # └─────┘
6451
7179
  def reshape(dims)
6452
- _from_rbexpr(_rbexpr.reshape(dims))
7180
+ wrap_expr(_rbexpr.reshape(dims))
6453
7181
  end
6454
7182
 
6455
7183
  # Shuffle the contents of this expr.
6456
7184
  #
6457
7185
  # @param seed [Integer]
6458
- # Seed for the random number generator. If set to None (default), a random
7186
+ # Seed for the random number generator. If set to nil (default), a random
6459
7187
  # seed is generated using the `random` module.
6460
7188
  #
6461
7189
  # @return [Expr]
@@ -6471,14 +7199,14 @@ module Polars
6471
7199
  # # │ i64 │
6472
7200
  # # ╞═════╡
6473
7201
  # # │ 2 │
6474
- # # │ 1 │
6475
7202
  # # │ 3 │
7203
+ # # │ 1 │
6476
7204
  # # └─────┘
6477
7205
  def shuffle(seed: nil)
6478
7206
  if seed.nil?
6479
7207
  seed = rand(10000)
6480
7208
  end
6481
- _from_rbexpr(_rbexpr.shuffle(seed))
7209
+ wrap_expr(_rbexpr.shuffle(seed))
6482
7210
  end
6483
7211
 
6484
7212
  # Sample from this expression.
@@ -6490,7 +7218,7 @@ module Polars
6490
7218
  # @param shuffle [Boolean]
6491
7219
  # Shuffle the order of sampled data points.
6492
7220
  # @param seed [Integer]
6493
- # Seed for the random number generator. If set to None (default), a random
7221
+ # Seed for the random number generator. If set to nil (default), a random
6494
7222
  # seed is used.
6495
7223
  # @param n [Integer]
6496
7224
  # Number of items to return. Cannot be used with `frac`.
@@ -6508,7 +7236,7 @@ module Polars
6508
7236
  # # │ i64 │
6509
7237
  # # ╞═════╡
6510
7238
  # # │ 3 │
6511
- # # │ 1
7239
+ # # │ 3
6512
7240
  # # │ 1 │
6513
7241
  # # └─────┘
6514
7242
  def sample(
@@ -6524,14 +7252,14 @@ module Polars
6524
7252
 
6525
7253
  if !n.nil? && frac.nil?
6526
7254
  n = Utils.parse_into_expression(n)
6527
- return _from_rbexpr(_rbexpr.sample_n(n, with_replacement, shuffle, seed))
7255
+ return wrap_expr(_rbexpr.sample_n(n, with_replacement, shuffle, seed))
6528
7256
  end
6529
7257
 
6530
7258
  if frac.nil?
6531
7259
  frac = 1.0
6532
7260
  end
6533
7261
  frac = Utils.parse_into_expression(frac)
6534
- _from_rbexpr(
7262
+ wrap_expr(
6535
7263
  _rbexpr.sample_frac(frac, with_replacement, shuffle, seed)
6536
7264
  )
6537
7265
  end
@@ -6564,7 +7292,76 @@ module Polars
6564
7292
  ignore_nulls: true
6565
7293
  )
6566
7294
  alpha = _prepare_alpha(com, span, half_life, alpha)
6567
- _from_rbexpr(_rbexpr.ewm_mean(alpha, adjust, min_periods, ignore_nulls))
7295
+ wrap_expr(_rbexpr.ewm_mean(alpha, adjust, min_periods, ignore_nulls))
7296
+ end
7297
+
7298
+ # Compute time-based exponentially weighted moving average.
7299
+ #
7300
+ # @param by [Object]
7301
+ # Times to calculate average by. Should be `DateTime`, `Date`, `UInt64`,
7302
+ # `UInt32`, `Int64`, or `Int32` data type.
7303
+ # @param half_life [Object]
7304
+ # Unit over which observation decays to half its value.
7305
+ #
7306
+ # Can be created either from a timedelta, or
7307
+ # by using the following string language:
7308
+ #
7309
+ # - 1ns (1 nanosecond)
7310
+ # - 1us (1 microsecond)
7311
+ # - 1ms (1 millisecond)
7312
+ # - 1s (1 second)
7313
+ # - 1m (1 minute)
7314
+ # - 1h (1 hour)
7315
+ # - 1d (1 day)
7316
+ # - 1w (1 week)
7317
+ # - 1i (1 index count)
7318
+ #
7319
+ # Or combine them:
7320
+ # "3d12h4m25s" # 3 days, 12 hours, 4 minutes, and 25 seconds
7321
+ #
7322
+ # Note that `half_life` is treated as a constant duration - calendar
7323
+ # durations such as months (or even days in the time-zone-aware case)
7324
+ # are not supported, please express your duration in an approximately
7325
+ # equivalent number of hours (e.g. '370h' instead of '1mo').
7326
+ #
7327
+ # @return [Expr]
7328
+ #
7329
+ # @example
7330
+ # df = Polars::DataFrame.new(
7331
+ # {
7332
+ # "values": [0, 1, 2, nil, 4],
7333
+ # "times": [
7334
+ # Date.new(2020, 1, 1),
7335
+ # Date.new(2020, 1, 3),
7336
+ # Date.new(2020, 1, 10),
7337
+ # Date.new(2020, 1, 15),
7338
+ # Date.new(2020, 1, 17)
7339
+ # ]
7340
+ # }
7341
+ # ).sort("times")
7342
+ # df.with_columns(
7343
+ # result: Polars.col("values").ewm_mean_by("times", half_life: "4d")
7344
+ # )
7345
+ # # =>
7346
+ # # shape: (5, 3)
7347
+ # # ┌────────┬────────────┬──────────┐
7348
+ # # │ values ┆ times ┆ result │
7349
+ # # │ --- ┆ --- ┆ --- │
7350
+ # # │ i64 ┆ date ┆ f64 │
7351
+ # # ╞════════╪════════════╪══════════╡
7352
+ # # │ 0 ┆ 2020-01-01 ┆ 0.0 │
7353
+ # # │ 1 ┆ 2020-01-03 ┆ 0.292893 │
7354
+ # # │ 2 ┆ 2020-01-10 ┆ 1.492474 │
7355
+ # # │ null ┆ 2020-01-15 ┆ null │
7356
+ # # │ 4 ┆ 2020-01-17 ┆ 3.254508 │
7357
+ # # └────────┴────────────┴──────────┘
7358
+ def ewm_mean_by(
7359
+ by,
7360
+ half_life:
7361
+ )
7362
+ by = Utils.parse_into_expression(by)
7363
+ half_life = Utils.parse_as_duration_string(half_life)
7364
+ wrap_expr(_rbexpr.ewm_mean_by(by, half_life))
6568
7365
  end
6569
7366
 
6570
7367
  # Exponentially-weighted moving standard deviation.
@@ -6596,7 +7393,7 @@ module Polars
6596
7393
  ignore_nulls: true
6597
7394
  )
6598
7395
  alpha = _prepare_alpha(com, span, half_life, alpha)
6599
- _from_rbexpr(_rbexpr.ewm_std(alpha, adjust, bias, min_periods, ignore_nulls))
7396
+ wrap_expr(_rbexpr.ewm_std(alpha, adjust, bias, min_periods, ignore_nulls))
6600
7397
  end
6601
7398
 
6602
7399
  # Exponentially-weighted moving variance.
@@ -6628,7 +7425,7 @@ module Polars
6628
7425
  ignore_nulls: true
6629
7426
  )
6630
7427
  alpha = _prepare_alpha(com, span, half_life, alpha)
6631
- _from_rbexpr(_rbexpr.ewm_var(alpha, adjust, bias, min_periods, ignore_nulls))
7428
+ wrap_expr(_rbexpr.ewm_var(alpha, adjust, bias, min_periods, ignore_nulls))
6632
7429
  end
6633
7430
 
6634
7431
  # Extend the Series with given number of values.
@@ -6660,7 +7457,7 @@ module Polars
6660
7457
  def extend_constant(value, n)
6661
7458
  value = Utils.parse_into_expression(value, str_as_lit: true)
6662
7459
  n = Utils.parse_into_expression(n)
6663
- _from_rbexpr(_rbexpr.extend_constant(value, n))
7460
+ wrap_expr(_rbexpr.extend_constant(value, n))
6664
7461
  end
6665
7462
 
6666
7463
  # Count all unique values and create a struct mapping value to count.
@@ -6714,7 +7511,7 @@ module Polars
6714
7511
  name = "count"
6715
7512
  end
6716
7513
  end
6717
- _from_rbexpr(
7514
+ wrap_expr(
6718
7515
  _rbexpr.value_counts(sort, parallel, name, normalize)
6719
7516
  )
6720
7517
  end
@@ -6749,7 +7546,7 @@ module Polars
6749
7546
  # # │ 3 │
6750
7547
  # # └─────┘
6751
7548
  def unique_counts
6752
- _from_rbexpr(_rbexpr.unique_counts)
7549
+ wrap_expr(_rbexpr.unique_counts)
6753
7550
  end
6754
7551
 
6755
7552
  # Compute the logarithm to a given base.
@@ -6774,7 +7571,31 @@ module Polars
6774
7571
  # # │ 1.584963 │
6775
7572
  # # └──────────┘
6776
7573
  def log(base = Math::E)
6777
- _from_rbexpr(_rbexpr.log(base))
7574
+ wrap_expr(_rbexpr.log(base))
7575
+ end
7576
+
7577
+ # Compute the natural logarithm of each element plus one.
7578
+ #
7579
+ # This computes `log(1 + x)` but is more numerically stable for `x` close to zero.
7580
+ #
7581
+ # @return [Expr]
7582
+ #
7583
+ # @example
7584
+ # df = Polars::DataFrame.new({"a" => [1, 2, 3]})
7585
+ # df.select(Polars.col("a").log1p)
7586
+ # # =>
7587
+ # # shape: (3, 1)
7588
+ # # ┌──────────┐
7589
+ # # │ a │
7590
+ # # │ --- │
7591
+ # # │ f64 │
7592
+ # # ╞══════════╡
7593
+ # # │ 0.693147 │
7594
+ # # │ 1.098612 │
7595
+ # # │ 1.386294 │
7596
+ # # └──────────┘
7597
+ def log1p
7598
+ wrap_expr(_rbexpr.log1p)
6778
7599
  end
6779
7600
 
6780
7601
  # Computes the entropy.
@@ -6813,7 +7634,7 @@ module Polars
6813
7634
  # # │ -6.754888 │
6814
7635
  # # └───────────┘
6815
7636
  def entropy(base: 2, normalize: true)
6816
- _from_rbexpr(_rbexpr.entropy(base, normalize))
7637
+ wrap_expr(_rbexpr.entropy(base, normalize))
6817
7638
  end
6818
7639
 
6819
7640
  # Run an expression over a sliding window that increases `1` slot every iteration.
@@ -6857,7 +7678,7 @@ module Polars
6857
7678
  # # │ -24 │
6858
7679
  # # └────────┘
6859
7680
  def cumulative_eval(expr, min_periods: 1)
6860
- _from_rbexpr(
7681
+ wrap_expr(
6861
7682
  _rbexpr.cumulative_eval(expr._rbexpr, min_periods)
6862
7683
  )
6863
7684
  end
@@ -6888,7 +7709,7 @@ module Polars
6888
7709
  # # │ 3 │
6889
7710
  # # └────────┘
6890
7711
  def set_sorted(descending: false)
6891
- _from_rbexpr(_rbexpr.set_sorted_flag(descending))
7712
+ wrap_expr(_rbexpr.set_sorted_flag(descending))
6892
7713
  end
6893
7714
 
6894
7715
  # Aggregate to list.
@@ -6913,7 +7734,7 @@ module Polars
6913
7734
  # # │ [1, 2, 3] ┆ [4, 5, 6] │
6914
7735
  # # └───────────┴───────────┘
6915
7736
  def implode
6916
- _from_rbexpr(_rbexpr.implode)
7737
+ wrap_expr(_rbexpr.implode)
6917
7738
  end
6918
7739
 
6919
7740
  # Shrink numeric columns to the minimal required datatype.
@@ -6948,7 +7769,72 @@ module Polars
6948
7769
  # # │ 3 ┆ 8589934592 ┆ 1073741824 ┆ 112 ┆ 129 ┆ c ┆ 0.12 ┆ false │
6949
7770
  # # └─────┴────────────┴────────────┴──────┴──────┴─────┴──────┴───────┘
6950
7771
  def shrink_dtype
6951
- _from_rbexpr(_rbexpr.shrink_dtype)
7772
+ wrap_expr(_rbexpr.shrink_dtype)
7773
+ end
7774
+
7775
+ # Bin values into buckets and count their occurrences.
7776
+ #
7777
+ # @note
7778
+ # This functionality is considered **unstable**. It may be changed
7779
+ # at any point without it being considered a breaking change.
7780
+ #
7781
+ # @param bins [Object]
7782
+ # Bin edges. If nil given, we determine the edges based on the data.
7783
+ # @param bin_count [Integer]
7784
+ # If `bins` is not provided, `bin_count` uniform bins are created that fully
7785
+ # encompass the data.
7786
+ # @param include_category [Boolean]
7787
+ # Include a column that shows the intervals as categories.
7788
+ # @param include_breakpoint [Boolean]
7789
+ # Include a column that indicates the upper breakpoint.
7790
+ #
7791
+ # @return [Expr]
7792
+ #
7793
+ # @example
7794
+ # df = Polars::DataFrame.new({"a" => [1, 3, 8, 8, 2, 1, 3]})
7795
+ # df.select(Polars.col("a").hist(bins: [1, 2, 3]))
7796
+ # # =>
7797
+ # # shape: (2, 1)
7798
+ # # ┌─────┐
7799
+ # # │ a │
7800
+ # # │ --- │
7801
+ # # │ u32 │
7802
+ # # ╞═════╡
7803
+ # # │ 3 │
7804
+ # # │ 2 │
7805
+ # # └─────┘
7806
+ #
7807
+ # @example
7808
+ # df.select(
7809
+ # Polars.col("a").hist(
7810
+ # bins: [1, 2, 3], include_breakpoint: true, include_category: true
7811
+ # )
7812
+ # )
7813
+ # # =>
7814
+ # # shape: (2, 1)
7815
+ # # ┌──────────────────────┐
7816
+ # # │ a │
7817
+ # # │ --- │
7818
+ # # │ struct[3] │
7819
+ # # ╞══════════════════════╡
7820
+ # # │ {2.0,"[1.0, 2.0]",3} │
7821
+ # # │ {3.0,"(2.0, 3.0]",2} │
7822
+ # # └──────────────────────┘
7823
+ def hist(
7824
+ bins: nil,
7825
+ bin_count: nil,
7826
+ include_category: false,
7827
+ include_breakpoint: false
7828
+ )
7829
+ if !bins.nil?
7830
+ if bins.is_a?(::Array)
7831
+ bins = Polars::Series.new(bins)
7832
+ end
7833
+ bins = Utils.parse_into_expression(bins)
7834
+ end
7835
+ wrap_expr(
7836
+ _rbexpr.hist(bins, bin_count, include_category, include_breakpoint)
7837
+ )
6952
7838
  end
6953
7839
 
6954
7840
  # Replace values by different values.
@@ -7107,7 +7993,7 @@ module Polars
7107
7993
  old = Utils.parse_into_expression(old, str_as_lit: true)
7108
7994
  new = Utils.parse_into_expression(new, str_as_lit: true)
7109
7995
 
7110
- result = _from_rbexpr(_rbexpr.replace(old, new))
7996
+ result = wrap_expr(_rbexpr.replace(old, new))
7111
7997
 
7112
7998
  if !return_dtype.nil?
7113
7999
  result = result.cast(return_dtype)
@@ -7259,11 +8145,161 @@ module Polars
7259
8145
 
7260
8146
  default = default.eql?(NO_DEFAULT) ? nil : Utils.parse_into_expression(default, str_as_lit: true)
7261
8147
 
7262
- _from_rbexpr(
8148
+ wrap_expr(
7263
8149
  _rbexpr.replace_strict(old, new, default, return_dtype)
7264
8150
  )
7265
8151
  end
7266
8152
 
8153
+ # Evaluate the number of set bits.
8154
+ #
8155
+ # @return [Expr]
8156
+ def bitwise_count_ones
8157
+ wrap_expr(_rbexpr.bitwise_count_ones)
8158
+ end
8159
+
8160
+ # Evaluate the number of unset bits.
8161
+ #
8162
+ # @return [Expr]
8163
+ def bitwise_count_zeros
8164
+ wrap_expr(_rbexpr.bitwise_count_zeros)
8165
+ end
8166
+
8167
+ # Evaluate the number most-significant set bits before seeing an unset bit.
8168
+ #
8169
+ # @return [Expr]
8170
+ def bitwise_leading_ones
8171
+ wrap_expr(_rbexpr.bitwise_leading_ones)
8172
+ end
8173
+
8174
+ # Evaluate the number most-significant unset bits before seeing a set bit.
8175
+ #
8176
+ # @return [Expr]
8177
+ def bitwise_leading_zeros
8178
+ wrap_expr(_rbexpr.bitwise_leading_zeros)
8179
+ end
8180
+
8181
+ # Evaluate the number least-significant set bits before seeing an unset bit.
8182
+ #
8183
+ # @return [Expr]
8184
+ def bitwise_trailing_ones
8185
+ wrap_expr(_rbexpr.bitwise_trailing_ones)
8186
+ end
8187
+
8188
+ # Evaluate the number least-significant unset bits before seeing a set bit.
8189
+ #
8190
+ # @return [Expr]
8191
+ def bitwise_trailing_zeros
8192
+ wrap_expr(_rbexpr.bitwise_trailing_zeros)
8193
+ end
8194
+
8195
+ # Perform an aggregation of bitwise ANDs.
8196
+ #
8197
+ # @return [Expr]
8198
+ #
8199
+ # @example
8200
+ # df = Polars::DataFrame.new({"n" => [-1, 0, 1]})
8201
+ # df.select(Polars.col("n").bitwise_and)
8202
+ # # =>
8203
+ # # shape: (1, 1)
8204
+ # # ┌─────┐
8205
+ # # │ n │
8206
+ # # │ --- │
8207
+ # # │ i64 │
8208
+ # # ╞═════╡
8209
+ # # │ 0 │
8210
+ # # └─────┘
8211
+ #
8212
+ # @example
8213
+ # df = Polars::DataFrame.new(
8214
+ # {"grouper" => ["a", "a", "a", "b", "b"], "n" => [-1, 0, 1, -1, 1]}
8215
+ # )
8216
+ # df.group_by("grouper", maintain_order: true).agg(Polars.col("n").bitwise_and)
8217
+ # # =>
8218
+ # # shape: (2, 2)
8219
+ # # ┌─────────┬─────┐
8220
+ # # │ grouper ┆ n │
8221
+ # # │ --- ┆ --- │
8222
+ # # │ str ┆ i64 │
8223
+ # # ╞═════════╪═════╡
8224
+ # # │ a ┆ 0 │
8225
+ # # │ b ┆ 1 │
8226
+ # # └─────────┴─────┘
8227
+ def bitwise_and
8228
+ wrap_expr(_rbexpr.bitwise_and)
8229
+ end
8230
+
8231
+ # Perform an aggregation of bitwise ORs.
8232
+ #
8233
+ # @return [Expr]
8234
+ #
8235
+ # @example
8236
+ # df = Polars::DataFrame.new({"n" => [-1, 0, 1]})
8237
+ # df.select(Polars.col("n").bitwise_or)
8238
+ # # =>
8239
+ # # shape: (1, 1)
8240
+ # # ┌─────┐
8241
+ # # │ n │
8242
+ # # │ --- │
8243
+ # # │ i64 │
8244
+ # # ╞═════╡
8245
+ # # │ -1 │
8246
+ # # └─────┘
8247
+ #
8248
+ # @example
8249
+ # df = Polars::DataFrame.new(
8250
+ # {"grouper" => ["a", "a", "a", "b", "b"], "n" => [-1, 0, 1, -1, 1]}
8251
+ # )
8252
+ # df.group_by("grouper", maintain_order: true).agg(Polars.col("n").bitwise_or)
8253
+ # # =>
8254
+ # # shape: (2, 2)
8255
+ # # ┌─────────┬─────┐
8256
+ # # │ grouper ┆ n │
8257
+ # # │ --- ┆ --- │
8258
+ # # │ str ┆ i64 │
8259
+ # # ╞═════════╪═════╡
8260
+ # # │ a ┆ -1 │
8261
+ # # │ b ┆ -1 │
8262
+ # # └─────────┴─────┘
8263
+ def bitwise_or
8264
+ wrap_expr(_rbexpr.bitwise_or)
8265
+ end
8266
+
8267
+ # Perform an aggregation of bitwise XORs.
8268
+ #
8269
+ # @return [Expr]
8270
+ #
8271
+ # @example
8272
+ # df = Polars::DataFrame.new({"n" => [-1, 0, 1]})
8273
+ # df.select(Polars.col("n").bitwise_xor)
8274
+ # # =>
8275
+ # # shape: (1, 1)
8276
+ # # ┌─────┐
8277
+ # # │ n │
8278
+ # # │ --- │
8279
+ # # │ i64 │
8280
+ # # ╞═════╡
8281
+ # # │ -2 │
8282
+ # # └─────┘
8283
+ #
8284
+ # @example
8285
+ # df = Polars::DataFrame.new(
8286
+ # {"grouper" => ["a", "a", "a", "b", "b"], "n" => [-1, 0, 1, -1, 1]}
8287
+ # )
8288
+ # df.group_by("grouper", maintain_order: true).agg(Polars.col("n").bitwise_xor)
8289
+ # # =>
8290
+ # # shape: (2, 2)
8291
+ # # ┌─────────┬─────┐
8292
+ # # │ grouper ┆ n │
8293
+ # # │ --- ┆ --- │
8294
+ # # │ str ┆ i64 │
8295
+ # # ╞═════════╪═════╡
8296
+ # # │ a ┆ -2 │
8297
+ # # │ b ┆ -2 │
8298
+ # # └─────────┴─────┘
8299
+ def bitwise_xor
8300
+ wrap_expr(_rbexpr.bitwise_xor)
8301
+ end
8302
+
7267
8303
  # Create an object namespace of all list related methods.
7268
8304
  #
7269
8305
  # @return [ListExpr]
@@ -7329,7 +8365,7 @@ module Polars
7329
8365
 
7330
8366
  private
7331
8367
 
7332
- def _from_rbexpr(expr)
8368
+ def wrap_expr(expr)
7333
8369
  Utils.wrap_expr(expr)
7334
8370
  end
7335
8371