polars-df 0.15.0 → 0.26.0
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +274 -0
- data/Cargo.lock +1465 -867
- data/Cargo.toml +3 -0
- data/LICENSE.txt +2 -2
- data/README.md +87 -37
- data/ext/polars/Cargo.toml +47 -16
- data/ext/polars/src/c_api/allocator.rs +7 -0
- data/ext/polars/src/c_api/mod.rs +1 -0
- data/ext/polars/src/catalog/mod.rs +1 -0
- data/ext/polars/src/catalog/unity.rs +470 -0
- data/ext/polars/src/conversion/any_value.rs +99 -84
- data/ext/polars/src/conversion/categorical.rs +30 -0
- data/ext/polars/src/conversion/chunked_array.rs +71 -62
- data/ext/polars/src/conversion/datetime.rs +63 -0
- data/ext/polars/src/conversion/mod.rs +796 -312
- data/ext/polars/src/dataframe/construction.rs +6 -18
- data/ext/polars/src/dataframe/export.rs +30 -39
- data/ext/polars/src/dataframe/general.rs +294 -362
- data/ext/polars/src/dataframe/io.rs +33 -150
- data/ext/polars/src/dataframe/map.rs +175 -0
- data/ext/polars/src/dataframe/mod.rs +37 -5
- data/ext/polars/src/dataframe/serde.rs +23 -8
- data/ext/polars/src/error.rs +44 -7
- data/ext/polars/src/exceptions.rs +21 -8
- data/ext/polars/src/expr/array.rs +86 -22
- data/ext/polars/src/expr/binary.rs +50 -1
- data/ext/polars/src/expr/bitwise.rs +39 -0
- data/ext/polars/src/expr/categorical.rs +20 -0
- data/ext/polars/src/expr/datatype.rs +51 -0
- data/ext/polars/src/expr/datetime.rs +99 -41
- data/ext/polars/src/expr/extension.rs +12 -0
- data/ext/polars/src/expr/general.rs +252 -128
- data/ext/polars/src/expr/list.rs +56 -60
- data/ext/polars/src/expr/meta.rs +30 -35
- data/ext/polars/src/expr/mod.rs +28 -6
- data/ext/polars/src/expr/name.rs +29 -14
- data/ext/polars/src/expr/rolling.rs +111 -3
- data/ext/polars/src/expr/selector.rs +219 -0
- data/ext/polars/src/expr/serde.rs +28 -0
- data/ext/polars/src/expr/string.rs +118 -20
- data/ext/polars/src/expr/struct.rs +14 -1
- data/ext/polars/src/file.rs +194 -86
- data/ext/polars/src/functions/aggregation.rs +13 -12
- data/ext/polars/src/functions/business.rs +2 -3
- data/ext/polars/src/functions/eager.rs +3 -2
- data/ext/polars/src/functions/io.rs +90 -18
- data/ext/polars/src/functions/lazy.rs +267 -118
- data/ext/polars/src/functions/meta.rs +8 -7
- data/ext/polars/src/functions/misc.rs +1 -1
- data/ext/polars/src/functions/mod.rs +2 -1
- data/ext/polars/src/functions/range.rs +88 -31
- data/ext/polars/src/functions/strings.rs +6 -0
- data/ext/polars/src/functions/utils.rs +8 -0
- data/ext/polars/src/interop/arrow/mod.rs +52 -1
- data/ext/polars/src/interop/arrow/{to_ruby.rs → to_rb.rs} +37 -7
- data/ext/polars/src/interop/arrow/to_rust.rs +43 -0
- data/ext/polars/src/interop/numo/to_numo_df.rs +1 -1
- data/ext/polars/src/interop/numo/to_numo_series.rs +72 -50
- data/ext/polars/src/io/cloud_options.rs +107 -0
- data/ext/polars/src/io/mod.rs +4 -0
- data/ext/polars/src/io/scan_options.rs +113 -0
- data/ext/polars/src/io/sink_options.rs +46 -0
- data/ext/polars/src/io/sink_output.rs +21 -0
- data/ext/polars/src/lazyframe/exitable.rs +39 -0
- data/ext/polars/src/lazyframe/general.rs +846 -368
- data/ext/polars/src/lazyframe/mod.rs +58 -5
- data/ext/polars/src/lazyframe/optflags.rs +59 -0
- data/ext/polars/src/lazyframe/serde.rs +36 -4
- data/ext/polars/src/lazyframe/sink.rs +46 -0
- data/ext/polars/src/lazygroupby.rs +38 -9
- data/ext/polars/src/lib.rs +574 -165
- data/ext/polars/src/map/lazy.rs +44 -74
- data/ext/polars/src/map/mod.rs +18 -254
- data/ext/polars/src/map/series.rs +241 -1087
- data/ext/polars/src/on_startup.rs +192 -9
- data/ext/polars/src/prelude.rs +1 -0
- data/ext/polars/src/rb_modules.rs +10 -57
- data/ext/polars/src/ruby/exceptions.rs +26 -0
- data/ext/polars/src/ruby/gvl.rs +104 -0
- data/ext/polars/src/ruby/lazy.rs +46 -0
- data/ext/polars/src/ruby/mod.rs +11 -0
- data/ext/polars/src/ruby/numo.rs +52 -0
- data/ext/polars/src/ruby/plan_callback.rs +198 -0
- data/ext/polars/src/ruby/rb_modules.rs +16 -0
- data/ext/polars/src/ruby/ruby_convert_registry.rs +51 -0
- data/ext/polars/src/ruby/ruby_function.rs +11 -0
- data/ext/polars/src/ruby/ruby_udf.rs +164 -0
- data/ext/polars/src/ruby/thread.rs +65 -0
- data/ext/polars/src/ruby/utils.rs +39 -0
- data/ext/polars/src/series/aggregation.rs +116 -91
- data/ext/polars/src/series/arithmetic.rs +16 -22
- data/ext/polars/src/series/comparison.rs +101 -222
- data/ext/polars/src/series/construction.rs +80 -70
- data/ext/polars/src/series/export.rs +98 -56
- data/ext/polars/src/series/general.rs +323 -440
- data/ext/polars/src/series/import.rs +22 -5
- data/ext/polars/src/series/map.rs +103 -0
- data/ext/polars/src/series/mod.rs +57 -15
- data/ext/polars/src/series/scatter.rs +139 -82
- data/ext/polars/src/sql.rs +16 -9
- data/ext/polars/src/testing/frame.rs +31 -0
- data/ext/polars/src/testing/mod.rs +5 -0
- data/ext/polars/src/testing/series.rs +31 -0
- data/ext/polars/src/timeout.rs +105 -0
- data/ext/polars/src/utils.rs +105 -4
- data/lib/polars/array_expr.rb +500 -22
- data/lib/polars/array_name_space.rb +384 -10
- data/lib/polars/batched_csv_reader.rb +48 -66
- data/lib/polars/binary_expr.rb +217 -0
- data/lib/polars/binary_name_space.rb +155 -1
- data/lib/polars/cat_expr.rb +224 -0
- data/lib/polars/cat_name_space.rb +132 -32
- data/lib/polars/catalog/unity/catalog_info.rb +20 -0
- data/lib/polars/catalog/unity/column_info.rb +31 -0
- data/lib/polars/catalog/unity/namespace_info.rb +21 -0
- data/lib/polars/catalog/unity/table_info.rb +50 -0
- data/lib/polars/catalog.rb +448 -0
- data/lib/polars/collect_batches.rb +22 -0
- data/lib/polars/config.rb +3 -3
- data/lib/polars/convert.rb +201 -36
- data/lib/polars/data_frame.rb +2851 -1017
- data/lib/polars/data_frame_plot.rb +173 -0
- data/lib/polars/data_type_expr.rb +52 -0
- data/lib/polars/data_type_group.rb +6 -0
- data/lib/polars/data_types.rb +118 -18
- data/lib/polars/date_time_expr.rb +426 -84
- data/lib/polars/date_time_name_space.rb +384 -111
- data/lib/polars/dynamic_group_by.rb +102 -10
- data/lib/polars/exceptions.rb +50 -5
- data/lib/polars/expr.rb +2159 -915
- data/lib/polars/extension_expr.rb +39 -0
- data/lib/polars/extension_name_space.rb +39 -0
- data/lib/polars/functions/aggregation/horizontal.rb +11 -6
- data/lib/polars/functions/aggregation/vertical.rb +2 -3
- data/lib/polars/functions/as_datatype.rb +290 -8
- data/lib/polars/functions/business.rb +95 -0
- data/lib/polars/functions/col.rb +6 -5
- data/lib/polars/functions/datatype.rb +62 -0
- data/lib/polars/functions/eager.rb +426 -24
- data/lib/polars/functions/escape_regex.rb +21 -0
- data/lib/polars/functions/lazy.rb +813 -195
- data/lib/polars/functions/lit.rb +21 -10
- data/lib/polars/functions/range/int_range.rb +74 -2
- data/lib/polars/functions/range/linear_space.rb +195 -0
- data/lib/polars/functions/range/time_range.rb +1 -1
- data/lib/polars/functions/repeat.rb +7 -12
- data/lib/polars/functions/whenthen.rb +2 -2
- data/lib/polars/group_by.rb +188 -58
- data/lib/polars/iceberg_dataset.rb +108 -0
- data/lib/polars/in_process_query.rb +37 -0
- data/lib/polars/io/cloud.rb +18 -0
- data/lib/polars/io/csv.rb +336 -128
- data/lib/polars/io/database.rb +19 -4
- data/lib/polars/io/delta.rb +134 -0
- data/lib/polars/io/iceberg.rb +34 -0
- data/lib/polars/io/ipc.rb +63 -63
- data/lib/polars/io/json.rb +16 -0
- data/lib/polars/io/lines.rb +172 -0
- data/lib/polars/io/ndjson.rb +176 -20
- data/lib/polars/io/parquet.rb +173 -95
- data/lib/polars/io/scan_options.rb +55 -0
- data/lib/polars/io/sink_options.rb +27 -0
- data/lib/polars/io/utils.rb +17 -0
- data/lib/polars/lazy_frame.rb +3017 -622
- data/lib/polars/lazy_group_by.rb +436 -2
- data/lib/polars/list_expr.rb +551 -59
- data/lib/polars/list_name_space.rb +465 -51
- data/lib/polars/meta_expr.rb +146 -24
- data/lib/polars/name_expr.rb +87 -2
- data/lib/polars/query_opt_flags.rb +264 -0
- data/lib/polars/rolling_group_by.rb +90 -5
- data/lib/polars/scan_cast_options.rb +86 -0
- data/lib/polars/schema.rb +128 -0
- data/lib/polars/selector.rb +245 -0
- data/lib/polars/selectors.rb +1048 -201
- data/lib/polars/series.rb +2522 -774
- data/lib/polars/series_plot.rb +72 -0
- data/lib/polars/slice.rb +1 -1
- data/lib/polars/sql_context.rb +13 -6
- data/lib/polars/string_cache.rb +19 -72
- data/lib/polars/string_expr.rb +561 -107
- data/lib/polars/string_name_space.rb +781 -109
- data/lib/polars/struct_expr.rb +139 -18
- data/lib/polars/struct_name_space.rb +19 -1
- data/lib/polars/testing.rb +24 -273
- data/lib/polars/utils/constants.rb +2 -0
- data/lib/polars/utils/construction/data_frame.rb +410 -0
- data/lib/polars/utils/construction/series.rb +350 -0
- data/lib/polars/utils/construction/utils.rb +9 -0
- data/lib/polars/utils/convert.rb +18 -8
- data/lib/polars/utils/deprecation.rb +11 -0
- data/lib/polars/utils/parse.rb +62 -9
- data/lib/polars/utils/reduce_balanced.rb +43 -0
- data/lib/polars/utils/serde.rb +22 -0
- data/lib/polars/utils/unstable.rb +19 -0
- data/lib/polars/utils/various.rb +86 -1
- data/lib/polars/utils.rb +63 -48
- data/lib/polars/version.rb +1 -1
- data/lib/polars.rb +85 -2
- metadata +80 -28
- data/ext/polars/src/allocator.rs +0 -13
- data/ext/polars/src/batched_csv.rs +0 -138
- data/ext/polars/src/functions/string_cache.rs +0 -25
- data/ext/polars/src/map/dataframe.rs +0 -338
- data/lib/polars/plot.rb +0 -109
data/lib/polars/meta_expr.rb
CHANGED
|
@@ -97,6 +97,70 @@ module Polars
|
|
|
97
97
|
_rbexpr.meta_is_regex_projection
|
|
98
98
|
end
|
|
99
99
|
|
|
100
|
+
# Indicate if this expression only selects columns (optionally with aliasing).
|
|
101
|
+
#
|
|
102
|
+
# This can include bare columns, columns matched by regex or dtype, selectors
|
|
103
|
+
# and exclude ops, and (optionally) column/expression aliasing.
|
|
104
|
+
#
|
|
105
|
+
# @param allow_aliasing [Boolean]
|
|
106
|
+
# If false (default), any aliasing is not considered to be column selection.
|
|
107
|
+
# Set true to allow for column selection that also includes aliasing.
|
|
108
|
+
#
|
|
109
|
+
# @return [Boolean]
|
|
110
|
+
#
|
|
111
|
+
# @example
|
|
112
|
+
# e = Polars.col("foo")
|
|
113
|
+
# e.meta.is_column_selection
|
|
114
|
+
# # => true
|
|
115
|
+
#
|
|
116
|
+
# @example
|
|
117
|
+
# e = Polars.col("foo").alias("bar")
|
|
118
|
+
# e.meta.is_column_selection
|
|
119
|
+
# # => false
|
|
120
|
+
#
|
|
121
|
+
# @example
|
|
122
|
+
# e.meta.is_column_selection(allow_aliasing: true)
|
|
123
|
+
# # => true
|
|
124
|
+
#
|
|
125
|
+
# @example
|
|
126
|
+
# e = Polars.col("foo") * Polars.col("bar")
|
|
127
|
+
# e.meta.is_column_selection
|
|
128
|
+
# # => false
|
|
129
|
+
#
|
|
130
|
+
# @example
|
|
131
|
+
# e = Polars.cs.starts_with("foo")
|
|
132
|
+
# e.meta.is_column_selection
|
|
133
|
+
# # => true
|
|
134
|
+
#
|
|
135
|
+
# @example
|
|
136
|
+
# e = Polars.cs.starts_with("foo").exclude("foo!")
|
|
137
|
+
# e.meta.is_column_selection
|
|
138
|
+
# # => true
|
|
139
|
+
def is_column_selection(allow_aliasing: false)
|
|
140
|
+
_rbexpr.meta_is_column_selection(allow_aliasing)
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
# Indicate if this expression is a literal value (optionally aliased).
|
|
144
|
+
#
|
|
145
|
+
# @param allow_aliasing [Boolean]
|
|
146
|
+
# If false (default), only a bare literal will match.
|
|
147
|
+
# Set true to also allow for aliased literals.
|
|
148
|
+
#
|
|
149
|
+
# @return [Boolean]
|
|
150
|
+
#
|
|
151
|
+
# @example
|
|
152
|
+
# e = Polars.lit(123)
|
|
153
|
+
# e.meta.is_literal
|
|
154
|
+
# # => true
|
|
155
|
+
#
|
|
156
|
+
# @example
|
|
157
|
+
# e = Polars.lit(987.654321).alias("foo")
|
|
158
|
+
# e.meta.is_literal
|
|
159
|
+
# # => false
|
|
160
|
+
def is_literal(allow_aliasing: false)
|
|
161
|
+
_rbexpr.meta_is_literal(allow_aliasing)
|
|
162
|
+
end
|
|
163
|
+
|
|
100
164
|
# Get the column name that this expression would produce.
|
|
101
165
|
#
|
|
102
166
|
# @return [String]
|
|
@@ -116,8 +180,13 @@ module Polars
|
|
|
116
180
|
# # => "foo"
|
|
117
181
|
# Polars.len.meta.output_name
|
|
118
182
|
# # => "len"
|
|
119
|
-
def output_name
|
|
183
|
+
def output_name(raise_if_undetermined: true)
|
|
120
184
|
_rbexpr.meta_output_name
|
|
185
|
+
rescue Polars::ComputeError
|
|
186
|
+
if !raise_if_undetermined
|
|
187
|
+
return nil
|
|
188
|
+
end
|
|
189
|
+
raise
|
|
121
190
|
end
|
|
122
191
|
|
|
123
192
|
# Pop the latest expression and return the input(s) of the popped expression.
|
|
@@ -125,14 +194,14 @@ module Polars
|
|
|
125
194
|
# @return [Array]
|
|
126
195
|
#
|
|
127
196
|
# @example
|
|
128
|
-
# e = Polars.col("foo").
|
|
197
|
+
# e = Polars.col("foo") + Polars.col("bar")
|
|
129
198
|
# first = e.meta.pop[0]
|
|
130
|
-
# _ = first.meta == Polars.col("foo")
|
|
131
|
-
# # => true
|
|
132
199
|
# _ = first.meta == Polars.col("bar")
|
|
200
|
+
# # => true
|
|
201
|
+
# _ = first.meta == Polars.col("foo")
|
|
133
202
|
# # => false
|
|
134
|
-
def pop
|
|
135
|
-
_rbexpr.meta_pop.map { |e| Utils.wrap_expr(e) }
|
|
203
|
+
def pop(schema: nil)
|
|
204
|
+
_rbexpr.meta_pop(schema).map { |e| Utils.wrap_expr(e) }
|
|
136
205
|
end
|
|
137
206
|
|
|
138
207
|
# Get a list with the root column name.
|
|
@@ -171,32 +240,49 @@ module Polars
|
|
|
171
240
|
Utils.wrap_expr(_rbexpr.meta_undo_aliases)
|
|
172
241
|
end
|
|
173
242
|
|
|
174
|
-
#
|
|
243
|
+
# Return the original expression.
|
|
175
244
|
#
|
|
176
245
|
# @return [Expr]
|
|
177
|
-
def
|
|
178
|
-
Utils.wrap_expr(_rbexpr
|
|
246
|
+
def as_expression
|
|
247
|
+
Utils.wrap_expr(_rbexpr)
|
|
179
248
|
end
|
|
180
249
|
|
|
181
|
-
#
|
|
250
|
+
# Try to turn this expression in a selector.
|
|
182
251
|
#
|
|
183
|
-
#
|
|
184
|
-
def _selector_add(other)
|
|
185
|
-
Utils.wrap_expr(_rbexpr._meta_selector_add(other._rbexpr))
|
|
186
|
-
end
|
|
187
|
-
|
|
188
|
-
# Subtract selectors.
|
|
252
|
+
# Raises if the underlying expressions is not a column or selector.
|
|
189
253
|
#
|
|
190
254
|
# @return [Expr]
|
|
191
|
-
|
|
192
|
-
|
|
255
|
+
#
|
|
256
|
+
# @note
|
|
257
|
+
# This functionality is considered **unstable**. It may be changed
|
|
258
|
+
# at any point without it being considered a breaking change.
|
|
259
|
+
def as_selector
|
|
260
|
+
Selector._from_rbselector(_rbexpr.into_selector)
|
|
193
261
|
end
|
|
194
262
|
|
|
195
|
-
#
|
|
263
|
+
# Serialize this expression to a file or string.
|
|
196
264
|
#
|
|
197
|
-
# @
|
|
198
|
-
|
|
199
|
-
|
|
265
|
+
# @param file [Object]
|
|
266
|
+
# File path to which the result should be written. If set to `nil`
|
|
267
|
+
# (default), the output is returned as a string instead.
|
|
268
|
+
#
|
|
269
|
+
# @return [Object]
|
|
270
|
+
#
|
|
271
|
+
# @note
|
|
272
|
+
# Serialization is not stable across Polars versions: a LazyFrame serialized
|
|
273
|
+
# in one Polars version may not be deserializable in another Polars version.
|
|
274
|
+
#
|
|
275
|
+
# @example Serialize the expression into a binary representation.
|
|
276
|
+
# expr = Polars.col("foo").sum.over("bar")
|
|
277
|
+
# bytes = expr.meta.serialize
|
|
278
|
+
# Polars::Expr.deserialize(StringIO.new(bytes))
|
|
279
|
+
# # => col("foo").sum().over([col("bar")])
|
|
280
|
+
def serialize(file = nil)
|
|
281
|
+
raise Todo unless _rbexpr.respond_to?(:serialize_binary)
|
|
282
|
+
|
|
283
|
+
serializer = _rbexpr.method(:serialize_binary)
|
|
284
|
+
|
|
285
|
+
Utils.serialize_polars_object(serializer, file)
|
|
200
286
|
end
|
|
201
287
|
|
|
202
288
|
# Format the expression as a tree.
|
|
@@ -209,8 +295,8 @@ module Polars
|
|
|
209
295
|
# @example
|
|
210
296
|
# e = (Polars.col("foo") * Polars.col("bar")).sum.over(Polars.col("ham")) / 2
|
|
211
297
|
# e.meta.tree_format(return_as_string: true)
|
|
212
|
-
def tree_format(return_as_string: false)
|
|
213
|
-
s = _rbexpr.meta_tree_format
|
|
298
|
+
def tree_format(return_as_string: false, schema: nil)
|
|
299
|
+
s = _rbexpr.meta_tree_format(schema)
|
|
214
300
|
if return_as_string
|
|
215
301
|
s
|
|
216
302
|
else
|
|
@@ -218,5 +304,41 @@ module Polars
|
|
|
218
304
|
nil
|
|
219
305
|
end
|
|
220
306
|
end
|
|
307
|
+
|
|
308
|
+
# Format the expression as a Graphviz graph.
|
|
309
|
+
#
|
|
310
|
+
# Note that Graphviz must be installed to render the visualization (if not
|
|
311
|
+
# already present, you can download it here: https://graphviz.org/download.
|
|
312
|
+
#
|
|
313
|
+
# @param show [Boolean]
|
|
314
|
+
# Show the figure.
|
|
315
|
+
# @param output_path [String]
|
|
316
|
+
# Write the figure to disk.
|
|
317
|
+
# @param raw_output [Boolean]
|
|
318
|
+
# Return dot syntax. This cannot be combined with `show` and/or `output_path`.
|
|
319
|
+
# @param figsize [Array]
|
|
320
|
+
# Passed to matplotlib if `show == true`.
|
|
321
|
+
#
|
|
322
|
+
# @return [Object]
|
|
323
|
+
#
|
|
324
|
+
# @example
|
|
325
|
+
# e = (Polars.col("foo") * Polars.col("bar")).sum.over(Polars.col("ham")) / 2
|
|
326
|
+
# e.meta.show_graph
|
|
327
|
+
def show_graph(
|
|
328
|
+
show: true,
|
|
329
|
+
output_path: nil,
|
|
330
|
+
raw_output: false,
|
|
331
|
+
figsize: [16.0, 12.0],
|
|
332
|
+
schema: nil
|
|
333
|
+
)
|
|
334
|
+
dot = _rbexpr.meta_show_graph(schema)
|
|
335
|
+
Utils.display_dot_graph(
|
|
336
|
+
dot: dot,
|
|
337
|
+
show: show,
|
|
338
|
+
output_path: output_path,
|
|
339
|
+
raw_output: raw_output,
|
|
340
|
+
figsize: figsize
|
|
341
|
+
)
|
|
342
|
+
end
|
|
221
343
|
end
|
|
222
344
|
end
|
data/lib/polars/name_expr.rb
CHANGED
|
@@ -77,8 +77,8 @@ module Polars
|
|
|
77
77
|
# # │ 2 ┆ y ┆ 2 ┆ y │
|
|
78
78
|
# # │ 1 ┆ x ┆ 3 ┆ z │
|
|
79
79
|
# # └───────────┴───────────┴─────┴─────┘
|
|
80
|
-
def map(&
|
|
81
|
-
Utils.wrap_expr(_rbexpr.name_map(
|
|
80
|
+
def map(&function)
|
|
81
|
+
Utils.wrap_expr(_rbexpr.name_map(function))
|
|
82
82
|
end
|
|
83
83
|
|
|
84
84
|
# Add a prefix to the root column name of the expression.
|
|
@@ -194,5 +194,90 @@ module Polars
|
|
|
194
194
|
def to_uppercase
|
|
195
195
|
Utils.wrap_expr(_rbexpr.name_to_uppercase)
|
|
196
196
|
end
|
|
197
|
+
|
|
198
|
+
# Rename fields of a struct by mapping a function over the field name(s).
|
|
199
|
+
#
|
|
200
|
+
# @note
|
|
201
|
+
# This only takes effect for struct columns.
|
|
202
|
+
#
|
|
203
|
+
# @return [Expr]
|
|
204
|
+
#
|
|
205
|
+
# @example
|
|
206
|
+
# df = Polars::DataFrame.new({"x" => {"a" => 1, "b" => 2}})
|
|
207
|
+
# df.select(Polars.col("x").name.map_fields { |x| x.upcase }).schema
|
|
208
|
+
# # => Polars::Schema({"x"=>Polars::Struct({"A"=>Polars::Int64, "B"=>Polars::Int64})})
|
|
209
|
+
def map_fields(&function)
|
|
210
|
+
Utils.wrap_expr(_rbexpr.name_map_fields(function))
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
# Add a prefix to all field names of a struct.
|
|
214
|
+
#
|
|
215
|
+
# @note
|
|
216
|
+
# This only takes effect for struct columns.
|
|
217
|
+
#
|
|
218
|
+
# @param prefix [String]
|
|
219
|
+
# Prefix to add to the field name.
|
|
220
|
+
#
|
|
221
|
+
# @return [Expr]
|
|
222
|
+
#
|
|
223
|
+
# @example
|
|
224
|
+
# df = Polars::DataFrame.new({"x" => {"a" => 1, "b" => 2}})
|
|
225
|
+
# df.select(Polars.col("x").name.prefix_fields("prefix_")).schema
|
|
226
|
+
# # => Polars::Schema({"x"=>Polars::Struct({"prefix_a"=>Polars::Int64, "prefix_b"=>Polars::Int64})})
|
|
227
|
+
def prefix_fields(prefix)
|
|
228
|
+
Utils.wrap_expr(_rbexpr.name_prefix_fields(prefix))
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
# Replace matching regex/literal substring in the name with a new value.
|
|
232
|
+
#
|
|
233
|
+
# @param pattern [String]
|
|
234
|
+
# A valid regular expression pattern, compatible with the [regex crate](https://docs.rs/regex/latest/regex/).
|
|
235
|
+
# @param value [String]
|
|
236
|
+
# String that will replace the matched substring.
|
|
237
|
+
# @param literal [Boolean]
|
|
238
|
+
# Treat `pattern` as a literal string, not a regex.
|
|
239
|
+
#
|
|
240
|
+
# @return [Expr]
|
|
241
|
+
#
|
|
242
|
+
# @example
|
|
243
|
+
# df = Polars::DataFrame.new(
|
|
244
|
+
# {
|
|
245
|
+
# "n_foo" => [1, 2, 3],
|
|
246
|
+
# "n_bar" => ["x", "y", "z"]
|
|
247
|
+
# }
|
|
248
|
+
# )
|
|
249
|
+
# df.select(Polars.all.name.replace("^n_", "col_"))
|
|
250
|
+
# # =>
|
|
251
|
+
# # shape: (3, 2)
|
|
252
|
+
# # ┌─────────┬─────────┐
|
|
253
|
+
# # │ col_foo ┆ col_bar │
|
|
254
|
+
# # │ --- ┆ --- │
|
|
255
|
+
# # │ i64 ┆ str │
|
|
256
|
+
# # ╞═════════╪═════════╡
|
|
257
|
+
# # │ 1 ┆ x │
|
|
258
|
+
# # │ 2 ┆ y │
|
|
259
|
+
# # │ 3 ┆ z │
|
|
260
|
+
# # └─────────┴─────────┘
|
|
261
|
+
def replace(pattern, value, literal: false)
|
|
262
|
+
Utils.wrap_expr(_rbexpr.name_replace(pattern, value, literal))
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
# Add a suffix to all field names of a struct.
|
|
266
|
+
#
|
|
267
|
+
# @note
|
|
268
|
+
# This only takes effect for struct columns.
|
|
269
|
+
#
|
|
270
|
+
# @param suffix [String]
|
|
271
|
+
# Suffix to add to the field name.
|
|
272
|
+
#
|
|
273
|
+
# @return [Expr]
|
|
274
|
+
#
|
|
275
|
+
# @example
|
|
276
|
+
# df = Polars::DataFrame.new({"x" => {"a" => 1, "b" => 2}})
|
|
277
|
+
# df.select(Polars.col("x").name.suffix_fields("_suffix")).schema
|
|
278
|
+
# # => Polars::Schema({"x"=>Polars::Struct({"a_suffix"=>Polars::Int64, "b_suffix"=>Polars::Int64})})
|
|
279
|
+
def suffix_fields(suffix)
|
|
280
|
+
Utils.wrap_expr(_rbexpr.name_suffix_fields(suffix))
|
|
281
|
+
end
|
|
197
282
|
end
|
|
198
283
|
end
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
module Polars
|
|
2
|
+
# The set of the optimizations considered during query optimization.
|
|
3
|
+
#
|
|
4
|
+
# @note
|
|
5
|
+
# This functionality is considered **unstable**. It may be changed
|
|
6
|
+
# at any point without it being considered a breaking change.
|
|
7
|
+
class QueryOptFlags
|
|
8
|
+
# @private
|
|
9
|
+
attr_accessor :_rboptflags
|
|
10
|
+
|
|
11
|
+
def initialize(
|
|
12
|
+
predicate_pushdown: nil,
|
|
13
|
+
projection_pushdown: nil,
|
|
14
|
+
simplify_expression: nil,
|
|
15
|
+
slice_pushdown: nil,
|
|
16
|
+
comm_subplan_elim: nil,
|
|
17
|
+
comm_subexpr_elim: nil,
|
|
18
|
+
cluster_with_columns: nil,
|
|
19
|
+
collapse_joins: nil,
|
|
20
|
+
check_order_observe: nil,
|
|
21
|
+
fast_projection: nil,
|
|
22
|
+
sort_collapse: nil
|
|
23
|
+
)
|
|
24
|
+
self._rboptflags = RbOptFlags.default
|
|
25
|
+
update(
|
|
26
|
+
predicate_pushdown: predicate_pushdown,
|
|
27
|
+
projection_pushdown: projection_pushdown,
|
|
28
|
+
simplify_expression: simplify_expression,
|
|
29
|
+
slice_pushdown: slice_pushdown,
|
|
30
|
+
comm_subplan_elim: comm_subplan_elim,
|
|
31
|
+
comm_subexpr_elim: comm_subexpr_elim,
|
|
32
|
+
cluster_with_columns: cluster_with_columns,
|
|
33
|
+
collapse_joins: collapse_joins,
|
|
34
|
+
check_order_observe: check_order_observe,
|
|
35
|
+
fast_projection: fast_projection,
|
|
36
|
+
sort_collapse: sort_collapse
|
|
37
|
+
)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Create new empty set off optimizations.
|
|
41
|
+
def self.none(
|
|
42
|
+
predicate_pushdown: nil,
|
|
43
|
+
projection_pushdown: nil,
|
|
44
|
+
simplify_expression: nil,
|
|
45
|
+
slice_pushdown: nil,
|
|
46
|
+
comm_subplan_elim: nil,
|
|
47
|
+
comm_subexpr_elim: nil,
|
|
48
|
+
cluster_with_columns: nil,
|
|
49
|
+
collapse_joins: nil,
|
|
50
|
+
check_order_observe: nil,
|
|
51
|
+
fast_projection: nil,
|
|
52
|
+
sort_collapse: nil
|
|
53
|
+
)
|
|
54
|
+
optflags = QueryOptFlags.new
|
|
55
|
+
optflags.no_optimizations
|
|
56
|
+
optflags.update(
|
|
57
|
+
predicate_pushdown: predicate_pushdown,
|
|
58
|
+
projection_pushdown: projection_pushdown,
|
|
59
|
+
simplify_expression: simplify_expression,
|
|
60
|
+
slice_pushdown: slice_pushdown,
|
|
61
|
+
comm_subplan_elim: comm_subplan_elim,
|
|
62
|
+
comm_subexpr_elim: comm_subexpr_elim,
|
|
63
|
+
cluster_with_columns: cluster_with_columns,
|
|
64
|
+
collapse_joins: collapse_joins,
|
|
65
|
+
check_order_observe: check_order_observe,
|
|
66
|
+
fast_projection: fast_projection,
|
|
67
|
+
sort_collapse: sort_collapse
|
|
68
|
+
)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def update(
|
|
72
|
+
predicate_pushdown: nil,
|
|
73
|
+
projection_pushdown: nil,
|
|
74
|
+
simplify_expression: nil,
|
|
75
|
+
slice_pushdown: nil,
|
|
76
|
+
comm_subplan_elim: nil,
|
|
77
|
+
comm_subexpr_elim: nil,
|
|
78
|
+
cluster_with_columns: nil,
|
|
79
|
+
collapse_joins: nil,
|
|
80
|
+
check_order_observe: nil,
|
|
81
|
+
fast_projection: nil,
|
|
82
|
+
sort_collapse: nil
|
|
83
|
+
)
|
|
84
|
+
if !predicate_pushdown.nil?
|
|
85
|
+
self.predicate_pushdown = predicate_pushdown
|
|
86
|
+
end
|
|
87
|
+
if !projection_pushdown.nil?
|
|
88
|
+
self.projection_pushdown = projection_pushdown
|
|
89
|
+
end
|
|
90
|
+
if !simplify_expression.nil?
|
|
91
|
+
self.simplify_expression = simplify_expression
|
|
92
|
+
end
|
|
93
|
+
if !slice_pushdown.nil?
|
|
94
|
+
self.slice_pushdown = slice_pushdown
|
|
95
|
+
end
|
|
96
|
+
if !comm_subplan_elim.nil?
|
|
97
|
+
self.comm_subplan_elim = comm_subplan_elim
|
|
98
|
+
end
|
|
99
|
+
if !comm_subexpr_elim.nil?
|
|
100
|
+
self.comm_subexpr_elim = comm_subexpr_elim
|
|
101
|
+
end
|
|
102
|
+
if !cluster_with_columns.nil?
|
|
103
|
+
self.cluster_with_columns = cluster_with_columns
|
|
104
|
+
end
|
|
105
|
+
if !collapse_joins.nil?
|
|
106
|
+
Utils.issue_deprecation_warning(
|
|
107
|
+
"the `collapse_joins` parameter for `QueryOptFlags` is deprecated. " +
|
|
108
|
+
"Use `predicate_pushdown` instead."
|
|
109
|
+
)
|
|
110
|
+
if !collapse_joins
|
|
111
|
+
self.predicate_pushdown = false
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
if !check_order_observe.nil?
|
|
115
|
+
self.check_order_observe = check_order_observe
|
|
116
|
+
end
|
|
117
|
+
if !fast_projection.nil?
|
|
118
|
+
self.fast_projection = fast_projection
|
|
119
|
+
end
|
|
120
|
+
if !sort_collapse.nil?
|
|
121
|
+
self.sort_collapse = sort_collapse
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
self
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
# Create new empty set off optimizations.
|
|
128
|
+
def self._eager
|
|
129
|
+
optflags = QueryOptFlags.new
|
|
130
|
+
optflags.no_optimizations
|
|
131
|
+
optflags._rboptflags.eager = true
|
|
132
|
+
optflags.simplify_expression = true
|
|
133
|
+
optflags
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
# Remove selected optimizations.
|
|
137
|
+
def no_optimizations
|
|
138
|
+
_rboptflags.no_optimizations
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
# Only read columns that are used later in the query.
|
|
142
|
+
def projection_pushdown
|
|
143
|
+
_rboptflags.projection_pushdown
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
def projection_pushdown=(value)
|
|
147
|
+
_rboptflags.projection_pushdown = value
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
# Apply predicates/filters as early as possible.
|
|
151
|
+
def predicate_pushdown
|
|
152
|
+
_rboptflags.predicate_pushdown
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
def predicate_pushdown=(value)
|
|
156
|
+
_rboptflags.predicate_pushdown = value
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
# Cluster sequential `with_columns` calls to independent calls.
|
|
160
|
+
def cluster_with_columns
|
|
161
|
+
_rboptflags.cluster_with_columns
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
def cluster_with_columns=(value)
|
|
165
|
+
_rboptflags.cluster_with_columns = value
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
# Run many expression optimization rules until fixed point.
|
|
169
|
+
def simplify_expression
|
|
170
|
+
_rboptflags.simplify_expression
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
def simplify_expression=(value)
|
|
174
|
+
_rboptflags.simplify_expression = value
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
# Pushdown slices/limits.
|
|
178
|
+
def slice_pushdown
|
|
179
|
+
_rboptflags.slice_pushdown
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
def slice_pushdown=(value)
|
|
183
|
+
_rboptflags.slice_pushdown = value
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
# Elide duplicate plans and caches their outputs.
|
|
187
|
+
def comm_subplan_elim
|
|
188
|
+
_rboptflags.comm_subplan_elim
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
def comm_subplan_elim=(value)
|
|
192
|
+
_rboptflags.comm_subplan_elim = value
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
# Elide duplicate expressions and caches their outputs.
|
|
196
|
+
def comm_subexpr_elim
|
|
197
|
+
_rboptflags.comm_subexpr_elim
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
def comm_subexpr_elim=(value)
|
|
201
|
+
_rboptflags.comm_subexpr_elim = value
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
# Do not maintain order if the order would not be observed.
|
|
205
|
+
def check_order_observe
|
|
206
|
+
_rboptflags.check_order_observe
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
def check_order_observe=(value)
|
|
210
|
+
_rboptflags.check_order_observe = value
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
# Replace simple projections with a faster inlined projection that skips the expression engine.
|
|
214
|
+
def fast_projection
|
|
215
|
+
_rboptflags.fast_projection
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
def fast_projection=(value)
|
|
219
|
+
_rboptflags.fast_projection = value
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
# Collapse sequential sort nodes into a single sort node.
|
|
223
|
+
def sort_collapse
|
|
224
|
+
_rboptflags.sort_collapse
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
def sort_collapse=(value)
|
|
228
|
+
_rboptflags.sort_collapse = value
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
def to_s
|
|
232
|
+
<<~STR
|
|
233
|
+
QueryOptFlags {
|
|
234
|
+
type_coercion: #{_rboptflags.type_coercion}
|
|
235
|
+
type_check: #{_rboptflags.type_check}
|
|
236
|
+
|
|
237
|
+
predicate_pushdown: #{predicate_pushdown}
|
|
238
|
+
projection_pushdown: #{projection_pushdown}
|
|
239
|
+
simplify_expression: #{simplify_expression}
|
|
240
|
+
slice_pushdown: #{slice_pushdown}
|
|
241
|
+
comm_subplan_elim: #{comm_subplan_elim}
|
|
242
|
+
comm_subexpr_elim: #{comm_subexpr_elim}
|
|
243
|
+
cluster_with_columns: #{cluster_with_columns}
|
|
244
|
+
check_order_observe: #{check_order_observe}
|
|
245
|
+
fast_projection: #{fast_projection}
|
|
246
|
+
|
|
247
|
+
eager: #{_rboptflags.eager}
|
|
248
|
+
streaming: #{_rboptflags.streaming}
|
|
249
|
+
}
|
|
250
|
+
STR
|
|
251
|
+
end
|
|
252
|
+
alias_method :inspect, :to_s
|
|
253
|
+
|
|
254
|
+
private
|
|
255
|
+
|
|
256
|
+
def initialize_copy(other)
|
|
257
|
+
super
|
|
258
|
+
self._rboptflags = _rboptflags.copy
|
|
259
|
+
end
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
# @private
|
|
263
|
+
DEFAULT_QUERY_OPT_FLAGS = QueryOptFlags.new
|
|
264
|
+
end
|
|
@@ -4,13 +4,15 @@ module Polars
|
|
|
4
4
|
# This has an `.agg` method which will allow you to run all polars expressions in a
|
|
5
5
|
# group by context.
|
|
6
6
|
class RollingGroupBy
|
|
7
|
+
# @private
|
|
7
8
|
def initialize(
|
|
8
9
|
df,
|
|
9
10
|
index_column,
|
|
10
11
|
period,
|
|
11
12
|
offset,
|
|
12
13
|
closed,
|
|
13
|
-
group_by
|
|
14
|
+
group_by,
|
|
15
|
+
predicates
|
|
14
16
|
)
|
|
15
17
|
period = Utils.parse_as_duration_string(period)
|
|
16
18
|
offset = Utils.parse_as_duration_string(offset)
|
|
@@ -21,15 +23,98 @@ module Polars
|
|
|
21
23
|
@offset = offset
|
|
22
24
|
@closed = closed
|
|
23
25
|
@group_by = group_by
|
|
26
|
+
@predicates = predicates
|
|
24
27
|
end
|
|
25
28
|
|
|
29
|
+
# Filter groups with a list of predicates after aggregation.
|
|
30
|
+
#
|
|
31
|
+
# Using this method is equivalent to adding the predicates to the aggregation and
|
|
32
|
+
# filtering afterwards.
|
|
33
|
+
#
|
|
34
|
+
# This method can be chained and all conditions will be combined using `&`.
|
|
35
|
+
#
|
|
36
|
+
# @param predicates [Array]
|
|
37
|
+
# Expressions that evaluate to a boolean value for each group. Typically, this
|
|
38
|
+
# requires the use of an aggregation function. Multiple predicates are
|
|
39
|
+
# combined using `&`.
|
|
40
|
+
#
|
|
41
|
+
# @return [RollingGroupBy]
|
|
42
|
+
def having(*predicates)
|
|
43
|
+
RollingGroupBy.new(
|
|
44
|
+
@df,
|
|
45
|
+
@time_column,
|
|
46
|
+
@period,
|
|
47
|
+
@offset,
|
|
48
|
+
@closed,
|
|
49
|
+
@group_by,
|
|
50
|
+
Utils._chain_predicates(@predicates, predicates)
|
|
51
|
+
)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Compute aggregations for each group of a group by operation.
|
|
55
|
+
#
|
|
56
|
+
# @param aggs [Array]
|
|
57
|
+
# Aggregations to compute for each group of the group by operation,
|
|
58
|
+
# specified as positional arguments.
|
|
59
|
+
# Accepts expression input. Strings are parsed as column names.
|
|
60
|
+
# @param named_aggs [Hash]
|
|
61
|
+
# Additional aggregations, specified as keyword arguments.
|
|
62
|
+
# The resulting columns will be renamed to the keyword used.
|
|
63
|
+
#
|
|
64
|
+
# @return [DataFrame]
|
|
26
65
|
def agg(*aggs, **named_aggs)
|
|
66
|
+
group_by =
|
|
67
|
+
@df.lazy.rolling(
|
|
68
|
+
index_column: @time_column, period: @period, offset: @offset, closed: @closed, group_by: @group_by
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
if @predicates&.any?
|
|
72
|
+
group_by = group_by.having(@predicates)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
group_by.agg(*aggs, **named_aggs).collect(
|
|
76
|
+
optimizations: QueryOptFlags.none
|
|
77
|
+
)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Apply a custom/user-defined function (UDF) over the groups as a new DataFrame.
|
|
81
|
+
#
|
|
82
|
+
# Using this is considered an anti-pattern as it will be very slow because:
|
|
83
|
+
#
|
|
84
|
+
# - it forces the engine to materialize the whole `DataFrames` for the groups.
|
|
85
|
+
# - it is not parallelized.
|
|
86
|
+
# - it blocks optimizations as the passed python function is opaque to the
|
|
87
|
+
# optimizer.
|
|
88
|
+
#
|
|
89
|
+
# The idiomatic way to apply custom functions over multiple columns is using:
|
|
90
|
+
#
|
|
91
|
+
# `Polars.struct([my_columns]).map_elements { |struct_series| ... }`
|
|
92
|
+
#
|
|
93
|
+
# @param schema [Object]
|
|
94
|
+
# Schema of the output function. This has to be known statically. If the
|
|
95
|
+
# given schema is incorrect, this is a bug in the caller's query and may
|
|
96
|
+
# lead to errors. If set to None, polars assumes the schema is unchanged.
|
|
97
|
+
#
|
|
98
|
+
# @return [DataFrame]
|
|
99
|
+
def map_groups(
|
|
100
|
+
schema,
|
|
101
|
+
&function
|
|
102
|
+
)
|
|
103
|
+
if @predicates&.any?
|
|
104
|
+
msg = "cannot call `map_groups` when filtering groups with `having`"
|
|
105
|
+
raise TypeError, msg
|
|
106
|
+
end
|
|
107
|
+
|
|
27
108
|
@df.lazy
|
|
28
|
-
.
|
|
29
|
-
index_column: @time_column,
|
|
109
|
+
.rolling(
|
|
110
|
+
index_column: @time_column,
|
|
111
|
+
period: @period,
|
|
112
|
+
offset: @offset,
|
|
113
|
+
closed: @closed,
|
|
114
|
+
group_by: @group_by
|
|
30
115
|
)
|
|
31
|
-
.
|
|
32
|
-
.collect(
|
|
116
|
+
.map_groups(schema, &function)
|
|
117
|
+
.collect(optimizations: QueryOptFlags.none)
|
|
33
118
|
end
|
|
34
119
|
end
|
|
35
120
|
end
|