polars-df 0.21.0-aarch64-linux-musl → 0.22.0-aarch64-linux-musl

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 (53) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +27 -0
  3. data/Cargo.lock +55 -48
  4. data/Cargo.toml +3 -0
  5. data/LICENSE-THIRD-PARTY.txt +23 -49
  6. data/README.md +12 -0
  7. data/lib/polars/3.2/polars.so +0 -0
  8. data/lib/polars/3.3/polars.so +0 -0
  9. data/lib/polars/3.4/polars.so +0 -0
  10. data/lib/polars/array_expr.rb +382 -3
  11. data/lib/polars/array_name_space.rb +281 -0
  12. data/lib/polars/binary_expr.rb +67 -0
  13. data/lib/polars/binary_name_space.rb +43 -0
  14. data/lib/polars/cat_expr.rb +224 -0
  15. data/lib/polars/cat_name_space.rb +138 -0
  16. data/lib/polars/config.rb +2 -2
  17. data/lib/polars/convert.rb +6 -6
  18. data/lib/polars/data_frame.rb +794 -27
  19. data/lib/polars/data_type_expr.rb +52 -0
  20. data/lib/polars/data_types.rb +26 -5
  21. data/lib/polars/date_time_expr.rb +252 -1
  22. data/lib/polars/date_time_name_space.rb +299 -0
  23. data/lib/polars/expr.rb +1248 -206
  24. data/lib/polars/functions/business.rb +95 -0
  25. data/lib/polars/functions/datatype.rb +21 -0
  26. data/lib/polars/functions/lazy.rb +14 -1
  27. data/lib/polars/io/csv.rb +1 -1
  28. data/lib/polars/io/iceberg.rb +27 -0
  29. data/lib/polars/io/json.rb +4 -4
  30. data/lib/polars/io/ndjson.rb +4 -4
  31. data/lib/polars/io/parquet.rb +32 -7
  32. data/lib/polars/io/scan_options.rb +4 -1
  33. data/lib/polars/lazy_frame.rb +1028 -28
  34. data/lib/polars/list_expr.rb +217 -17
  35. data/lib/polars/list_name_space.rb +231 -22
  36. data/lib/polars/meta_expr.rb +89 -0
  37. data/lib/polars/name_expr.rb +36 -0
  38. data/lib/polars/query_opt_flags.rb +50 -0
  39. data/lib/polars/scan_cast_options.rb +20 -1
  40. data/lib/polars/schema.rb +79 -3
  41. data/lib/polars/selector.rb +72 -0
  42. data/lib/polars/selectors.rb +3 -3
  43. data/lib/polars/series.rb +1053 -54
  44. data/lib/polars/string_expr.rb +436 -32
  45. data/lib/polars/string_name_space.rb +736 -50
  46. data/lib/polars/struct_expr.rb +103 -0
  47. data/lib/polars/struct_name_space.rb +19 -1
  48. data/lib/polars/utils/serde.rb +17 -0
  49. data/lib/polars/utils/various.rb +22 -1
  50. data/lib/polars/utils.rb +5 -1
  51. data/lib/polars/version.rb +1 -1
  52. data/lib/polars.rb +6 -0
  53. metadata +8 -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,47 @@ 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)
147
+ end
148
+
149
+ # Read a serialized expression from a file.
150
+ #
151
+ # @param source [Object]
152
+ # Path to a file or a file-like object (by file-like object, we refer to
153
+ # objects that have a `read` method, such as a file handler or `StringIO`).
154
+ #
155
+ # @return [Expr]
156
+ #
157
+ # @note
158
+ # This function uses marshaling if the logical plan contains Ruby UDFs,
159
+ # and as such inherits the security implications. Deserializing can execute
160
+ # arbitrary code, so it should only be attempted on trusted data.
161
+ #
162
+ # @note
163
+ # Serialization is not stable across Polars versions: a LazyFrame serialized
164
+ # in one Polars version may not be deserializable in another Polars version.
165
+ #
166
+ # @example
167
+ # expr = Polars.col("foo").sum.over("bar")
168
+ # bytes = expr.meta.serialize
169
+ # Polars::Expr.deserialize(StringIO.new(bytes))
170
+ # # => col("foo").sum().over([col("bar")])
171
+ def self.deserialize(source)
172
+ raise Todo unless RbExpr.respond_to?(:deserialize_binary)
173
+
174
+ if Utils.pathlike?(source)
175
+ source = Utils.normalize_filepath(source)
176
+ end
177
+
178
+ deserializer = RbExpr.method(:deserialize_binary)
179
+
180
+ _from_rbexpr(deserializer.(source))
143
181
  end
144
182
 
145
183
  # Cast to physical representation of the logical dtype.
@@ -176,7 +214,7 @@ module Polars
176
214
  # # │ a ┆ 0 │
177
215
  # # └──────┴───────────────┘
178
216
  def to_physical
179
- _from_rbexpr(_rbexpr.to_physical)
217
+ wrap_expr(_rbexpr.to_physical)
180
218
  end
181
219
 
182
220
  # Check if any boolean value in a Boolean column is `true`.
@@ -196,7 +234,7 @@ module Polars
196
234
  # # │ true ┆ false │
197
235
  # # └──────┴───────┘
198
236
  def any(drop_nulls: true)
199
- _from_rbexpr(_rbexpr.any(drop_nulls))
237
+ wrap_expr(_rbexpr.any(drop_nulls))
200
238
  end
201
239
 
202
240
  # Check if all boolean values in a Boolean column are `true`.
@@ -221,7 +259,33 @@ module Polars
221
259
  # # │ true ┆ false ┆ false │
222
260
  # # └──────┴───────┴───────┘
223
261
  def all(drop_nulls: true)
224
- _from_rbexpr(_rbexpr.all(drop_nulls))
262
+ wrap_expr(_rbexpr.all(drop_nulls))
263
+ end
264
+
265
+ # Return indices where expression evaluates `true`.
266
+ #
267
+ # @return [Expr]
268
+ #
269
+ # @note
270
+ # Modifies number of rows returned, so will fail in combination with other
271
+ # expressions. Use as only expression in `select` / `with_columns`.
272
+ #
273
+ # @example
274
+ # df = Polars::DataFrame.new({"a" => [1, 1, 2, 1]})
275
+ # df.select((Polars.col("a") == 1).arg_true)
276
+ # # =>
277
+ # # shape: (3, 1)
278
+ # # ┌─────┐
279
+ # # │ a │
280
+ # # │ --- │
281
+ # # │ u32 │
282
+ # # ╞═════╡
283
+ # # │ 0 │
284
+ # # │ 1 │
285
+ # # │ 3 │
286
+ # # └─────┘
287
+ def arg_true
288
+ wrap_expr(Plr.arg_where(_rbexpr))
225
289
  end
226
290
 
227
291
  # Compute the square root of the elements.
@@ -243,7 +307,29 @@ module Polars
243
307
  # # │ 2.0 │
244
308
  # # └──────────┘
245
309
  def sqrt
246
- self**0.5
310
+ wrap_expr(_rbexpr.sqrt)
311
+ end
312
+
313
+ # Compute the cube root of the elements.
314
+ #
315
+ # @return [Expr]
316
+ #
317
+ # @example
318
+ # df = Polars::DataFrame.new({"values" => [1.0, 2.0, 4.0]})
319
+ # df.select(Polars.col("values").cbrt)
320
+ # # =>
321
+ # # shape: (3, 1)
322
+ # # ┌──────────┐
323
+ # # │ values │
324
+ # # │ --- │
325
+ # # │ f64 │
326
+ # # ╞══════════╡
327
+ # # │ 1.0 │
328
+ # # │ 1.259921 │
329
+ # # │ 1.587401 │
330
+ # # └──────────┘
331
+ def cbrt
332
+ wrap_expr(_rbexpr.cbrt)
247
333
  end
248
334
 
249
335
  # Compute the base 10 logarithm of the input array, element-wise.
@@ -287,7 +373,7 @@ module Polars
287
373
  # # │ 54.59815 │
288
374
  # # └──────────┘
289
375
  def exp
290
- _from_rbexpr(_rbexpr.exp)
376
+ wrap_expr(_rbexpr.exp)
291
377
  end
292
378
 
293
379
  # Rename the output of an expression.
@@ -322,11 +408,9 @@ module Polars
322
408
  # # │ 3 ┆ null │
323
409
  # # └─────┴──────┘
324
410
  def alias(name)
325
- _from_rbexpr(_rbexpr._alias(name))
411
+ wrap_expr(_rbexpr._alias(name))
326
412
  end
327
413
 
328
- # TODO support symbols for exclude
329
-
330
414
  # Exclude certain columns from a wildcard/regex selection.
331
415
  #
332
416
  # You may also use regexes in the exclude list. They must start with `^` and end
@@ -510,7 +594,7 @@ module Polars
510
594
  # # │ true │
511
595
  # # └───────┘
512
596
  def is_not
513
- _from_rbexpr(_rbexpr.not_)
597
+ wrap_expr(_rbexpr.not_)
514
598
  end
515
599
  alias_method :not_, :is_not
516
600
 
@@ -540,7 +624,7 @@ module Polars
540
624
  # # │ 5 ┆ 5.0 ┆ false ┆ false │
541
625
  # # └──────┴─────┴──────────┴──────────┘
542
626
  def is_null
543
- _from_rbexpr(_rbexpr.is_null)
627
+ wrap_expr(_rbexpr.is_null)
544
628
  end
545
629
 
546
630
  # Returns a boolean Series indicating which values are not null.
@@ -569,7 +653,7 @@ module Polars
569
653
  # # │ 5 ┆ 5.0 ┆ true ┆ true │
570
654
  # # └──────┴─────┴────────────┴────────────┘
571
655
  def is_not_null
572
- _from_rbexpr(_rbexpr.is_not_null)
656
+ wrap_expr(_rbexpr.is_not_null)
573
657
  end
574
658
 
575
659
  # Returns a boolean Series indicating which values are finite.
@@ -595,7 +679,7 @@ module Polars
595
679
  # # │ true ┆ false │
596
680
  # # └──────┴───────┘
597
681
  def is_finite
598
- _from_rbexpr(_rbexpr.is_finite)
682
+ wrap_expr(_rbexpr.is_finite)
599
683
  end
600
684
 
601
685
  # Returns a boolean Series indicating which values are infinite.
@@ -621,7 +705,7 @@ module Polars
621
705
  # # │ false ┆ true │
622
706
  # # └───────┴───────┘
623
707
  def is_infinite
624
- _from_rbexpr(_rbexpr.is_infinite)
708
+ wrap_expr(_rbexpr.is_infinite)
625
709
  end
626
710
 
627
711
  # Returns a boolean Series indicating which values are NaN.
@@ -654,7 +738,7 @@ module Polars
654
738
  # # │ 5 ┆ 5.0 ┆ false │
655
739
  # # └──────┴─────┴─────────┘
656
740
  def is_nan
657
- _from_rbexpr(_rbexpr.is_nan)
741
+ wrap_expr(_rbexpr.is_nan)
658
742
  end
659
743
 
660
744
  # Returns a boolean Series indicating which values are not NaN.
@@ -687,7 +771,7 @@ module Polars
687
771
  # # │ 5 ┆ 5.0 ┆ true │
688
772
  # # └──────┴─────┴──────────────┘
689
773
  def is_not_nan
690
- _from_rbexpr(_rbexpr.is_not_nan)
774
+ wrap_expr(_rbexpr.is_not_nan)
691
775
  end
692
776
 
693
777
  # Get the group indexes of the group by operation.
@@ -722,7 +806,7 @@ module Polars
722
806
  # # │ two ┆ [3, 4, 5] │
723
807
  # # └───────┴───────────┘
724
808
  def agg_groups
725
- _from_rbexpr(_rbexpr.agg_groups)
809
+ wrap_expr(_rbexpr.agg_groups)
726
810
  end
727
811
 
728
812
  # Count the number of values in this expression.
@@ -742,7 +826,7 @@ module Polars
742
826
  # # │ 3 ┆ 2 │
743
827
  # # └─────┴─────┘
744
828
  def count
745
- _from_rbexpr(_rbexpr.count)
829
+ wrap_expr(_rbexpr.count)
746
830
  end
747
831
 
748
832
  # Count the number of values in this expression.
@@ -762,7 +846,7 @@ module Polars
762
846
  # # │ 3 ┆ 3 │
763
847
  # # └─────┴─────┘
764
848
  def len
765
- _from_rbexpr(_rbexpr.len)
849
+ wrap_expr(_rbexpr.len)
766
850
  end
767
851
  alias_method :length, :len
768
852
 
@@ -801,7 +885,7 @@ module Polars
801
885
  if !length.is_a?(Expr)
802
886
  length = Polars.lit(length)
803
887
  end
804
- _from_rbexpr(_rbexpr.slice(offset._rbexpr, length._rbexpr))
888
+ wrap_expr(_rbexpr.slice(offset._rbexpr, length._rbexpr))
805
889
  end
806
890
 
807
891
  # Append expressions.
@@ -835,7 +919,7 @@ module Polars
835
919
  # # └─────┴──────┘
836
920
  def append(other, upcast: true)
837
921
  other = Utils.parse_into_expression(other)
838
- _from_rbexpr(_rbexpr.append(other, upcast))
922
+ wrap_expr(_rbexpr.append(other, upcast))
839
923
  end
840
924
 
841
925
  # Create a single chunk of memory for this Series.
@@ -860,7 +944,7 @@ module Polars
860
944
  # # │ 2 │
861
945
  # # └────────┘
862
946
  def rechunk
863
- _from_rbexpr(_rbexpr.rechunk)
947
+ wrap_expr(_rbexpr.rechunk)
864
948
  end
865
949
 
866
950
  # Drop null values.
@@ -887,7 +971,7 @@ module Polars
887
971
  # # │ NaN │
888
972
  # # └─────┘
889
973
  def drop_nulls
890
- _from_rbexpr(_rbexpr.drop_nulls)
974
+ wrap_expr(_rbexpr.drop_nulls)
891
975
  end
892
976
 
893
977
  # Drop floating point NaN values.
@@ -914,7 +998,7 @@ module Polars
914
998
  # # │ 4.0 │
915
999
  # # └──────┘
916
1000
  def drop_nans
917
- _from_rbexpr(_rbexpr.drop_nans)
1001
+ wrap_expr(_rbexpr.drop_nans)
918
1002
  end
919
1003
 
920
1004
  # Get an array with the cumulative sum computed at every element.
@@ -949,7 +1033,7 @@ module Polars
949
1033
  # # │ 10 ┆ 4 │
950
1034
  # # └─────┴───────────┘
951
1035
  def cum_sum(reverse: false)
952
- _from_rbexpr(_rbexpr.cum_sum(reverse))
1036
+ wrap_expr(_rbexpr.cum_sum(reverse))
953
1037
  end
954
1038
  alias_method :cumsum, :cum_sum
955
1039
 
@@ -985,7 +1069,7 @@ module Polars
985
1069
  # # │ 24 ┆ 4 │
986
1070
  # # └─────┴───────────┘
987
1071
  def cum_prod(reverse: false)
988
- _from_rbexpr(_rbexpr.cum_prod(reverse))
1072
+ wrap_expr(_rbexpr.cum_prod(reverse))
989
1073
  end
990
1074
  alias_method :cumprod, :cum_prod
991
1075
 
@@ -1017,7 +1101,7 @@ module Polars
1017
1101
  # # │ 1 ┆ 4 │
1018
1102
  # # └─────┴───────────┘
1019
1103
  def cum_min(reverse: false)
1020
- _from_rbexpr(_rbexpr.cum_min(reverse))
1104
+ wrap_expr(_rbexpr.cum_min(reverse))
1021
1105
  end
1022
1106
  alias_method :cummin, :cum_min
1023
1107
 
@@ -1049,7 +1133,7 @@ module Polars
1049
1133
  # # │ 4 ┆ 4 │
1050
1134
  # # └─────┴───────────┘
1051
1135
  def cum_max(reverse: false)
1052
- _from_rbexpr(_rbexpr.cum_max(reverse))
1136
+ wrap_expr(_rbexpr.cum_max(reverse))
1053
1137
  end
1054
1138
  alias_method :cummax, :cum_max
1055
1139
 
@@ -1083,7 +1167,7 @@ module Polars
1083
1167
  # # │ d ┆ 3 ┆ 1 │
1084
1168
  # # └──────┴───────────┴───────────────────┘
1085
1169
  def cum_count(reverse: false)
1086
- _from_rbexpr(_rbexpr.cum_count(reverse))
1170
+ wrap_expr(_rbexpr.cum_count(reverse))
1087
1171
  end
1088
1172
  alias_method :cumcount, :cum_count
1089
1173
 
@@ -1109,7 +1193,7 @@ module Polars
1109
1193
  # # │ 1.0 │
1110
1194
  # # └─────┘
1111
1195
  def floor
1112
- _from_rbexpr(_rbexpr.floor)
1196
+ wrap_expr(_rbexpr.floor)
1113
1197
  end
1114
1198
 
1115
1199
  # Rounds up to the nearest integer value.
@@ -1134,7 +1218,7 @@ module Polars
1134
1218
  # # │ 2.0 │
1135
1219
  # # └─────┘
1136
1220
  def ceil
1137
- _from_rbexpr(_rbexpr.ceil)
1221
+ wrap_expr(_rbexpr.ceil)
1138
1222
  end
1139
1223
 
1140
1224
  # Round underlying floating point data by `decimals` digits.
@@ -1167,7 +1251,32 @@ module Polars
1167
1251
  # # │ 1.2 │
1168
1252
  # # └─────┘
1169
1253
  def round(decimals = 0, mode: "half_to_even")
1170
- _from_rbexpr(_rbexpr.round(decimals, mode))
1254
+ wrap_expr(_rbexpr.round(decimals, mode))
1255
+ end
1256
+
1257
+ # Round to a number of significant figures.
1258
+ #
1259
+ # @param digits [Integer]
1260
+ # Number of significant figures to round to.
1261
+ #
1262
+ # @return [Expr]
1263
+ #
1264
+ # @example
1265
+ # df = Polars::DataFrame.new({"a" => [0.01234, 3.333, 1234.0]})
1266
+ # df.with_columns(Polars.col("a").round_sig_figs(2).alias("round_sig_figs"))
1267
+ # # =>
1268
+ # # shape: (3, 2)
1269
+ # # ┌─────────┬────────────────┐
1270
+ # # │ a ┆ round_sig_figs │
1271
+ # # │ --- ┆ --- │
1272
+ # # │ f64 ┆ f64 │
1273
+ # # ╞═════════╪════════════════╡
1274
+ # # │ 0.01234 ┆ 0.012 │
1275
+ # # │ 3.333 ┆ 3.3 │
1276
+ # # │ 1234.0 ┆ 1200.0 │
1277
+ # # └─────────┴────────────────┘
1278
+ def round_sig_figs(digits)
1279
+ wrap_expr(_rbexpr.round_sig_figs(digits))
1171
1280
  end
1172
1281
 
1173
1282
  # Compute the dot/inner product between two Expressions.
@@ -1196,7 +1305,7 @@ module Polars
1196
1305
  # # └─────┘
1197
1306
  def dot(other)
1198
1307
  other = Utils.parse_into_expression(other, str_as_lit: false)
1199
- _from_rbexpr(_rbexpr.dot(other))
1308
+ wrap_expr(_rbexpr.dot(other))
1200
1309
  end
1201
1310
 
1202
1311
  # Compute the most occurring value(s).
@@ -1224,7 +1333,7 @@ module Polars
1224
1333
  # # │ 1 ┆ 2 │
1225
1334
  # # └─────┴─────┘
1226
1335
  def mode
1227
- _from_rbexpr(_rbexpr.mode)
1336
+ wrap_expr(_rbexpr.mode)
1228
1337
  end
1229
1338
 
1230
1339
  # Cast between data types.
@@ -1263,7 +1372,7 @@ module Polars
1263
1372
  # # └─────┴─────┘
1264
1373
  def cast(dtype, strict: true)
1265
1374
  dtype = Utils.rb_type_to_dtype(dtype)
1266
- _from_rbexpr(_rbexpr.cast(dtype, strict))
1375
+ wrap_expr(_rbexpr.cast(dtype, strict))
1267
1376
  end
1268
1377
 
1269
1378
  # Sort this column. In projection/ selection context the whole column is sorted.
@@ -1338,7 +1447,7 @@ module Polars
1338
1447
  # # │ one ┆ [1, 2, 98] │
1339
1448
  # # └───────┴────────────┘
1340
1449
  def sort(reverse: false, nulls_last: false)
1341
- _from_rbexpr(_rbexpr.sort_with(reverse, nulls_last))
1450
+ wrap_expr(_rbexpr.sort_with(reverse, nulls_last))
1342
1451
  end
1343
1452
 
1344
1453
  # Return the `k` largest elements.
@@ -1377,7 +1486,113 @@ module Polars
1377
1486
  # # └───────┴──────────┘
1378
1487
  def top_k(k: 5)
1379
1488
  k = Utils.parse_into_expression(k)
1380
- _from_rbexpr(_rbexpr.top_k(k))
1489
+ wrap_expr(_rbexpr.top_k(k))
1490
+ end
1491
+
1492
+ # Return the elements corresponding to the `k` largest elements of the `by` column(s).
1493
+ #
1494
+ # Non-null elements are always preferred over null elements, regardless of
1495
+ # the value of `reverse`. The output is not guaranteed to be in any
1496
+ # particular order, call :func:`sort` after this function if you wish the
1497
+ # output to be sorted.
1498
+ #
1499
+ # @param by [Object]
1500
+ # Column(s) used to determine the largest elements.
1501
+ # Accepts expression input. Strings are parsed as column names.
1502
+ # @param k [Integer]
1503
+ # Number of elements to return.
1504
+ # @param reverse [Object]
1505
+ # Consider the `k` smallest elements of the `by` column(s) (instead of the `k`
1506
+ # largest). This can be specified per column by passing a sequence of
1507
+ # booleans.
1508
+ #
1509
+ # @return [Expr]
1510
+ #
1511
+ # @example
1512
+ # df = Polars::DataFrame.new(
1513
+ # {
1514
+ # "a" => [1, 2, 3, 4, 5, 6],
1515
+ # "b" => [6, 5, 4, 3, 2, 1],
1516
+ # "c" => ["Apple", "Orange", "Apple", "Apple", "Banana", "Banana"]
1517
+ # }
1518
+ # )
1519
+ # # =>
1520
+ # # shape: (6, 3)
1521
+ # # ┌─────┬─────┬────────┐
1522
+ # # │ a ┆ b ┆ c │
1523
+ # # │ --- ┆ --- ┆ --- │
1524
+ # # │ i64 ┆ i64 ┆ str │
1525
+ # # ╞═════╪═════╪════════╡
1526
+ # # │ 1 ┆ 6 ┆ Apple │
1527
+ # # │ 2 ┆ 5 ┆ Orange │
1528
+ # # │ 3 ┆ 4 ┆ Apple │
1529
+ # # │ 4 ┆ 3 ┆ Apple │
1530
+ # # │ 5 ┆ 2 ┆ Banana │
1531
+ # # │ 6 ┆ 1 ┆ Banana │
1532
+ # # └─────┴─────┴────────┘
1533
+ #
1534
+ # @example Get the top 2 rows by column `a` or `b`.
1535
+ # df.select(
1536
+ # Polars.all.top_k_by("a", k: 2).name.suffix("_top_by_a"),
1537
+ # Polars.all.top_k_by("b", k: 2).name.suffix("_top_by_b")
1538
+ # )
1539
+ # # =>
1540
+ # # shape: (2, 6)
1541
+ # # ┌────────────┬────────────┬────────────┬────────────┬────────────┬────────────┐
1542
+ # # │ a_top_by_a ┆ b_top_by_a ┆ c_top_by_a ┆ a_top_by_b ┆ b_top_by_b ┆ c_top_by_b │
1543
+ # # │ --- ┆ --- ┆ --- ┆ --- ┆ --- ┆ --- │
1544
+ # # │ i64 ┆ i64 ┆ str ┆ i64 ┆ i64 ┆ str │
1545
+ # # ╞════════════╪════════════╪════════════╪════════════╪════════════╪════════════╡
1546
+ # # │ 6 ┆ 1 ┆ Banana ┆ 1 ┆ 6 ┆ Apple │
1547
+ # # │ 5 ┆ 2 ┆ Banana ┆ 2 ┆ 5 ┆ Orange │
1548
+ # # └────────────┴────────────┴────────────┴────────────┴────────────┴────────────┘
1549
+ #
1550
+ # @example Get the top 2 rows by multiple columns with given order.
1551
+ # df.select(
1552
+ # Polars.all
1553
+ # .top_k_by(["c", "a"], k: 2, reverse: [false, true])
1554
+ # .name.suffix("_by_ca"),
1555
+ # Polars.all
1556
+ # .top_k_by(["c", "b"], k: 2, reverse: [false, true])
1557
+ # .name.suffix("_by_cb")
1558
+ # )
1559
+ # # =>
1560
+ # # shape: (2, 6)
1561
+ # # ┌─────────┬─────────┬─────────┬─────────┬─────────┬─────────┐
1562
+ # # │ a_by_ca ┆ b_by_ca ┆ c_by_ca ┆ a_by_cb ┆ b_by_cb ┆ c_by_cb │
1563
+ # # │ --- ┆ --- ┆ --- ┆ --- ┆ --- ┆ --- │
1564
+ # # │ i64 ┆ i64 ┆ str ┆ i64 ┆ i64 ┆ str │
1565
+ # # ╞═════════╪═════════╪═════════╪═════════╪═════════╪═════════╡
1566
+ # # │ 2 ┆ 5 ┆ Orange ┆ 2 ┆ 5 ┆ Orange │
1567
+ # # │ 5 ┆ 2 ┆ Banana ┆ 6 ┆ 1 ┆ Banana │
1568
+ # # └─────────┴─────────┴─────────┴─────────┴─────────┴─────────┘
1569
+ #
1570
+ # @example Get the top 2 rows by column `a` in each group.
1571
+ # df.group_by("c", maintain_order: true)
1572
+ # .agg(Polars.all.top_k_by("a", k: 2))
1573
+ # .explode(Polars.all.exclude("c"))
1574
+ # # =>
1575
+ # # shape: (5, 3)
1576
+ # # ┌────────┬─────┬─────┐
1577
+ # # │ c ┆ a ┆ b │
1578
+ # # │ --- ┆ --- ┆ --- │
1579
+ # # │ str ┆ i64 ┆ i64 │
1580
+ # # ╞════════╪═════╪═════╡
1581
+ # # │ Apple ┆ 4 ┆ 3 │
1582
+ # # │ Apple ┆ 3 ┆ 4 │
1583
+ # # │ Orange ┆ 2 ┆ 5 │
1584
+ # # │ Banana ┆ 6 ┆ 1 │
1585
+ # # │ Banana ┆ 5 ┆ 2 │
1586
+ # # └────────┴─────┴─────┘
1587
+ def top_k_by(
1588
+ by,
1589
+ k: 5,
1590
+ reverse: false
1591
+ )
1592
+ k = Utils.parse_into_expression(k)
1593
+ by = Utils.parse_into_list_of_expressions(by)
1594
+ reverse = Utils.extend_bool(reverse, by.length, "reverse", "by")
1595
+ wrap_expr(_rbexpr.top_k_by(by, k, reverse))
1381
1596
  end
1382
1597
 
1383
1598
  # Return the `k` smallest elements.
@@ -1416,7 +1631,113 @@ module Polars
1416
1631
  # # └───────┴──────────┘
1417
1632
  def bottom_k(k: 5)
1418
1633
  k = Utils.parse_into_expression(k)
1419
- _from_rbexpr(_rbexpr.bottom_k(k))
1634
+ wrap_expr(_rbexpr.bottom_k(k))
1635
+ end
1636
+
1637
+ # Return the elements corresponding to the `k` smallest elements of the `by` column(s).
1638
+ #
1639
+ # Non-null elements are always preferred over null elements, regardless of
1640
+ # the value of `reverse`. The output is not guaranteed to be in any
1641
+ # particular order, call :func:`sort` after this function if you wish the
1642
+ # output to be sorted.
1643
+ #
1644
+ # @param by [Object]
1645
+ # Column(s) used to determine the smallest elements.
1646
+ # Accepts expression input. Strings are parsed as column names.
1647
+ # @param k [Integer]
1648
+ # Number of elements to return.
1649
+ # @param reverse [Object]
1650
+ # Consider the `k` largest elements of the `by` column(s) (instead of the `k`
1651
+ # smallest). This can be specified per column by passing a sequence of
1652
+ # booleans.
1653
+ #
1654
+ # @return [Expr]
1655
+ #
1656
+ # @example
1657
+ # df = Polars::DataFrame.new(
1658
+ # {
1659
+ # "a" => [1, 2, 3, 4, 5, 6],
1660
+ # "b" => [6, 5, 4, 3, 2, 1],
1661
+ # "c" => ["Apple", "Orange", "Apple", "Apple", "Banana", "Banana"],
1662
+ # }
1663
+ # )
1664
+ # # =>
1665
+ # # shape: (6, 3)
1666
+ # # ┌─────┬─────┬────────┐
1667
+ # # │ a ┆ b ┆ c │
1668
+ # # │ --- ┆ --- ┆ --- │
1669
+ # # │ i64 ┆ i64 ┆ str │
1670
+ # # ╞═════╪═════╪════════╡
1671
+ # # │ 1 ┆ 6 ┆ Apple │
1672
+ # # │ 2 ┆ 5 ┆ Orange │
1673
+ # # │ 3 ┆ 4 ┆ Apple │
1674
+ # # │ 4 ┆ 3 ┆ Apple │
1675
+ # # │ 5 ┆ 2 ┆ Banana │
1676
+ # # │ 6 ┆ 1 ┆ Banana │
1677
+ # # └─────┴─────┴────────┘
1678
+ #
1679
+ # @example Get the bottom 2 rows by column `a` or `b`.
1680
+ # df.select(
1681
+ # Polars.all.bottom_k_by("a", k: 2).name.suffix("_btm_by_a"),
1682
+ # Polars.all.bottom_k_by("b", k: 2).name.suffix("_btm_by_b")
1683
+ # )
1684
+ # # =>
1685
+ # # shape: (2, 6)
1686
+ # # ┌────────────┬────────────┬────────────┬────────────┬────────────┬────────────┐
1687
+ # # │ a_btm_by_a ┆ b_btm_by_a ┆ c_btm_by_a ┆ a_btm_by_b ┆ b_btm_by_b ┆ c_btm_by_b │
1688
+ # # │ --- ┆ --- ┆ --- ┆ --- ┆ --- ┆ --- │
1689
+ # # │ i64 ┆ i64 ┆ str ┆ i64 ┆ i64 ┆ str │
1690
+ # # ╞════════════╪════════════╪════════════╪════════════╪════════════╪════════════╡
1691
+ # # │ 1 ┆ 6 ┆ Apple ┆ 6 ┆ 1 ┆ Banana │
1692
+ # # │ 2 ┆ 5 ┆ Orange ┆ 5 ┆ 2 ┆ Banana │
1693
+ # # └────────────┴────────────┴────────────┴────────────┴────────────┴────────────┘
1694
+ #
1695
+ # @example Get the bottom 2 rows by multiple columns with given order.
1696
+ # df.select(
1697
+ # Polars.all
1698
+ # .bottom_k_by(["c", "a"], k: 2, reverse: [false, true])
1699
+ # .name.suffix("_by_ca"),
1700
+ # Polars.all
1701
+ # .bottom_k_by(["c", "b"], k: 2, reverse: [false, true])
1702
+ # .name.suffix("_by_cb"),
1703
+ # )
1704
+ # # =>
1705
+ # # shape: (2, 6)
1706
+ # # ┌─────────┬─────────┬─────────┬─────────┬─────────┬─────────┐
1707
+ # # │ a_by_ca ┆ b_by_ca ┆ c_by_ca ┆ a_by_cb ┆ b_by_cb ┆ c_by_cb │
1708
+ # # │ --- ┆ --- ┆ --- ┆ --- ┆ --- ┆ --- │
1709
+ # # │ i64 ┆ i64 ┆ str ┆ i64 ┆ i64 ┆ str │
1710
+ # # ╞═════════╪═════════╪═════════╪═════════╪═════════╪═════════╡
1711
+ # # │ 4 ┆ 3 ┆ Apple ┆ 1 ┆ 6 ┆ Apple │
1712
+ # # │ 3 ┆ 4 ┆ Apple ┆ 3 ┆ 4 ┆ Apple │
1713
+ # # └─────────┴─────────┴─────────┴─────────┴─────────┴─────────┘
1714
+ #
1715
+ # @example Get the bottom 2 rows by column `a` in each group.
1716
+ # df.group_by("c", maintain_order: true)
1717
+ # .agg(Polars.all.bottom_k_by("a", k: 2))
1718
+ # .explode(Polars.all.exclude("c"))
1719
+ # # =>
1720
+ # # shape: (5, 3)
1721
+ # # ┌────────┬─────┬─────┐
1722
+ # # │ c ┆ a ┆ b │
1723
+ # # │ --- ┆ --- ┆ --- │
1724
+ # # │ str ┆ i64 ┆ i64 │
1725
+ # # ╞════════╪═════╪═════╡
1726
+ # # │ Apple ┆ 1 ┆ 6 │
1727
+ # # │ Apple ┆ 3 ┆ 4 │
1728
+ # # │ Orange ┆ 2 ┆ 5 │
1729
+ # # │ Banana ┆ 5 ┆ 2 │
1730
+ # # │ Banana ┆ 6 ┆ 1 │
1731
+ # # └────────┴─────┴─────┘
1732
+ def bottom_k_by(
1733
+ by,
1734
+ k: 5,
1735
+ reverse: false
1736
+ )
1737
+ k = Utils.parse_into_expression(k)
1738
+ by = Utils.parse_into_list_of_expressions(by)
1739
+ reverse = Utils.extend_bool(reverse, by.length, "reverse", "by")
1740
+ wrap_expr(_rbexpr.bottom_k_by(by, k, reverse))
1420
1741
  end
1421
1742
 
1422
1743
  # Get the index values that would sort this column.
@@ -1447,7 +1768,7 @@ module Polars
1447
1768
  # # │ 2 │
1448
1769
  # # └─────┘
1449
1770
  def arg_sort(reverse: false, nulls_last: false)
1450
- _from_rbexpr(_rbexpr.arg_sort(reverse, nulls_last))
1771
+ wrap_expr(_rbexpr.arg_sort(reverse, nulls_last))
1451
1772
  end
1452
1773
 
1453
1774
  # Get the index of the maximal value.
@@ -1471,7 +1792,7 @@ module Polars
1471
1792
  # # │ 2 │
1472
1793
  # # └─────┘
1473
1794
  def arg_max
1474
- _from_rbexpr(_rbexpr.arg_max)
1795
+ wrap_expr(_rbexpr.arg_max)
1475
1796
  end
1476
1797
 
1477
1798
  # Get the index of the minimal value.
@@ -1495,7 +1816,37 @@ module Polars
1495
1816
  # # │ 1 │
1496
1817
  # # └─────┘
1497
1818
  def arg_min
1498
- _from_rbexpr(_rbexpr.arg_min)
1819
+ wrap_expr(_rbexpr.arg_min)
1820
+ end
1821
+
1822
+ # Get the index of the first occurrence of a value, or `nil` if it's not found.
1823
+ #
1824
+ # @param element [Object]
1825
+ # Value to find.
1826
+ #
1827
+ # @return [Expr]
1828
+ #
1829
+ # @example
1830
+ # df = Polars::DataFrame.new({"a" => [1, nil, 17]})
1831
+ # df.select(
1832
+ # [
1833
+ # Polars.col("a").index_of(17).alias("seventeen"),
1834
+ # Polars.col("a").index_of(nil).alias("null"),
1835
+ # Polars.col("a").index_of(55).alias("fiftyfive")
1836
+ # ]
1837
+ # )
1838
+ # # =>
1839
+ # # shape: (1, 3)
1840
+ # # ┌───────────┬──────┬───────────┐
1841
+ # # │ seventeen ┆ null ┆ fiftyfive │
1842
+ # # │ --- ┆ --- ┆ --- │
1843
+ # # │ u32 ┆ u32 ┆ u32 │
1844
+ # # ╞═══════════╪══════╪═══════════╡
1845
+ # # │ 2 ┆ 1 ┆ null │
1846
+ # # └───────────┴──────┴───────────┘
1847
+ def index_of(element)
1848
+ element = Utils.parse_into_expression(element, str_as_lit: true)
1849
+ wrap_expr(_rbexpr.index_of(element))
1499
1850
  end
1500
1851
 
1501
1852
  # Find indices where elements should be inserted to maintain order.
@@ -1536,7 +1887,7 @@ module Polars
1536
1887
  # # └──────┴───────┴─────┘
1537
1888
  def search_sorted(element, side: "any", descending: false)
1538
1889
  element = Utils.parse_into_expression(element, str_as_lit: false)
1539
- _from_rbexpr(_rbexpr.search_sorted(element, side, descending))
1890
+ wrap_expr(_rbexpr.search_sorted(element, side, descending))
1540
1891
  end
1541
1892
 
1542
1893
  # Sort this column by the ordering of another column, or multiple other columns.
@@ -1594,7 +1945,7 @@ module Polars
1594
1945
  by = Utils.parse_into_list_of_expressions(by, *more_by)
1595
1946
  reverse = Utils.extend_bool(reverse, by.length, "reverse", "by")
1596
1947
  nulls_last = Utils.extend_bool(nulls_last, by.length, "nulls_last", "by")
1597
- _from_rbexpr(
1948
+ wrap_expr(
1598
1949
  _rbexpr.sort_by(
1599
1950
  by, reverse, nulls_last, multithreaded, maintain_order
1600
1951
  )
@@ -1639,7 +1990,7 @@ module Polars
1639
1990
  else
1640
1991
  indices_lit = Utils.parse_into_expression(indices, str_as_lit: false)
1641
1992
  end
1642
- _from_rbexpr(_rbexpr.gather(indices_lit))
1993
+ wrap_expr(_rbexpr.gather(indices_lit))
1643
1994
  end
1644
1995
  alias_method :take, :gather
1645
1996
 
@@ -1677,7 +2028,7 @@ module Polars
1677
2028
  # # └───────┴───────┘
1678
2029
  def get(index)
1679
2030
  index_lit = Utils.parse_into_expression(index)
1680
- _from_rbexpr(_rbexpr.get(index_lit))
2031
+ wrap_expr(_rbexpr.get(index_lit))
1681
2032
  end
1682
2033
 
1683
2034
  # Shift the values by a given period.
@@ -1709,7 +2060,7 @@ module Polars
1709
2060
  fill_value = Utils.parse_into_expression(fill_value, str_as_lit: true)
1710
2061
  end
1711
2062
  n = Utils.parse_into_expression(n)
1712
- _from_rbexpr(_rbexpr.shift(n, fill_value))
2063
+ wrap_expr(_rbexpr.shift(n, fill_value))
1713
2064
  end
1714
2065
 
1715
2066
  # Shift the values by a given period and fill the resulting null values.
@@ -1812,9 +2163,9 @@ module Polars
1812
2163
 
1813
2164
  if !value.nil?
1814
2165
  value = Utils.parse_into_expression(value, str_as_lit: true)
1815
- _from_rbexpr(_rbexpr.fill_null(value))
2166
+ wrap_expr(_rbexpr.fill_null(value))
1816
2167
  else
1817
- _from_rbexpr(_rbexpr.fill_null_with_strategy(strategy, limit))
2168
+ wrap_expr(_rbexpr.fill_null_with_strategy(strategy, limit))
1818
2169
  end
1819
2170
  end
1820
2171
 
@@ -1843,7 +2194,7 @@ module Polars
1843
2194
  # # └──────┴──────┘
1844
2195
  def fill_nan(fill_value)
1845
2196
  fill_value = Utils.parse_into_expression(fill_value, str_as_lit: true)
1846
- _from_rbexpr(_rbexpr.fill_nan(fill_value))
2197
+ wrap_expr(_rbexpr.fill_nan(fill_value))
1847
2198
  end
1848
2199
 
1849
2200
  # Fill missing values with the latest seen values.
@@ -1939,7 +2290,7 @@ module Polars
1939
2290
  # # │ 5 ┆ banana ┆ 1 ┆ beetle ┆ 1 ┆ banana ┆ 5 ┆ beetle │
1940
2291
  # # └─────┴────────┴─────┴────────┴───────────┴────────────────┴───────────┴──────────────┘
1941
2292
  def reverse
1942
- _from_rbexpr(_rbexpr.reverse)
2293
+ wrap_expr(_rbexpr.reverse)
1943
2294
  end
1944
2295
 
1945
2296
  # Get standard deviation.
@@ -1962,7 +2313,7 @@ module Polars
1962
2313
  # # │ 1.0 │
1963
2314
  # # └─────┘
1964
2315
  def std(ddof: 1)
1965
- _from_rbexpr(_rbexpr.std(ddof))
2316
+ wrap_expr(_rbexpr.std(ddof))
1966
2317
  end
1967
2318
 
1968
2319
  # Get variance.
@@ -1985,7 +2336,7 @@ module Polars
1985
2336
  # # │ 1.0 │
1986
2337
  # # └─────┘
1987
2338
  def var(ddof: 1)
1988
- _from_rbexpr(_rbexpr.var(ddof))
2339
+ wrap_expr(_rbexpr.var(ddof))
1989
2340
  end
1990
2341
 
1991
2342
  # Get maximum value.
@@ -2005,7 +2356,7 @@ module Polars
2005
2356
  # # │ 1.0 │
2006
2357
  # # └─────┘
2007
2358
  def max
2008
- _from_rbexpr(_rbexpr.max)
2359
+ wrap_expr(_rbexpr.max)
2009
2360
  end
2010
2361
 
2011
2362
  # Get minimum value.
@@ -2025,7 +2376,7 @@ module Polars
2025
2376
  # # │ -1.0 │
2026
2377
  # # └──────┘
2027
2378
  def min
2028
- _from_rbexpr(_rbexpr.min)
2379
+ wrap_expr(_rbexpr.min)
2029
2380
  end
2030
2381
 
2031
2382
  # Get maximum value, but propagate/poison encountered NaN values.
@@ -2045,7 +2396,7 @@ module Polars
2045
2396
  # # │ NaN │
2046
2397
  # # └─────┘
2047
2398
  def nan_max
2048
- _from_rbexpr(_rbexpr.nan_max)
2399
+ wrap_expr(_rbexpr.nan_max)
2049
2400
  end
2050
2401
 
2051
2402
  # Get minimum value, but propagate/poison encountered NaN values.
@@ -2065,7 +2416,7 @@ module Polars
2065
2416
  # # │ NaN │
2066
2417
  # # └─────┘
2067
2418
  def nan_min
2068
- _from_rbexpr(_rbexpr.nan_min)
2419
+ wrap_expr(_rbexpr.nan_min)
2069
2420
  end
2070
2421
 
2071
2422
  # Get sum value.
@@ -2089,7 +2440,7 @@ module Polars
2089
2440
  # # │ 0 │
2090
2441
  # # └─────┘
2091
2442
  def sum
2092
- _from_rbexpr(_rbexpr.sum)
2443
+ wrap_expr(_rbexpr.sum)
2093
2444
  end
2094
2445
 
2095
2446
  # Get mean value.
@@ -2109,7 +2460,7 @@ module Polars
2109
2460
  # # │ 0.0 │
2110
2461
  # # └─────┘
2111
2462
  def mean
2112
- _from_rbexpr(_rbexpr.mean)
2463
+ wrap_expr(_rbexpr.mean)
2113
2464
  end
2114
2465
 
2115
2466
  # Get median value using linear interpolation.
@@ -2129,7 +2480,7 @@ module Polars
2129
2480
  # # │ 0.0 │
2130
2481
  # # └─────┘
2131
2482
  def median
2132
- _from_rbexpr(_rbexpr.median)
2483
+ wrap_expr(_rbexpr.median)
2133
2484
  end
2134
2485
 
2135
2486
  # Compute the product of an expression.
@@ -2149,7 +2500,7 @@ module Polars
2149
2500
  # # │ 6 │
2150
2501
  # # └─────┘
2151
2502
  def product
2152
- _from_rbexpr(_rbexpr.product)
2503
+ wrap_expr(_rbexpr.product)
2153
2504
  end
2154
2505
 
2155
2506
  # Count unique values.
@@ -2169,7 +2520,7 @@ module Polars
2169
2520
  # # │ 2 │
2170
2521
  # # └─────┘
2171
2522
  def n_unique
2172
- _from_rbexpr(_rbexpr.n_unique)
2523
+ wrap_expr(_rbexpr.n_unique)
2173
2524
  end
2174
2525
 
2175
2526
  # Approx count unique values.
@@ -2191,7 +2542,7 @@ module Polars
2191
2542
  # # │ 2 │
2192
2543
  # # └─────┘
2193
2544
  def approx_n_unique
2194
- _from_rbexpr(_rbexpr.approx_n_unique)
2545
+ wrap_expr(_rbexpr.approx_n_unique)
2195
2546
  end
2196
2547
  alias_method :approx_unique, :approx_n_unique
2197
2548
 
@@ -2217,7 +2568,33 @@ module Polars
2217
2568
  # # │ 2 ┆ 0 │
2218
2569
  # # └─────┴─────┘
2219
2570
  def null_count
2220
- _from_rbexpr(_rbexpr.null_count)
2571
+ wrap_expr(_rbexpr.null_count)
2572
+ end
2573
+
2574
+ # Check whether the expression contains one or more null values.
2575
+ #
2576
+ # @return [Expr]
2577
+ #
2578
+ # @example
2579
+ # df = Polars::DataFrame.new(
2580
+ # {
2581
+ # "a" => [nil, 1, nil],
2582
+ # "b" => [10, nil, 300],
2583
+ # "c" => [350, 650, 850]
2584
+ # }
2585
+ # )
2586
+ # df.select(Polars.all.has_nulls)
2587
+ # # =>
2588
+ # # shape: (1, 3)
2589
+ # # ┌──────┬──────┬───────┐
2590
+ # # │ a ┆ b ┆ c │
2591
+ # # │ --- ┆ --- ┆ --- │
2592
+ # # │ bool ┆ bool ┆ bool │
2593
+ # # ╞══════╪══════╪═══════╡
2594
+ # # │ true ┆ true ┆ false │
2595
+ # # └──────┴──────┴───────┘
2596
+ def has_nulls
2597
+ null_count > 0
2221
2598
  end
2222
2599
 
2223
2600
  # Get index of first unique value.
@@ -2257,7 +2634,7 @@ module Polars
2257
2634
  # # │ 1 │
2258
2635
  # # └─────┘
2259
2636
  def arg_unique
2260
- _from_rbexpr(_rbexpr.arg_unique)
2637
+ wrap_expr(_rbexpr.arg_unique)
2261
2638
  end
2262
2639
 
2263
2640
  # Get unique values of this expression.
@@ -2282,9 +2659,9 @@ module Polars
2282
2659
  # # └─────┘
2283
2660
  def unique(maintain_order: false)
2284
2661
  if maintain_order
2285
- _from_rbexpr(_rbexpr.unique_stable)
2662
+ wrap_expr(_rbexpr.unique_stable)
2286
2663
  else
2287
- _from_rbexpr(_rbexpr.unique)
2664
+ wrap_expr(_rbexpr.unique)
2288
2665
  end
2289
2666
  end
2290
2667
 
@@ -2305,7 +2682,7 @@ module Polars
2305
2682
  # # │ 1 │
2306
2683
  # # └─────┘
2307
2684
  def first
2308
- _from_rbexpr(_rbexpr.first)
2685
+ wrap_expr(_rbexpr.first)
2309
2686
  end
2310
2687
 
2311
2688
  # Get the last value.
@@ -2325,7 +2702,7 @@ module Polars
2325
2702
  # # │ 2 │
2326
2703
  # # └─────┘
2327
2704
  def last
2328
- _from_rbexpr(_rbexpr.last)
2705
+ wrap_expr(_rbexpr.last)
2329
2706
  end
2330
2707
 
2331
2708
  # Apply window function over a subgroup.
@@ -2389,7 +2766,110 @@ module Polars
2389
2766
  # # └────────┘
2390
2767
  def over(expr)
2391
2768
  rbexprs = Utils.parse_into_list_of_expressions(expr)
2392
- _from_rbexpr(_rbexpr.over(rbexprs))
2769
+ wrap_expr(_rbexpr.over(rbexprs))
2770
+ end
2771
+
2772
+ # Create rolling groups based on a temporal or integer column.
2773
+ #
2774
+ # If you have a time series `<t_0, t_1, ..., t_n>`, then by default the
2775
+ # windows created will be
2776
+ #
2777
+ # * (t_0 - period, t_0]
2778
+ # * (t_1 - period, t_1]
2779
+ # * ...
2780
+ # * (t_n - period, t_n]
2781
+ #
2782
+ # whereas if you pass a non-default `offset`, then the windows will be
2783
+ #
2784
+ # * (t_0 + offset, t_0 + offset + period]
2785
+ # * (t_1 + offset, t_1 + offset + period]
2786
+ # * ...
2787
+ # * (t_n + offset, t_n + offset + period]
2788
+ #
2789
+ # The `period` and `offset` arguments are created either from a timedelta, or
2790
+ # by using the following string language:
2791
+ #
2792
+ # - 1ns (1 nanosecond)
2793
+ # - 1us (1 microsecond)
2794
+ # - 1ms (1 millisecond)
2795
+ # - 1s (1 second)
2796
+ # - 1m (1 minute)
2797
+ # - 1h (1 hour)
2798
+ # - 1d (1 calendar day)
2799
+ # - 1w (1 calendar week)
2800
+ # - 1mo (1 calendar month)
2801
+ # - 1q (1 calendar quarter)
2802
+ # - 1y (1 calendar year)
2803
+ # - 1i (1 index count)
2804
+ #
2805
+ # Or combine them:
2806
+ # "3d12h4m25s" # 3 days, 12 hours, 4 minutes, and 25 seconds
2807
+ #
2808
+ # By "calendar day", we mean the corresponding time on the next day (which may
2809
+ # not be 24 hours, due to daylight savings). Similarly for "calendar week",
2810
+ # "calendar month", "calendar quarter", and "calendar year".
2811
+ #
2812
+ # @param index_column [Object]
2813
+ # Column used to group based on the time window.
2814
+ # Often of type Date/Datetime.
2815
+ # This column must be sorted in ascending order.
2816
+ # In case of a rolling group by on indices, dtype needs to be one of
2817
+ # \\\\{UInt32, UInt64, Int32, Int64}. Note that the first three get temporarily
2818
+ # cast to Int64, so if performance matters use an Int64 column.
2819
+ # @param period [Object]
2820
+ # Length of the window - must be non-negative.
2821
+ # @param offset [Object]
2822
+ # Offset of the window. Default is `-period`.
2823
+ # @param closed ['right', 'left', 'both', 'none']
2824
+ # Define which sides of the temporal interval are closed (inclusive).
2825
+ #
2826
+ # @return [Expr]
2827
+ #
2828
+ # @example
2829
+ # dates = [
2830
+ # "2020-01-01 13:45:48",
2831
+ # "2020-01-01 16:42:13",
2832
+ # "2020-01-01 16:45:09",
2833
+ # "2020-01-02 18:12:48",
2834
+ # "2020-01-03 19:45:32",
2835
+ # "2020-01-08 23:16:43"
2836
+ # ]
2837
+ # df = Polars::DataFrame.new({"dt" => dates, "a": [3, 7, 5, 9, 2, 1]}).with_columns(
2838
+ # Polars.col("dt").str.strptime(Polars::Datetime).set_sorted
2839
+ # )
2840
+ # df.with_columns(
2841
+ # sum_a: Polars.sum("a").rolling(index_column: "dt", period: "2d"),
2842
+ # min_a: Polars.min("a").rolling(index_column: "dt", period: "2d"),
2843
+ # max_a: Polars.max("a").rolling(index_column: "dt", period: "2d")
2844
+ # )
2845
+ # # =>
2846
+ # # shape: (6, 5)
2847
+ # # ┌─────────────────────┬─────┬───────┬───────┬───────┐
2848
+ # # │ dt ┆ a ┆ sum_a ┆ min_a ┆ max_a │
2849
+ # # │ --- ┆ --- ┆ --- ┆ --- ┆ --- │
2850
+ # # │ datetime[μs] ┆ i64 ┆ i64 ┆ i64 ┆ i64 │
2851
+ # # ╞═════════════════════╪═════╪═══════╪═══════╪═══════╡
2852
+ # # │ 2020-01-01 13:45:48 ┆ 3 ┆ 3 ┆ 3 ┆ 3 │
2853
+ # # │ 2020-01-01 16:42:13 ┆ 7 ┆ 10 ┆ 3 ┆ 7 │
2854
+ # # │ 2020-01-01 16:45:09 ┆ 5 ┆ 15 ┆ 3 ┆ 7 │
2855
+ # # │ 2020-01-02 18:12:48 ┆ 9 ┆ 24 ┆ 3 ┆ 9 │
2856
+ # # │ 2020-01-03 19:45:32 ┆ 2 ┆ 11 ┆ 2 ┆ 9 │
2857
+ # # │ 2020-01-08 23:16:43 ┆ 1 ┆ 1 ┆ 1 ┆ 1 │
2858
+ # # └─────────────────────┴─────┴───────┴───────┴───────┘
2859
+ def rolling(
2860
+ index_column:,
2861
+ period:,
2862
+ offset: nil,
2863
+ closed: "right"
2864
+ )
2865
+ if offset.nil?
2866
+ offset = Utils.negate_duration_string(Utils.parse_as_duration_string(period))
2867
+ end
2868
+
2869
+ period = Utils.parse_as_duration_string(period)
2870
+ offset = Utils.parse_as_duration_string(offset)
2871
+
2872
+ wrap_expr(_rbexpr.rolling(index_column, period, offset, closed))
2393
2873
  end
2394
2874
 
2395
2875
  # Get mask of unique values.
@@ -2411,7 +2891,7 @@ module Polars
2411
2891
  # # │ true │
2412
2892
  # # └───────┘
2413
2893
  def is_unique
2414
- _from_rbexpr(_rbexpr.is_unique)
2894
+ wrap_expr(_rbexpr.is_unique)
2415
2895
  end
2416
2896
 
2417
2897
  # Get a mask of the first unique value.
@@ -2439,10 +2919,34 @@ module Polars
2439
2919
  # # │ 5 ┆ true │
2440
2920
  # # └─────┴──────────┘
2441
2921
  def is_first_distinct
2442
- _from_rbexpr(_rbexpr.is_first_distinct)
2922
+ wrap_expr(_rbexpr.is_first_distinct)
2443
2923
  end
2444
2924
  alias_method :is_first, :is_first_distinct
2445
2925
 
2926
+ # Return a boolean mask indicating the last occurrence of each distinct value.
2927
+ #
2928
+ # @return [Expr]
2929
+ #
2930
+ # @example
2931
+ # df = Polars::DataFrame.new({"a" => [1, 1, 2, 3, 2]})
2932
+ # df.with_columns(Polars.col("a").is_last_distinct.alias("last"))
2933
+ # # =>
2934
+ # # shape: (5, 2)
2935
+ # # ┌─────┬───────┐
2936
+ # # │ a ┆ last │
2937
+ # # │ --- ┆ --- │
2938
+ # # │ i64 ┆ bool │
2939
+ # # ╞═════╪═══════╡
2940
+ # # │ 1 ┆ false │
2941
+ # # │ 1 ┆ true │
2942
+ # # │ 2 ┆ false │
2943
+ # # │ 3 ┆ true │
2944
+ # # │ 2 ┆ true │
2945
+ # # └─────┴───────┘
2946
+ def is_last_distinct
2947
+ wrap_expr(_rbexpr.is_last_distinct)
2948
+ end
2949
+
2446
2950
  # Get mask of duplicated values.
2447
2951
  #
2448
2952
  # @return [Expr]
@@ -2462,7 +2966,7 @@ module Polars
2462
2966
  # # │ false │
2463
2967
  # # └───────┘
2464
2968
  def is_duplicated
2465
- _from_rbexpr(_rbexpr.is_duplicated)
2969
+ wrap_expr(_rbexpr.is_duplicated)
2466
2970
  end
2467
2971
 
2468
2972
  # Get a boolean mask of the local maximum peaks.
@@ -2486,7 +2990,7 @@ module Polars
2486
2990
  # # │ true │
2487
2991
  # # └───────┘
2488
2992
  def peak_max
2489
- _from_rbexpr(_rbexpr.peak_max)
2993
+ wrap_expr(_rbexpr.peak_max)
2490
2994
  end
2491
2995
 
2492
2996
  # Get a boolean mask of the local minimum peaks.
@@ -2510,7 +3014,7 @@ module Polars
2510
3014
  # # │ false │
2511
3015
  # # └───────┘
2512
3016
  def peak_min
2513
- _from_rbexpr(_rbexpr.peak_min)
3017
+ wrap_expr(_rbexpr.peak_min)
2514
3018
  end
2515
3019
 
2516
3020
  # Get quantile value.
@@ -2584,7 +3088,7 @@ module Polars
2584
3088
  # # └─────┘
2585
3089
  def quantile(quantile, interpolation: "nearest")
2586
3090
  quantile = Utils.parse_into_expression(quantile, str_as_lit: false)
2587
- _from_rbexpr(_rbexpr.quantile(quantile, interpolation))
3091
+ wrap_expr(_rbexpr.quantile(quantile, interpolation))
2588
3092
  end
2589
3093
 
2590
3094
  # Bin continuous values into discrete categories.
@@ -2640,7 +3144,7 @@ module Polars
2640
3144
  # # │ 2 ┆ inf ┆ (1, inf] │
2641
3145
  # # └─────┴────────────┴────────────┘
2642
3146
  def cut(breaks, labels: nil, left_closed: false, include_breaks: false)
2643
- _from_rbexpr(_rbexpr.cut(breaks, labels, left_closed, include_breaks))
3147
+ wrap_expr(_rbexpr.cut(breaks, labels, left_closed, include_breaks))
2644
3148
  end
2645
3149
 
2646
3150
  # Bin continuous values into discrete categories based on their quantiles.
@@ -2731,7 +3235,7 @@ module Polars
2731
3235
  )
2732
3236
  end
2733
3237
 
2734
- _from_rbexpr(rbexpr)
3238
+ wrap_expr(rbexpr)
2735
3239
  end
2736
3240
 
2737
3241
  # Get the lengths of runs of identical values.
@@ -2756,7 +3260,7 @@ module Polars
2756
3260
  # # │ 2 ┆ 3 │
2757
3261
  # # └─────┴───────┘
2758
3262
  def rle
2759
- _from_rbexpr(_rbexpr.rle)
3263
+ wrap_expr(_rbexpr.rle)
2760
3264
  end
2761
3265
 
2762
3266
  # Map values to run IDs.
@@ -2784,7 +3288,7 @@ module Polars
2784
3288
  # # │ 1 ┆ y ┆ 2 ┆ 3 │
2785
3289
  # # └─────┴──────┴─────┴──────┘
2786
3290
  def rle_id
2787
- _from_rbexpr(_rbexpr.rle_id)
3291
+ wrap_expr(_rbexpr.rle_id)
2788
3292
  end
2789
3293
 
2790
3294
  # Filter a single column.
@@ -2823,7 +3327,7 @@ module Polars
2823
3327
  # # │ g2 ┆ 0 ┆ 3 │
2824
3328
  # # └───────────┴─────┴─────┘
2825
3329
  def filter(predicate)
2826
- _from_rbexpr(_rbexpr.filter(predicate._rbexpr))
3330
+ wrap_expr(_rbexpr.filter(predicate._rbexpr))
2827
3331
  end
2828
3332
 
2829
3333
  # Filter a single column.
@@ -2904,7 +3408,7 @@ module Polars
2904
3408
  # if !return_dtype.nil?
2905
3409
  # return_dtype = Utils.rb_type_to_dtype(return_dtype)
2906
3410
  # end
2907
- # _from_rbexpr(
3411
+ # wrap_expr(
2908
3412
  # _rbexpr.map_batches(
2909
3413
  # # TODO _map_batches_wrapper
2910
3414
  # f,
@@ -3036,7 +3540,7 @@ module Polars
3036
3540
  # # │ b ┆ [2, 3, 4] │
3037
3541
  # # └───────┴───────────┘
3038
3542
  def flatten
3039
- _from_rbexpr(_rbexpr.explode)
3543
+ wrap_expr(_rbexpr.explode)
3040
3544
  end
3041
3545
 
3042
3546
  # Explode a list or utf8 Series.
@@ -3063,7 +3567,7 @@ module Polars
3063
3567
  # # │ 6 │
3064
3568
  # # └─────┘
3065
3569
  def explode
3066
- _from_rbexpr(_rbexpr.explode)
3570
+ wrap_expr(_rbexpr.explode)
3067
3571
  end
3068
3572
 
3069
3573
  # Take every nth value in the Series and return as a new Series.
@@ -3085,7 +3589,7 @@ module Polars
3085
3589
  # # │ 7 │
3086
3590
  # # └─────┘
3087
3591
  def gather_every(n, offset = 0)
3088
- _from_rbexpr(_rbexpr.gather_every(n, offset))
3592
+ wrap_expr(_rbexpr.gather_every(n, offset))
3089
3593
  end
3090
3594
  alias_method :take_every, :gather_every
3091
3595
 
@@ -3111,7 +3615,7 @@ module Polars
3111
3615
  # # │ 3 │
3112
3616
  # # └─────┘
3113
3617
  def head(n = 10)
3114
- _from_rbexpr(_rbexpr.head(n))
3618
+ wrap_expr(_rbexpr.head(n))
3115
3619
  end
3116
3620
 
3117
3621
  # Get the last `n` rows.
@@ -3136,7 +3640,7 @@ module Polars
3136
3640
  # # │ 7 │
3137
3641
  # # └─────┘
3138
3642
  def tail(n = 10)
3139
- _from_rbexpr(_rbexpr.tail(n))
3643
+ wrap_expr(_rbexpr.tail(n))
3140
3644
  end
3141
3645
 
3142
3646
  # Get the first `n` rows.
@@ -3166,6 +3670,89 @@ module Polars
3166
3670
  head(n)
3167
3671
  end
3168
3672
 
3673
+ # Method equivalent of bitwise "and" operator `expr & other & ...`.
3674
+ #
3675
+ # @param others [Array]
3676
+ # One or more integer or boolean expressions to evaluate/combine.
3677
+ #
3678
+ # @return [Expr]
3679
+ #
3680
+ # @example
3681
+ # df = Polars::DataFrame.new(
3682
+ # {
3683
+ # "x" => [5, 6, 7, 4, 8],
3684
+ # "y" => [1.5, 2.5, 1.0, 4.0, -5.75],
3685
+ # "z" => [-9, 2, -1, 4, 8]
3686
+ # }
3687
+ # )
3688
+ # df.select(
3689
+ # (Polars.col("x") >= Polars.col("z"))
3690
+ # .and_(
3691
+ # Polars.col("y") >= Polars.col("z"),
3692
+ # Polars.col("y") == Polars.col("y"),
3693
+ # Polars.col("z") <= Polars.col("x"),
3694
+ # Polars.col("y") != Polars.col("x"),
3695
+ # )
3696
+ # .alias("all")
3697
+ # )
3698
+ # # =>
3699
+ # # shape: (5, 1)
3700
+ # # ┌───────┐
3701
+ # # │ all │
3702
+ # # │ --- │
3703
+ # # │ bool │
3704
+ # # ╞═══════╡
3705
+ # # │ true │
3706
+ # # │ true │
3707
+ # # │ true │
3708
+ # # │ false │
3709
+ # # │ false │
3710
+ # # └───────┘
3711
+ def and_(*others)
3712
+ ([self] + others).reduce(:&)
3713
+ end
3714
+
3715
+ # Method equivalent of bitwise "or" operator `expr | other | ...`.
3716
+ #
3717
+ # @param others [Array]
3718
+ # One or more integer or boolean expressions to evaluate/combine.
3719
+ #
3720
+ # @return [Expr]
3721
+ #
3722
+ # @example
3723
+ # df = Polars::DataFrame.new(
3724
+ # {
3725
+ # "x" => [5, 6, 7, 4, 8],
3726
+ # "y" => [1.5, 2.5, 1.0, 4.0, -5.75],
3727
+ # "z" => [-9, 2, -1, 4, 8]
3728
+ # }
3729
+ # )
3730
+ # df.select(
3731
+ # (Polars.col("x") == Polars.col("y"))
3732
+ # .or_(
3733
+ # Polars.col("x") == Polars.col("y"),
3734
+ # Polars.col("y") == Polars.col("z"),
3735
+ # Polars.col("y").cast(Integer) == Polars.col("z"),
3736
+ # )
3737
+ # .alias("any")
3738
+ # )
3739
+ # # =>
3740
+ # # shape: (5, 1)
3741
+ # # ┌───────┐
3742
+ # # │ any │
3743
+ # # │ --- │
3744
+ # # │ bool │
3745
+ # # ╞═══════╡
3746
+ # # │ false │
3747
+ # # │ true │
3748
+ # # │ false │
3749
+ # # │ true │
3750
+ # # │ false │
3751
+ # # └───────┘
3752
+ def or_(*others)
3753
+ ([self] + others).reduce(:|)
3754
+ end
3755
+
3169
3756
  # Method equivalent of equality operator `expr == other`.
3170
3757
  #
3171
3758
  # @param other [Object]
@@ -3198,7 +3785,7 @@ module Polars
3198
3785
  self == other
3199
3786
  end
3200
3787
 
3201
- # Method equivalent of equality operator `expr == other` where `None == None`.
3788
+ # Method equivalent of equality operator `expr == other` where `nil == nil`.
3202
3789
  #
3203
3790
  # This differs from default `eq` where null values are propagated.
3204
3791
  #
@@ -3234,7 +3821,7 @@ module Polars
3234
3821
  # # └──────┴──────┴────────┴────────────────┘
3235
3822
  def eq_missing(other)
3236
3823
  other = Utils.parse_into_expression(other, str_as_lit: true)
3237
- _from_rbexpr(_rbexpr.eq_missing(other))
3824
+ wrap_expr(_rbexpr.eq_missing(other))
3238
3825
  end
3239
3826
 
3240
3827
  # Method equivalent of "greater than or equal" operator `expr >= other`.
@@ -3402,7 +3989,7 @@ module Polars
3402
3989
  self != other
3403
3990
  end
3404
3991
 
3405
- # Method equivalent of equality operator `expr != other` where `None == None`.
3992
+ # Method equivalent of equality operator `expr != other` where `nil == nil`.
3406
3993
  #
3407
3994
  # This differs from default `ne` where null values are propagated.
3408
3995
  #
@@ -3438,7 +4025,7 @@ module Polars
3438
4025
  # # └──────┴──────┴────────┴────────────────┘
3439
4026
  def ne_missing(other)
3440
4027
  other = Utils.parse_into_expression(other, str_as_lit: true)
3441
- _from_rbexpr(_rbexpr.neq_missing(other))
4028
+ wrap_expr(_rbexpr.neq_missing(other))
3442
4029
  end
3443
4030
 
3444
4031
  # Method equivalent of addition operator `expr + other`.
@@ -3515,7 +4102,7 @@ module Polars
3515
4102
  # # │ 5 ┆ 2.5 ┆ 2 │
3516
4103
  # # └─────┴─────┴──────┘
3517
4104
  def floordiv(other)
3518
- _from_rbexpr(_rbexpr.floordiv(_to_rbexpr(other)))
4105
+ wrap_expr(_rbexpr.floordiv(_to_rbexpr(other)))
3519
4106
  end
3520
4107
 
3521
4108
  # Method equivalent of modulus operator `expr % other`.
@@ -3741,7 +4328,7 @@ module Polars
3741
4328
  # # └───────────┴──────────────────┴──────────┘
3742
4329
  def is_in(other, nulls_equal: false)
3743
4330
  other = Utils.parse_into_expression(other)
3744
- _from_rbexpr(_rbexpr.is_in(other, nulls_equal))
4331
+ wrap_expr(_rbexpr.is_in(other, nulls_equal))
3745
4332
  end
3746
4333
  alias_method :in?, :is_in
3747
4334
 
@@ -3777,7 +4364,7 @@ module Polars
3777
4364
  # # └─────────────────┘
3778
4365
  def repeat_by(by)
3779
4366
  by = Utils.parse_into_expression(by, str_as_lit: false)
3780
- _from_rbexpr(_rbexpr.repeat_by(by))
4367
+ wrap_expr(_rbexpr.repeat_by(by))
3781
4368
  end
3782
4369
 
3783
4370
  # Check if this expression is between start and end.
@@ -3850,11 +4437,48 @@ module Polars
3850
4437
  lower_bound = Utils.parse_into_expression(lower_bound)
3851
4438
  upper_bound = Utils.parse_into_expression(upper_bound)
3852
4439
 
3853
- _from_rbexpr(
4440
+ wrap_expr(
3854
4441
  _rbexpr.is_between(lower_bound, upper_bound, closed)
3855
4442
  )
3856
4443
  end
3857
4444
 
4445
+ # Check if this expression is close, i.e. almost equal, to the other expression.
4446
+ #
4447
+ # @param abs_tol [Float]
4448
+ # Absolute tolerance. This is the maximum allowed absolute difference between
4449
+ # two values. Must be non-negative.
4450
+ # @param rel_tol [Float]
4451
+ # Relative tolerance. This is the maximum allowed difference between two
4452
+ # values, relative to the larger absolute value. Must be in the range [0, 1).
4453
+ # @param nans_equal [Boolean]
4454
+ # Whether NaN values should be considered equal.
4455
+ #
4456
+ # @return [Expr]
4457
+ #
4458
+ # @example
4459
+ # df = Polars::DataFrame.new({"a" => [1.5, 2.0, 2.5], "b" => [1.55, 2.2, 3.0]})
4460
+ # df.with_columns(Polars.col("a").is_close("b", abs_tol: 0.1).alias("is_close"))
4461
+ # # =>
4462
+ # # shape: (3, 3)
4463
+ # # ┌─────┬──────┬──────────┐
4464
+ # # │ a ┆ b ┆ is_close │
4465
+ # # │ --- ┆ --- ┆ --- │
4466
+ # # │ f64 ┆ f64 ┆ bool │
4467
+ # # ╞═════╪══════╪══════════╡
4468
+ # # │ 1.5 ┆ 1.55 ┆ true │
4469
+ # # │ 2.0 ┆ 2.2 ┆ false │
4470
+ # # │ 2.5 ┆ 3.0 ┆ false │
4471
+ # # └─────┴──────┴──────────┘
4472
+ def is_close(
4473
+ other,
4474
+ abs_tol: 0.0,
4475
+ rel_tol: 1e-09,
4476
+ nans_equal: false
4477
+ )
4478
+ other = Utils.parse_into_expression(other)
4479
+ wrap_expr(_rbexpr.is_close(other, abs_tol, rel_tol, nans_equal))
4480
+ end
4481
+
3858
4482
  # Hash the elements in the selection.
3859
4483
  #
3860
4484
  # The hash value is of type `:u64`.
@@ -3894,7 +4518,7 @@ module Polars
3894
4518
  k1 = seed_1.nil? ? seed : seed_1
3895
4519
  k2 = seed_2.nil? ? seed : seed_2
3896
4520
  k3 = seed_3.nil? ? seed : seed_3
3897
- _from_rbexpr(_rbexpr._hash(k0, k1, k2, k3))
4521
+ wrap_expr(_rbexpr._hash(k0, k1, k2, k3))
3898
4522
  end
3899
4523
 
3900
4524
  # Reinterpret the underlying bits as a signed/unsigned integer.
@@ -3928,7 +4552,7 @@ module Polars
3928
4552
  # # │ 2 ┆ 2 │
3929
4553
  # # └───────────────┴──────────┘
3930
4554
  def reinterpret(signed: false)
3931
- _from_rbexpr(_rbexpr.reinterpret(signed))
4555
+ wrap_expr(_rbexpr.reinterpret(signed))
3932
4556
  end
3933
4557
 
3934
4558
  # Print the value that this expression evaluates to and pass on the value.
@@ -3991,7 +4615,7 @@ module Polars
3991
4615
  # # │ 3.0 ┆ 3.0 │
3992
4616
  # # └─────┴─────┘
3993
4617
  def interpolate(method: "linear")
3994
- _from_rbexpr(_rbexpr.interpolate(method))
4618
+ wrap_expr(_rbexpr.interpolate(method))
3995
4619
  end
3996
4620
 
3997
4621
  # Fill null values using interpolation based on another column.
@@ -4022,7 +4646,7 @@ module Polars
4022
4646
  # # └──────┴─────┴────────────────┘
4023
4647
  def interpolate_by(by)
4024
4648
  by = Utils.parse_into_expression(by)
4025
- _from_rbexpr(_rbexpr.interpolate_by(by))
4649
+ wrap_expr(_rbexpr.interpolate_by(by))
4026
4650
  end
4027
4651
 
4028
4652
  # Apply a rolling min based on another column.
@@ -4123,7 +4747,7 @@ module Polars
4123
4747
  )
4124
4748
  window_size = _prepare_rolling_by_window_args(window_size)
4125
4749
  by = Utils.parse_into_expression(by)
4126
- _from_rbexpr(
4750
+ wrap_expr(
4127
4751
  _rbexpr.rolling_min_by(by, window_size, min_periods, closed)
4128
4752
  )
4129
4753
  end
@@ -4252,7 +4876,7 @@ module Polars
4252
4876
  )
4253
4877
  window_size = _prepare_rolling_by_window_args(window_size)
4254
4878
  by = Utils.parse_into_expression(by)
4255
- _from_rbexpr(
4879
+ wrap_expr(
4256
4880
  _rbexpr.rolling_max_by(by, window_size, min_periods, closed)
4257
4881
  )
4258
4882
  end
@@ -4383,7 +5007,7 @@ module Polars
4383
5007
  )
4384
5008
  window_size = _prepare_rolling_by_window_args(window_size)
4385
5009
  by = Utils.parse_into_expression(by)
4386
- _from_rbexpr(
5010
+ wrap_expr(
4387
5011
  _rbexpr.rolling_mean_by(
4388
5012
  by,
4389
5013
  window_size,
@@ -4517,7 +5141,7 @@ module Polars
4517
5141
  )
4518
5142
  window_size = _prepare_rolling_by_window_args(window_size)
4519
5143
  by = Utils.parse_into_expression(by)
4520
- _from_rbexpr(
5144
+ wrap_expr(
4521
5145
  _rbexpr.rolling_sum_by(by, window_size, min_periods, closed)
4522
5146
  )
4523
5147
  end
@@ -4649,7 +5273,7 @@ module Polars
4649
5273
  )
4650
5274
  window_size = _prepare_rolling_by_window_args(window_size)
4651
5275
  by = Utils.parse_into_expression(by)
4652
- _from_rbexpr(
5276
+ wrap_expr(
4653
5277
  _rbexpr.rolling_std_by(
4654
5278
  by,
4655
5279
  window_size,
@@ -4787,7 +5411,7 @@ module Polars
4787
5411
  )
4788
5412
  window_size = _prepare_rolling_by_window_args(window_size)
4789
5413
  by = Utils.parse_into_expression(by)
4790
- _from_rbexpr(
5414
+ wrap_expr(
4791
5415
  _rbexpr.rolling_var_by(
4792
5416
  by,
4793
5417
  window_size,
@@ -4898,7 +5522,7 @@ module Polars
4898
5522
  )
4899
5523
  window_size = _prepare_rolling_by_window_args(window_size)
4900
5524
  by = Utils.parse_into_expression(by)
4901
- _from_rbexpr(
5525
+ wrap_expr(
4902
5526
  _rbexpr.rolling_median_by(by, window_size, min_periods, closed)
4903
5527
  )
4904
5528
  end
@@ -5009,7 +5633,7 @@ module Polars
5009
5633
  )
5010
5634
  window_size = _prepare_rolling_by_window_args(window_size)
5011
5635
  by = Utils.parse_into_expression(by)
5012
- _from_rbexpr(
5636
+ wrap_expr(
5013
5637
  _rbexpr.rolling_quantile_by(
5014
5638
  by,
5015
5639
  quantile,
@@ -5050,7 +5674,7 @@ module Polars
5050
5674
  # elementwise with the values in the window.
5051
5675
  # @param min_periods [Integer]
5052
5676
  # The number of values in the window that should be non-null before computing
5053
- # a result. If None, it will be set equal to window size.
5677
+ # a result. If nil, it will be set equal to window size.
5054
5678
  # @param center [Boolean]
5055
5679
  # Set the labels at the center of the window
5056
5680
  #
@@ -5092,7 +5716,7 @@ module Polars
5092
5716
  min_periods: nil,
5093
5717
  center: false
5094
5718
  )
5095
- _from_rbexpr(
5719
+ wrap_expr(
5096
5720
  _rbexpr.rolling_min(
5097
5721
  window_size, weights, min_periods, center
5098
5722
  )
@@ -5128,7 +5752,7 @@ module Polars
5128
5752
  # elementwise with the values in the window.
5129
5753
  # @param min_periods [Integer]
5130
5754
  # The number of values in the window that should be non-null before computing
5131
- # a result. If None, it will be set equal to window size.
5755
+ # a result. If nil, it will be set equal to window size.
5132
5756
  # @param center [Boolean]
5133
5757
  # Set the labels at the center of the window
5134
5758
  #
@@ -5170,7 +5794,7 @@ module Polars
5170
5794
  min_periods: nil,
5171
5795
  center: false
5172
5796
  )
5173
- _from_rbexpr(
5797
+ wrap_expr(
5174
5798
  _rbexpr.rolling_max(
5175
5799
  window_size, weights, min_periods, center
5176
5800
  )
@@ -5206,7 +5830,7 @@ module Polars
5206
5830
  # elementwise with the values in the window.
5207
5831
  # @param min_periods [Integer]
5208
5832
  # The number of values in the window that should be non-null before computing
5209
- # a result. If None, it will be set equal to window size.
5833
+ # a result. If nil, it will be set equal to window size.
5210
5834
  # @param center [Boolean]
5211
5835
  # Set the labels at the center of the window
5212
5836
  #
@@ -5248,7 +5872,7 @@ module Polars
5248
5872
  min_periods: nil,
5249
5873
  center: false
5250
5874
  )
5251
- _from_rbexpr(
5875
+ wrap_expr(
5252
5876
  _rbexpr.rolling_mean(
5253
5877
  window_size, weights, min_periods, center
5254
5878
  )
@@ -5284,7 +5908,7 @@ module Polars
5284
5908
  # elementwise with the values in the window.
5285
5909
  # @param min_periods [Integer]
5286
5910
  # The number of values in the window that should be non-null before computing
5287
- # a result. If None, it will be set equal to window size.
5911
+ # a result. If nil, it will be set equal to window size.
5288
5912
  # @param center [Boolean]
5289
5913
  # Set the labels at the center of the window
5290
5914
  #
@@ -5326,7 +5950,7 @@ module Polars
5326
5950
  min_periods: nil,
5327
5951
  center: false
5328
5952
  )
5329
- _from_rbexpr(
5953
+ wrap_expr(
5330
5954
  _rbexpr.rolling_sum(
5331
5955
  window_size, weights, min_periods, center
5332
5956
  )
@@ -5362,7 +5986,7 @@ module Polars
5362
5986
  # elementwise with the values in the window.
5363
5987
  # @param min_periods [Integer]
5364
5988
  # The number of values in the window that should be non-null before computing
5365
- # a result. If None, it will be set equal to window size.
5989
+ # a result. If nil, it will be set equal to window size.
5366
5990
  # @param center [Boolean]
5367
5991
  # Set the labels at the center of the window
5368
5992
  # @param ddof [Integer]
@@ -5407,7 +6031,7 @@ module Polars
5407
6031
  center: false,
5408
6032
  ddof: 1
5409
6033
  )
5410
- _from_rbexpr(
6034
+ wrap_expr(
5411
6035
  _rbexpr.rolling_std(
5412
6036
  window_size, weights, min_periods, center, ddof
5413
6037
  )
@@ -5443,7 +6067,7 @@ module Polars
5443
6067
  # elementwise with the values in the window.
5444
6068
  # @param min_periods [Integer]
5445
6069
  # The number of values in the window that should be non-null before computing
5446
- # a result. If None, it will be set equal to window size.
6070
+ # a result. If nil, it will be set equal to window size.
5447
6071
  # @param center [Boolean]
5448
6072
  # Set the labels at the center of the window
5449
6073
  # @param ddof [Integer]
@@ -5488,7 +6112,7 @@ module Polars
5488
6112
  center: false,
5489
6113
  ddof: 1
5490
6114
  )
5491
- _from_rbexpr(
6115
+ wrap_expr(
5492
6116
  _rbexpr.rolling_var(
5493
6117
  window_size, weights, min_periods, center, ddof
5494
6118
  )
@@ -5520,7 +6144,7 @@ module Polars
5520
6144
  # elementwise with the values in the window.
5521
6145
  # @param min_periods [Integer]
5522
6146
  # The number of values in the window that should be non-null before computing
5523
- # a result. If None, it will be set equal to window size.
6147
+ # a result. If nil, it will be set equal to window size.
5524
6148
  # @param center [Boolean]
5525
6149
  # Set the labels at the center of the window
5526
6150
  #
@@ -5562,7 +6186,7 @@ module Polars
5562
6186
  min_periods: nil,
5563
6187
  center: false
5564
6188
  )
5565
- _from_rbexpr(
6189
+ wrap_expr(
5566
6190
  _rbexpr.rolling_median(
5567
6191
  window_size, weights, min_periods, center
5568
6192
  )
@@ -5598,7 +6222,7 @@ module Polars
5598
6222
  # elementwise with the values in the window.
5599
6223
  # @param min_periods [Integer]
5600
6224
  # The number of values in the window that should be non-null before computing
5601
- # a result. If None, it will be set equal to window size.
6225
+ # a result. If nil, it will be set equal to window size.
5602
6226
  # @param center [Boolean]
5603
6227
  # Set the labels at the center of the window
5604
6228
  #
@@ -5642,7 +6266,7 @@ module Polars
5642
6266
  min_periods: nil,
5643
6267
  center: false
5644
6268
  )
5645
- _from_rbexpr(
6269
+ wrap_expr(
5646
6270
  _rbexpr.rolling_quantile(
5647
6271
  quantile, interpolation, window_size, weights, min_periods, center
5648
6272
  )
@@ -5706,7 +6330,7 @@ module Polars
5706
6330
  # if min_periods.nil?
5707
6331
  # min_periods = window_size
5708
6332
  # end
5709
- # _from_rbexpr(
6333
+ # wrap_expr(
5710
6334
  # _rbexpr.rolling_apply(
5711
6335
  # function, window_size, weights, min_periods, center
5712
6336
  # )
@@ -5743,7 +6367,64 @@ module Polars
5743
6367
  # # │ 0.47033 │
5744
6368
  # # └──────────┘
5745
6369
  def rolling_skew(window_size, bias: true, min_samples: nil, center: false)
5746
- _from_rbexpr(_rbexpr.rolling_skew(window_size, bias, min_samples, center))
6370
+ wrap_expr(_rbexpr.rolling_skew(window_size, bias, min_samples, center))
6371
+ end
6372
+
6373
+ # Compute a rolling kurtosis.
6374
+ #
6375
+ # @note
6376
+ # This functionality is considered **unstable**. It may be changed
6377
+ # at any point without it being considered a breaking change.
6378
+ #
6379
+ # The window at a given row will include the row itself, and the `window_size - 1`
6380
+ # elements before it.
6381
+ #
6382
+ # @param window_size [Integer]
6383
+ # Integer size of the rolling window.
6384
+ # @param fisher [Boolean]
6385
+ # If true, Fisher's definition is used (normal ==> 0.0). If false,
6386
+ # Pearson's definition is used (normal ==> 3.0).
6387
+ # @param bias [Boolean]
6388
+ # If false, the calculations are corrected for statistical bias.
6389
+ # @param min_samples [Integer]
6390
+ # The number of values in the window that should be non-null before computing
6391
+ # a result. If set to `nil` (default), it will be set equal to `window_size`.
6392
+ # @param center
6393
+ # Set the labels at the center of the window.
6394
+ #
6395
+ # @return [Expr]
6396
+ #
6397
+ # @example
6398
+ # df = Polars::DataFrame.new({"a" => [1, 4, 2, 9]})
6399
+ # df.select(Polars.col("a").rolling_kurtosis(3))
6400
+ # # =>
6401
+ # # shape: (4, 1)
6402
+ # # ┌──────┐
6403
+ # # │ a │
6404
+ # # │ --- │
6405
+ # # │ f64 │
6406
+ # # ╞══════╡
6407
+ # # │ null │
6408
+ # # │ null │
6409
+ # # │ -1.5 │
6410
+ # # │ -1.5 │
6411
+ # # └──────┘
6412
+ def rolling_kurtosis(
6413
+ window_size,
6414
+ fisher: true,
6415
+ bias: true,
6416
+ min_samples: nil,
6417
+ center: false
6418
+ )
6419
+ wrap_expr(
6420
+ _rbexpr.rolling_kurtosis(
6421
+ window_size,
6422
+ fisher,
6423
+ bias,
6424
+ min_samples,
6425
+ center
6426
+ )
6427
+ )
5747
6428
  end
5748
6429
 
5749
6430
  # Compute absolute values.
@@ -5770,7 +6451,7 @@ module Polars
5770
6451
  # # │ 2.0 │
5771
6452
  # # └─────┘
5772
6453
  def abs
5773
- _from_rbexpr(_rbexpr.abs)
6454
+ wrap_expr(_rbexpr.abs)
5774
6455
  end
5775
6456
 
5776
6457
  # Get the index values that would sort this column.
@@ -5867,7 +6548,7 @@ module Polars
5867
6548
  # # │ 5 │
5868
6549
  # # └─────┘
5869
6550
  def rank(method: "average", reverse: false, seed: nil)
5870
- _from_rbexpr(_rbexpr.rank(method, reverse, seed))
6551
+ wrap_expr(_rbexpr.rank(method, reverse, seed))
5871
6552
  end
5872
6553
 
5873
6554
  # Calculate the n-th discrete difference.
@@ -5899,7 +6580,7 @@ module Polars
5899
6580
  # # └──────┘
5900
6581
  def diff(n: 1, null_behavior: "ignore")
5901
6582
  n = Utils.parse_into_expression(n)
5902
- _from_rbexpr(_rbexpr.diff(n, null_behavior))
6583
+ wrap_expr(_rbexpr.diff(n, null_behavior))
5903
6584
  end
5904
6585
 
5905
6586
  # Computes percentage change between values.
@@ -5936,7 +6617,7 @@ module Polars
5936
6617
  # # └──────┴────────────┘
5937
6618
  def pct_change(n: 1)
5938
6619
  n = Utils.parse_into_expression(n)
5939
- _from_rbexpr(_rbexpr.pct_change(n))
6620
+ wrap_expr(_rbexpr.pct_change(n))
5940
6621
  end
5941
6622
 
5942
6623
  # Compute the sample skewness of a data set.
@@ -5965,7 +6646,7 @@ module Polars
5965
6646
  # # │ 0.343622 │
5966
6647
  # # └──────────┘
5967
6648
  def skew(bias: true)
5968
- _from_rbexpr(_rbexpr.skew(bias))
6649
+ wrap_expr(_rbexpr.skew(bias))
5969
6650
  end
5970
6651
 
5971
6652
  # Compute the kurtosis (Fisher or Pearson) of a dataset.
@@ -5997,7 +6678,7 @@ module Polars
5997
6678
  # # │ -1.153061 │
5998
6679
  # # └───────────┘
5999
6680
  def kurtosis(fisher: true, bias: true)
6000
- _from_rbexpr(_rbexpr.kurtosis(fisher, bias))
6681
+ wrap_expr(_rbexpr.kurtosis(fisher, bias))
6001
6682
  end
6002
6683
 
6003
6684
  # Set values outside the given boundaries to the boundary value.
@@ -6034,7 +6715,7 @@ module Polars
6034
6715
  if !upper_bound.nil?
6035
6716
  upper_bound = Utils.parse_into_expression(upper_bound)
6036
6717
  end
6037
- _from_rbexpr(_rbexpr.clip(lower_bound, upper_bound))
6718
+ wrap_expr(_rbexpr.clip(lower_bound, upper_bound))
6038
6719
  end
6039
6720
 
6040
6721
  # Clip (limit) the values in an array to a `min` boundary.
@@ -6119,7 +6800,7 @@ module Polars
6119
6800
  # # │ -9223372036854775808 │
6120
6801
  # # └──────────────────────┘
6121
6802
  def lower_bound
6122
- _from_rbexpr(_rbexpr.lower_bound)
6803
+ wrap_expr(_rbexpr.lower_bound)
6123
6804
  end
6124
6805
 
6125
6806
  # Calculate the upper bound.
@@ -6142,7 +6823,7 @@ module Polars
6142
6823
  # # │ 9223372036854775807 │
6143
6824
  # # └─────────────────────┘
6144
6825
  def upper_bound
6145
- _from_rbexpr(_rbexpr.upper_bound)
6826
+ wrap_expr(_rbexpr.upper_bound)
6146
6827
  end
6147
6828
 
6148
6829
  # Compute the element-wise indication of the sign.
@@ -6166,7 +6847,7 @@ module Polars
6166
6847
  # # │ null │
6167
6848
  # # └──────┘
6168
6849
  def sign
6169
- _from_rbexpr(_rbexpr.sign)
6850
+ wrap_expr(_rbexpr.sign)
6170
6851
  end
6171
6852
 
6172
6853
  # Compute the element-wise value for the sine.
@@ -6186,7 +6867,7 @@ module Polars
6186
6867
  # # │ 0.0 │
6187
6868
  # # └─────┘
6188
6869
  def sin
6189
- _from_rbexpr(_rbexpr.sin)
6870
+ wrap_expr(_rbexpr.sin)
6190
6871
  end
6191
6872
 
6192
6873
  # Compute the element-wise value for the cosine.
@@ -6206,7 +6887,7 @@ module Polars
6206
6887
  # # │ 1.0 │
6207
6888
  # # └─────┘
6208
6889
  def cos
6209
- _from_rbexpr(_rbexpr.cos)
6890
+ wrap_expr(_rbexpr.cos)
6210
6891
  end
6211
6892
 
6212
6893
  # Compute the element-wise value for the tangent.
@@ -6226,7 +6907,27 @@ module Polars
6226
6907
  # # │ 1.557408 │
6227
6908
  # # └──────────┘
6228
6909
  def tan
6229
- _from_rbexpr(_rbexpr.tan)
6910
+ wrap_expr(_rbexpr.tan)
6911
+ end
6912
+
6913
+ # Compute the element-wise value for the cotangent.
6914
+ #
6915
+ # @return [Expr]
6916
+ #
6917
+ # @example
6918
+ # df = Polars::DataFrame.new({"a" => [1.0]})
6919
+ # df.select(Polars.col("a").cot.round(2))
6920
+ # # =>
6921
+ # # shape: (1, 1)
6922
+ # # ┌──────┐
6923
+ # # │ a │
6924
+ # # │ --- │
6925
+ # # │ f64 │
6926
+ # # ╞══════╡
6927
+ # # │ 0.64 │
6928
+ # # └──────┘
6929
+ def cot
6930
+ wrap_expr(_rbexpr.cot)
6230
6931
  end
6231
6932
 
6232
6933
  # Compute the element-wise value for the inverse sine.
@@ -6246,7 +6947,7 @@ module Polars
6246
6947
  # # │ 1.570796 │
6247
6948
  # # └──────────┘
6248
6949
  def arcsin
6249
- _from_rbexpr(_rbexpr.arcsin)
6950
+ wrap_expr(_rbexpr.arcsin)
6250
6951
  end
6251
6952
 
6252
6953
  # Compute the element-wise value for the inverse cosine.
@@ -6266,7 +6967,7 @@ module Polars
6266
6967
  # # │ 1.570796 │
6267
6968
  # # └──────────┘
6268
6969
  def arccos
6269
- _from_rbexpr(_rbexpr.arccos)
6970
+ wrap_expr(_rbexpr.arccos)
6270
6971
  end
6271
6972
 
6272
6973
  # Compute the element-wise value for the inverse tangent.
@@ -6286,7 +6987,7 @@ module Polars
6286
6987
  # # │ 0.785398 │
6287
6988
  # # └──────────┘
6288
6989
  def arctan
6289
- _from_rbexpr(_rbexpr.arctan)
6990
+ wrap_expr(_rbexpr.arctan)
6290
6991
  end
6291
6992
 
6292
6993
  # Compute the element-wise value for the hyperbolic sine.
@@ -6306,7 +7007,7 @@ module Polars
6306
7007
  # # │ 1.175201 │
6307
7008
  # # └──────────┘
6308
7009
  def sinh
6309
- _from_rbexpr(_rbexpr.sinh)
7010
+ wrap_expr(_rbexpr.sinh)
6310
7011
  end
6311
7012
 
6312
7013
  # Compute the element-wise value for the hyperbolic cosine.
@@ -6326,7 +7027,7 @@ module Polars
6326
7027
  # # │ 1.543081 │
6327
7028
  # # └──────────┘
6328
7029
  def cosh
6329
- _from_rbexpr(_rbexpr.cosh)
7030
+ wrap_expr(_rbexpr.cosh)
6330
7031
  end
6331
7032
 
6332
7033
  # Compute the element-wise value for the hyperbolic tangent.
@@ -6346,7 +7047,7 @@ module Polars
6346
7047
  # # │ 0.761594 │
6347
7048
  # # └──────────┘
6348
7049
  def tanh
6349
- _from_rbexpr(_rbexpr.tanh)
7050
+ wrap_expr(_rbexpr.tanh)
6350
7051
  end
6351
7052
 
6352
7053
  # Compute the element-wise value for the inverse hyperbolic sine.
@@ -6366,7 +7067,7 @@ module Polars
6366
7067
  # # │ 0.881374 │
6367
7068
  # # └──────────┘
6368
7069
  def arcsinh
6369
- _from_rbexpr(_rbexpr.arcsinh)
7070
+ wrap_expr(_rbexpr.arcsinh)
6370
7071
  end
6371
7072
 
6372
7073
  # Compute the element-wise value for the inverse hyperbolic cosine.
@@ -6386,7 +7087,7 @@ module Polars
6386
7087
  # # │ 0.0 │
6387
7088
  # # └─────┘
6388
7089
  def arccosh
6389
- _from_rbexpr(_rbexpr.arccosh)
7090
+ wrap_expr(_rbexpr.arccosh)
6390
7091
  end
6391
7092
 
6392
7093
  # Compute the element-wise value for the inverse hyperbolic tangent.
@@ -6406,7 +7107,63 @@ module Polars
6406
7107
  # # │ inf │
6407
7108
  # # └─────┘
6408
7109
  def arctanh
6409
- _from_rbexpr(_rbexpr.arctanh)
7110
+ wrap_expr(_rbexpr.arctanh)
7111
+ end
7112
+
7113
+ # Convert from radians to degrees.
7114
+ #
7115
+ # @return [Expr]
7116
+ #
7117
+ # @example
7118
+ # df = Polars::DataFrame.new({"a" => (-4...5).map { |x| x * Math::PI }})
7119
+ # df.select(Polars.col("a").degrees)
7120
+ # # =>
7121
+ # # shape: (9, 1)
7122
+ # # ┌────────┐
7123
+ # # │ a │
7124
+ # # │ --- │
7125
+ # # │ f64 │
7126
+ # # ╞════════╡
7127
+ # # │ -720.0 │
7128
+ # # │ -540.0 │
7129
+ # # │ -360.0 │
7130
+ # # │ -180.0 │
7131
+ # # │ 0.0 │
7132
+ # # │ 180.0 │
7133
+ # # │ 360.0 │
7134
+ # # │ 540.0 │
7135
+ # # │ 720.0 │
7136
+ # # └────────┘
7137
+ def degrees
7138
+ wrap_expr(_rbexpr.degrees)
7139
+ end
7140
+
7141
+ # Convert from degrees to radians.
7142
+ #
7143
+ # @return [Expr]
7144
+ #
7145
+ # @example
7146
+ # df = Polars::DataFrame.new({"a" => [-720, -540, -360, -180, 0, 180, 360, 540, 720]})
7147
+ # df.select(Polars.col("a").radians)
7148
+ # # =>
7149
+ # # shape: (9, 1)
7150
+ # # ┌────────────┐
7151
+ # # │ a │
7152
+ # # │ --- │
7153
+ # # │ f64 │
7154
+ # # ╞════════════╡
7155
+ # # │ -12.566371 │
7156
+ # # │ -9.424778 │
7157
+ # # │ -6.283185 │
7158
+ # # │ -3.141593 │
7159
+ # # │ 0.0 │
7160
+ # # │ 3.141593 │
7161
+ # # │ 6.283185 │
7162
+ # # │ 9.424778 │
7163
+ # # │ 12.566371 │
7164
+ # # └────────────┘
7165
+ def radians
7166
+ wrap_expr(_rbexpr.radians)
6410
7167
  end
6411
7168
 
6412
7169
  # Reshape this Expr to a flat Series or a Series of Lists.
@@ -6452,13 +7209,13 @@ module Polars
6452
7209
  # # │ 9 │
6453
7210
  # # └─────┘
6454
7211
  def reshape(dims)
6455
- _from_rbexpr(_rbexpr.reshape(dims))
7212
+ wrap_expr(_rbexpr.reshape(dims))
6456
7213
  end
6457
7214
 
6458
7215
  # Shuffle the contents of this expr.
6459
7216
  #
6460
7217
  # @param seed [Integer]
6461
- # Seed for the random number generator. If set to None (default), a random
7218
+ # Seed for the random number generator. If set to nil (default), a random
6462
7219
  # seed is generated using the `random` module.
6463
7220
  #
6464
7221
  # @return [Expr]
@@ -6481,7 +7238,7 @@ module Polars
6481
7238
  if seed.nil?
6482
7239
  seed = rand(10000)
6483
7240
  end
6484
- _from_rbexpr(_rbexpr.shuffle(seed))
7241
+ wrap_expr(_rbexpr.shuffle(seed))
6485
7242
  end
6486
7243
 
6487
7244
  # Sample from this expression.
@@ -6493,7 +7250,7 @@ module Polars
6493
7250
  # @param shuffle [Boolean]
6494
7251
  # Shuffle the order of sampled data points.
6495
7252
  # @param seed [Integer]
6496
- # Seed for the random number generator. If set to None (default), a random
7253
+ # Seed for the random number generator. If set to nil (default), a random
6497
7254
  # seed is used.
6498
7255
  # @param n [Integer]
6499
7256
  # Number of items to return. Cannot be used with `frac`.
@@ -6527,14 +7284,14 @@ module Polars
6527
7284
 
6528
7285
  if !n.nil? && frac.nil?
6529
7286
  n = Utils.parse_into_expression(n)
6530
- return _from_rbexpr(_rbexpr.sample_n(n, with_replacement, shuffle, seed))
7287
+ return wrap_expr(_rbexpr.sample_n(n, with_replacement, shuffle, seed))
6531
7288
  end
6532
7289
 
6533
7290
  if frac.nil?
6534
7291
  frac = 1.0
6535
7292
  end
6536
7293
  frac = Utils.parse_into_expression(frac)
6537
- _from_rbexpr(
7294
+ wrap_expr(
6538
7295
  _rbexpr.sample_frac(frac, with_replacement, shuffle, seed)
6539
7296
  )
6540
7297
  end
@@ -6567,7 +7324,76 @@ module Polars
6567
7324
  ignore_nulls: true
6568
7325
  )
6569
7326
  alpha = _prepare_alpha(com, span, half_life, alpha)
6570
- _from_rbexpr(_rbexpr.ewm_mean(alpha, adjust, min_periods, ignore_nulls))
7327
+ wrap_expr(_rbexpr.ewm_mean(alpha, adjust, min_periods, ignore_nulls))
7328
+ end
7329
+
7330
+ # Compute time-based exponentially weighted moving average.
7331
+ #
7332
+ # @param by [Object]
7333
+ # Times to calculate average by. Should be `DateTime`, `Date`, `UInt64`,
7334
+ # `UInt32`, `Int64`, or `Int32` data type.
7335
+ # @param half_life [Object]
7336
+ # Unit over which observation decays to half its value.
7337
+ #
7338
+ # Can be created either from a timedelta, or
7339
+ # by using the following string language:
7340
+ #
7341
+ # - 1ns (1 nanosecond)
7342
+ # - 1us (1 microsecond)
7343
+ # - 1ms (1 millisecond)
7344
+ # - 1s (1 second)
7345
+ # - 1m (1 minute)
7346
+ # - 1h (1 hour)
7347
+ # - 1d (1 day)
7348
+ # - 1w (1 week)
7349
+ # - 1i (1 index count)
7350
+ #
7351
+ # Or combine them:
7352
+ # "3d12h4m25s" # 3 days, 12 hours, 4 minutes, and 25 seconds
7353
+ #
7354
+ # Note that `half_life` is treated as a constant duration - calendar
7355
+ # durations such as months (or even days in the time-zone-aware case)
7356
+ # are not supported, please express your duration in an approximately
7357
+ # equivalent number of hours (e.g. '370h' instead of '1mo').
7358
+ #
7359
+ # @return [Expr]
7360
+ #
7361
+ # @example
7362
+ # df = Polars::DataFrame.new(
7363
+ # {
7364
+ # "values": [0, 1, 2, nil, 4],
7365
+ # "times": [
7366
+ # Date.new(2020, 1, 1),
7367
+ # Date.new(2020, 1, 3),
7368
+ # Date.new(2020, 1, 10),
7369
+ # Date.new(2020, 1, 15),
7370
+ # Date.new(2020, 1, 17)
7371
+ # ]
7372
+ # }
7373
+ # ).sort("times")
7374
+ # df.with_columns(
7375
+ # result: Polars.col("values").ewm_mean_by("times", half_life: "4d")
7376
+ # )
7377
+ # # =>
7378
+ # # shape: (5, 3)
7379
+ # # ┌────────┬────────────┬──────────┐
7380
+ # # │ values ┆ times ┆ result │
7381
+ # # │ --- ┆ --- ┆ --- │
7382
+ # # │ i64 ┆ date ┆ f64 │
7383
+ # # ╞════════╪════════════╪══════════╡
7384
+ # # │ 0 ┆ 2020-01-01 ┆ 0.0 │
7385
+ # # │ 1 ┆ 2020-01-03 ┆ 0.292893 │
7386
+ # # │ 2 ┆ 2020-01-10 ┆ 1.492474 │
7387
+ # # │ null ┆ 2020-01-15 ┆ null │
7388
+ # # │ 4 ┆ 2020-01-17 ┆ 3.254508 │
7389
+ # # └────────┴────────────┴──────────┘
7390
+ def ewm_mean_by(
7391
+ by,
7392
+ half_life:
7393
+ )
7394
+ by = Utils.parse_into_expression(by)
7395
+ half_life = Utils.parse_as_duration_string(half_life)
7396
+ wrap_expr(_rbexpr.ewm_mean_by(by, half_life))
6571
7397
  end
6572
7398
 
6573
7399
  # Exponentially-weighted moving standard deviation.
@@ -6599,7 +7425,7 @@ module Polars
6599
7425
  ignore_nulls: true
6600
7426
  )
6601
7427
  alpha = _prepare_alpha(com, span, half_life, alpha)
6602
- _from_rbexpr(_rbexpr.ewm_std(alpha, adjust, bias, min_periods, ignore_nulls))
7428
+ wrap_expr(_rbexpr.ewm_std(alpha, adjust, bias, min_periods, ignore_nulls))
6603
7429
  end
6604
7430
 
6605
7431
  # Exponentially-weighted moving variance.
@@ -6631,7 +7457,7 @@ module Polars
6631
7457
  ignore_nulls: true
6632
7458
  )
6633
7459
  alpha = _prepare_alpha(com, span, half_life, alpha)
6634
- _from_rbexpr(_rbexpr.ewm_var(alpha, adjust, bias, min_periods, ignore_nulls))
7460
+ wrap_expr(_rbexpr.ewm_var(alpha, adjust, bias, min_periods, ignore_nulls))
6635
7461
  end
6636
7462
 
6637
7463
  # Extend the Series with given number of values.
@@ -6663,7 +7489,7 @@ module Polars
6663
7489
  def extend_constant(value, n)
6664
7490
  value = Utils.parse_into_expression(value, str_as_lit: true)
6665
7491
  n = Utils.parse_into_expression(n)
6666
- _from_rbexpr(_rbexpr.extend_constant(value, n))
7492
+ wrap_expr(_rbexpr.extend_constant(value, n))
6667
7493
  end
6668
7494
 
6669
7495
  # Count all unique values and create a struct mapping value to count.
@@ -6717,7 +7543,7 @@ module Polars
6717
7543
  name = "count"
6718
7544
  end
6719
7545
  end
6720
- _from_rbexpr(
7546
+ wrap_expr(
6721
7547
  _rbexpr.value_counts(sort, parallel, name, normalize)
6722
7548
  )
6723
7549
  end
@@ -6752,7 +7578,7 @@ module Polars
6752
7578
  # # │ 3 │
6753
7579
  # # └─────┘
6754
7580
  def unique_counts
6755
- _from_rbexpr(_rbexpr.unique_counts)
7581
+ wrap_expr(_rbexpr.unique_counts)
6756
7582
  end
6757
7583
 
6758
7584
  # Compute the logarithm to a given base.
@@ -6777,7 +7603,32 @@ module Polars
6777
7603
  # # │ 1.584963 │
6778
7604
  # # └──────────┘
6779
7605
  def log(base = Math::E)
6780
- _from_rbexpr(_rbexpr.log(base))
7606
+ base_rbexpr = Utils.parse_into_expression(base)
7607
+ wrap_expr(_rbexpr.log(base_rbexpr))
7608
+ end
7609
+
7610
+ # Compute the natural logarithm of each element plus one.
7611
+ #
7612
+ # This computes `log(1 + x)` but is more numerically stable for `x` close to zero.
7613
+ #
7614
+ # @return [Expr]
7615
+ #
7616
+ # @example
7617
+ # df = Polars::DataFrame.new({"a" => [1, 2, 3]})
7618
+ # df.select(Polars.col("a").log1p)
7619
+ # # =>
7620
+ # # shape: (3, 1)
7621
+ # # ┌──────────┐
7622
+ # # │ a │
7623
+ # # │ --- │
7624
+ # # │ f64 │
7625
+ # # ╞══════════╡
7626
+ # # │ 0.693147 │
7627
+ # # │ 1.098612 │
7628
+ # # │ 1.386294 │
7629
+ # # └──────────┘
7630
+ def log1p
7631
+ wrap_expr(_rbexpr.log1p)
6781
7632
  end
6782
7633
 
6783
7634
  # Computes the entropy.
@@ -6816,7 +7667,7 @@ module Polars
6816
7667
  # # │ -6.754888 │
6817
7668
  # # └───────────┘
6818
7669
  def entropy(base: 2, normalize: true)
6819
- _from_rbexpr(_rbexpr.entropy(base, normalize))
7670
+ wrap_expr(_rbexpr.entropy(base, normalize))
6820
7671
  end
6821
7672
 
6822
7673
  # Run an expression over a sliding window that increases `1` slot every iteration.
@@ -6860,7 +7711,7 @@ module Polars
6860
7711
  # # │ -24 │
6861
7712
  # # └────────┘
6862
7713
  def cumulative_eval(expr, min_periods: 1)
6863
- _from_rbexpr(
7714
+ wrap_expr(
6864
7715
  _rbexpr.cumulative_eval(expr._rbexpr, min_periods)
6865
7716
  )
6866
7717
  end
@@ -6891,7 +7742,7 @@ module Polars
6891
7742
  # # │ 3 │
6892
7743
  # # └────────┘
6893
7744
  def set_sorted(descending: false)
6894
- _from_rbexpr(_rbexpr.set_sorted_flag(descending))
7745
+ wrap_expr(_rbexpr.set_sorted_flag(descending))
6895
7746
  end
6896
7747
 
6897
7748
  # Aggregate to list.
@@ -6916,7 +7767,7 @@ module Polars
6916
7767
  # # │ [1, 2, 3] ┆ [4, 5, 6] │
6917
7768
  # # └───────────┴───────────┘
6918
7769
  def implode
6919
- _from_rbexpr(_rbexpr.implode)
7770
+ wrap_expr(_rbexpr.implode)
6920
7771
  end
6921
7772
 
6922
7773
  # Shrink numeric columns to the minimal required datatype.
@@ -6925,33 +7776,74 @@ module Polars
6925
7776
  # This can be used to reduce memory pressure.
6926
7777
  #
6927
7778
  # @return [Expr]
7779
+ def shrink_dtype
7780
+ warn "`Expr.shrink_dtype` is deprecated and is a no-op; use `Series.shrink_dtype` instead."
7781
+ self
7782
+ end
7783
+
7784
+ # Bin values into buckets and count their occurrences.
7785
+ #
7786
+ # @note
7787
+ # This functionality is considered **unstable**. It may be changed
7788
+ # at any point without it being considered a breaking change.
7789
+ #
7790
+ # @param bins [Object]
7791
+ # Bin edges. If nil given, we determine the edges based on the data.
7792
+ # @param bin_count [Integer]
7793
+ # If `bins` is not provided, `bin_count` uniform bins are created that fully
7794
+ # encompass the data.
7795
+ # @param include_category [Boolean]
7796
+ # Include a column that shows the intervals as categories.
7797
+ # @param include_breakpoint [Boolean]
7798
+ # Include a column that indicates the upper breakpoint.
7799
+ #
7800
+ # @return [Expr]
6928
7801
  #
6929
7802
  # @example
6930
- # Polars::DataFrame.new(
6931
- # {
6932
- # "a" => [1, 2, 3],
6933
- # "b" => [1, 2, 2 << 32],
6934
- # "c" => [-1, 2, 1 << 30],
6935
- # "d" => [-112, 2, 112],
6936
- # "e" => [-112, 2, 129],
6937
- # "f" => ["a", "b", "c"],
6938
- # "g" => [0.1, 1.32, 0.12],
6939
- # "h" => [true, nil, false]
6940
- # }
6941
- # ).select(Polars.all.shrink_dtype)
6942
- # # =>
6943
- # # shape: (3, 8)
6944
- # # ┌─────┬────────────┬────────────┬──────┬──────┬─────┬──────┬───────┐
6945
- # # │ a ┆ b ┆ c ┆ d ┆ e ┆ f ┆ g ┆ h │
6946
- # # --- --- ┆ --- ┆ --- ┆ --- ┆ --- ┆ --- ┆ --- │
6947
- # # │ i8 ┆ i64 ┆ i32 ┆ i8 ┆ i16 ┆ str ┆ f32 ┆ bool │
6948
- # # ╞═════╪════════════╪════════════╪══════╪══════╪═════╪══════╪═══════╡
6949
- # # │ 1 ┆ 1 ┆ -1 ┆ -112 ┆ -112 ┆ a ┆ 0.1 ┆ true │
6950
- # # 2 2 ┆ 2 ┆ 2 ┆ 2 ┆ b ┆ 1.32 ┆ null │
6951
- # # │ 3 ┆ 8589934592 ┆ 1073741824 ┆ 112 ┆ 129 ┆ c ┆ 0.12 ┆ false │
6952
- # # └─────┴────────────┴────────────┴──────┴──────┴─────┴──────┴───────┘
6953
- def shrink_dtype
6954
- _from_rbexpr(_rbexpr.shrink_dtype)
7803
+ # df = Polars::DataFrame.new({"a" => [1, 3, 8, 8, 2, 1, 3]})
7804
+ # df.select(Polars.col("a").hist(bins: [1, 2, 3]))
7805
+ # # =>
7806
+ # # shape: (2, 1)
7807
+ # # ┌─────┐
7808
+ # # a │
7809
+ # # ---
7810
+ # # u32
7811
+ # # ╞═════╡
7812
+ # # 3 │
7813
+ # # │ 2 │
7814
+ # # └─────┘
7815
+ #
7816
+ # @example
7817
+ # df.select(
7818
+ # Polars.col("a").hist(
7819
+ # bins: [1, 2, 3], include_breakpoint: true, include_category: true
7820
+ # )
7821
+ # )
7822
+ # # =>
7823
+ # # shape: (2, 1)
7824
+ # # ┌──────────────────────┐
7825
+ # # │ a │
7826
+ # # │ --- │
7827
+ # # │ struct[3] │
7828
+ # # ╞══════════════════════╡
7829
+ # # │ {2.0,"[1.0, 2.0]",3} │
7830
+ # # │ {3.0,"(2.0, 3.0]",2} │
7831
+ # # └──────────────────────┘
7832
+ def hist(
7833
+ bins: nil,
7834
+ bin_count: nil,
7835
+ include_category: false,
7836
+ include_breakpoint: false
7837
+ )
7838
+ if !bins.nil?
7839
+ if bins.is_a?(::Array)
7840
+ bins = Polars::Series.new(bins)
7841
+ end
7842
+ bins = Utils.parse_into_expression(bins)
7843
+ end
7844
+ wrap_expr(
7845
+ _rbexpr.hist(bins, bin_count, include_category, include_breakpoint)
7846
+ )
6955
7847
  end
6956
7848
 
6957
7849
  # Replace values by different values.
@@ -7110,7 +8002,7 @@ module Polars
7110
8002
  old = Utils.parse_into_expression(old, str_as_lit: true)
7111
8003
  new = Utils.parse_into_expression(new, str_as_lit: true)
7112
8004
 
7113
- result = _from_rbexpr(_rbexpr.replace(old, new))
8005
+ result = wrap_expr(_rbexpr.replace(old, new))
7114
8006
 
7115
8007
  if !return_dtype.nil?
7116
8008
  result = result.cast(return_dtype)
@@ -7262,11 +8154,161 @@ module Polars
7262
8154
 
7263
8155
  default = default.eql?(NO_DEFAULT) ? nil : Utils.parse_into_expression(default, str_as_lit: true)
7264
8156
 
7265
- _from_rbexpr(
8157
+ wrap_expr(
7266
8158
  _rbexpr.replace_strict(old, new, default, return_dtype)
7267
8159
  )
7268
8160
  end
7269
8161
 
8162
+ # Evaluate the number of set bits.
8163
+ #
8164
+ # @return [Expr]
8165
+ def bitwise_count_ones
8166
+ wrap_expr(_rbexpr.bitwise_count_ones)
8167
+ end
8168
+
8169
+ # Evaluate the number of unset bits.
8170
+ #
8171
+ # @return [Expr]
8172
+ def bitwise_count_zeros
8173
+ wrap_expr(_rbexpr.bitwise_count_zeros)
8174
+ end
8175
+
8176
+ # Evaluate the number most-significant set bits before seeing an unset bit.
8177
+ #
8178
+ # @return [Expr]
8179
+ def bitwise_leading_ones
8180
+ wrap_expr(_rbexpr.bitwise_leading_ones)
8181
+ end
8182
+
8183
+ # Evaluate the number most-significant unset bits before seeing a set bit.
8184
+ #
8185
+ # @return [Expr]
8186
+ def bitwise_leading_zeros
8187
+ wrap_expr(_rbexpr.bitwise_leading_zeros)
8188
+ end
8189
+
8190
+ # Evaluate the number least-significant set bits before seeing an unset bit.
8191
+ #
8192
+ # @return [Expr]
8193
+ def bitwise_trailing_ones
8194
+ wrap_expr(_rbexpr.bitwise_trailing_ones)
8195
+ end
8196
+
8197
+ # Evaluate the number least-significant unset bits before seeing a set bit.
8198
+ #
8199
+ # @return [Expr]
8200
+ def bitwise_trailing_zeros
8201
+ wrap_expr(_rbexpr.bitwise_trailing_zeros)
8202
+ end
8203
+
8204
+ # Perform an aggregation of bitwise ANDs.
8205
+ #
8206
+ # @return [Expr]
8207
+ #
8208
+ # @example
8209
+ # df = Polars::DataFrame.new({"n" => [-1, 0, 1]})
8210
+ # df.select(Polars.col("n").bitwise_and)
8211
+ # # =>
8212
+ # # shape: (1, 1)
8213
+ # # ┌─────┐
8214
+ # # │ n │
8215
+ # # │ --- │
8216
+ # # │ i64 │
8217
+ # # ╞═════╡
8218
+ # # │ 0 │
8219
+ # # └─────┘
8220
+ #
8221
+ # @example
8222
+ # df = Polars::DataFrame.new(
8223
+ # {"grouper" => ["a", "a", "a", "b", "b"], "n" => [-1, 0, 1, -1, 1]}
8224
+ # )
8225
+ # df.group_by("grouper", maintain_order: true).agg(Polars.col("n").bitwise_and)
8226
+ # # =>
8227
+ # # shape: (2, 2)
8228
+ # # ┌─────────┬─────┐
8229
+ # # │ grouper ┆ n │
8230
+ # # │ --- ┆ --- │
8231
+ # # │ str ┆ i64 │
8232
+ # # ╞═════════╪═════╡
8233
+ # # │ a ┆ 0 │
8234
+ # # │ b ┆ 1 │
8235
+ # # └─────────┴─────┘
8236
+ def bitwise_and
8237
+ wrap_expr(_rbexpr.bitwise_and)
8238
+ end
8239
+
8240
+ # Perform an aggregation of bitwise ORs.
8241
+ #
8242
+ # @return [Expr]
8243
+ #
8244
+ # @example
8245
+ # df = Polars::DataFrame.new({"n" => [-1, 0, 1]})
8246
+ # df.select(Polars.col("n").bitwise_or)
8247
+ # # =>
8248
+ # # shape: (1, 1)
8249
+ # # ┌─────┐
8250
+ # # │ n │
8251
+ # # │ --- │
8252
+ # # │ i64 │
8253
+ # # ╞═════╡
8254
+ # # │ -1 │
8255
+ # # └─────┘
8256
+ #
8257
+ # @example
8258
+ # df = Polars::DataFrame.new(
8259
+ # {"grouper" => ["a", "a", "a", "b", "b"], "n" => [-1, 0, 1, -1, 1]}
8260
+ # )
8261
+ # df.group_by("grouper", maintain_order: true).agg(Polars.col("n").bitwise_or)
8262
+ # # =>
8263
+ # # shape: (2, 2)
8264
+ # # ┌─────────┬─────┐
8265
+ # # │ grouper ┆ n │
8266
+ # # │ --- ┆ --- │
8267
+ # # │ str ┆ i64 │
8268
+ # # ╞═════════╪═════╡
8269
+ # # │ a ┆ -1 │
8270
+ # # │ b ┆ -1 │
8271
+ # # └─────────┴─────┘
8272
+ def bitwise_or
8273
+ wrap_expr(_rbexpr.bitwise_or)
8274
+ end
8275
+
8276
+ # Perform an aggregation of bitwise XORs.
8277
+ #
8278
+ # @return [Expr]
8279
+ #
8280
+ # @example
8281
+ # df = Polars::DataFrame.new({"n" => [-1, 0, 1]})
8282
+ # df.select(Polars.col("n").bitwise_xor)
8283
+ # # =>
8284
+ # # shape: (1, 1)
8285
+ # # ┌─────┐
8286
+ # # │ n │
8287
+ # # │ --- │
8288
+ # # │ i64 │
8289
+ # # ╞═════╡
8290
+ # # │ -2 │
8291
+ # # └─────┘
8292
+ #
8293
+ # @example
8294
+ # df = Polars::DataFrame.new(
8295
+ # {"grouper" => ["a", "a", "a", "b", "b"], "n" => [-1, 0, 1, -1, 1]}
8296
+ # )
8297
+ # df.group_by("grouper", maintain_order: true).agg(Polars.col("n").bitwise_xor)
8298
+ # # =>
8299
+ # # shape: (2, 2)
8300
+ # # ┌─────────┬─────┐
8301
+ # # │ grouper ┆ n │
8302
+ # # │ --- ┆ --- │
8303
+ # # │ str ┆ i64 │
8304
+ # # ╞═════════╪═════╡
8305
+ # # │ a ┆ -2 │
8306
+ # # │ b ┆ -2 │
8307
+ # # └─────────┴─────┘
8308
+ def bitwise_xor
8309
+ wrap_expr(_rbexpr.bitwise_xor)
8310
+ end
8311
+
7270
8312
  # Create an object namespace of all list related methods.
7271
8313
  #
7272
8314
  # @return [ListExpr]
@@ -7332,7 +8374,7 @@ module Polars
7332
8374
 
7333
8375
  private
7334
8376
 
7335
- def _from_rbexpr(expr)
8377
+ def wrap_expr(expr)
7336
8378
  Utils.wrap_expr(expr)
7337
8379
  end
7338
8380