polars-df 0.25.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 +33 -0
- data/Cargo.lock +270 -97
- data/LICENSE.txt +1 -1
- data/README.md +1 -3
- data/ext/polars/Cargo.toml +19 -18
- data/ext/polars/src/catalog/unity.rs +15 -20
- data/ext/polars/src/conversion/any_value.rs +53 -29
- data/ext/polars/src/conversion/chunked_array.rs +58 -56
- data/ext/polars/src/conversion/datetime.rs +58 -7
- data/ext/polars/src/conversion/mod.rs +200 -150
- data/ext/polars/src/dataframe/export.rs +15 -12
- data/ext/polars/src/dataframe/general.rs +25 -7
- data/ext/polars/src/dataframe/map.rs +6 -4
- data/ext/polars/src/error.rs +1 -1
- data/ext/polars/src/expr/array.rs +0 -24
- data/ext/polars/src/expr/datatype.rs +13 -3
- data/ext/polars/src/expr/datetime.rs +4 -4
- data/ext/polars/src/expr/general.rs +35 -15
- data/ext/polars/src/expr/list.rs +0 -26
- data/ext/polars/src/expr/rolling.rs +24 -0
- data/ext/polars/src/functions/business.rs +2 -2
- data/ext/polars/src/functions/io.rs +4 -3
- data/ext/polars/src/functions/lazy.rs +65 -46
- data/ext/polars/src/functions/meta.rs +6 -5
- data/ext/polars/src/functions/mod.rs +0 -1
- data/ext/polars/src/functions/range.rs +13 -0
- data/ext/polars/src/functions/utils.rs +4 -2
- data/ext/polars/src/interop/arrow/mod.rs +4 -2
- data/ext/polars/src/interop/arrow/to_rb.rs +1 -1
- data/ext/polars/src/interop/numo/to_numo_series.rs +26 -25
- data/ext/polars/src/io/scan_options.rs +6 -3
- data/ext/polars/src/io/sink_options.rs +2 -0
- data/ext/polars/src/lazyframe/general.rs +243 -17
- data/ext/polars/src/lazyframe/optflags.rs +2 -1
- data/ext/polars/src/lib.rs +39 -35
- data/ext/polars/src/map/lazy.rs +5 -2
- data/ext/polars/src/map/series.rs +19 -18
- data/ext/polars/src/on_startup.rs +25 -6
- data/ext/polars/src/ruby/numo.rs +3 -4
- data/ext/polars/src/ruby/plan_callback.rs +1 -4
- data/ext/polars/src/ruby/rb_modules.rs +2 -4
- data/ext/polars/src/ruby/ruby_udf.rs +7 -9
- data/ext/polars/src/ruby/utils.rs +12 -1
- data/ext/polars/src/series/aggregation.rs +13 -1
- data/ext/polars/src/series/construction.rs +31 -50
- data/ext/polars/src/series/export.rs +33 -38
- data/ext/polars/src/series/general.rs +6 -6
- data/ext/polars/src/series/map.rs +3 -2
- data/ext/polars/src/series/scatter.rs +4 -4
- data/ext/polars/src/utils.rs +31 -7
- data/lib/polars/array_expr.rb +23 -7
- data/lib/polars/array_name_space.rb +16 -2
- data/lib/polars/binary_name_space.rb +32 -0
- data/lib/polars/collect_batches.rb +4 -0
- data/lib/polars/data_frame.rb +144 -11
- data/lib/polars/data_type_group.rb +5 -0
- data/lib/polars/date_time_expr.rb +91 -3
- data/lib/polars/date_time_name_space.rb +7 -1
- data/lib/polars/expr.rb +247 -44
- data/lib/polars/functions/business.rb +2 -2
- data/lib/polars/functions/datatype.rb +30 -0
- data/lib/polars/functions/eager.rb +80 -7
- data/lib/polars/functions/lazy.rb +97 -2
- data/lib/polars/functions/range/linear_space.rb +118 -0
- data/lib/polars/io/csv.rb +27 -5
- data/lib/polars/io/database.rb +2 -3
- data/lib/polars/io/ipc.rb +2 -2
- data/lib/polars/io/lines.rb +172 -0
- data/lib/polars/io/parquet.rb +1 -1
- data/lib/polars/io/sink_options.rb +5 -2
- data/lib/polars/lazy_frame.rb +517 -14
- data/lib/polars/list_expr.rb +21 -7
- data/lib/polars/list_name_space.rb +16 -2
- data/lib/polars/query_opt_flags.rb +23 -5
- data/lib/polars/selectors.rb +2 -2
- data/lib/polars/series.rb +176 -19
- data/lib/polars/sql_context.rb +2 -2
- data/lib/polars/string_cache.rb +19 -72
- data/lib/polars/string_expr.rb +1 -7
- data/lib/polars/string_name_space.rb +1 -7
- data/lib/polars/utils/construction/series.rb +24 -39
- data/lib/polars/utils/convert.rb +16 -6
- data/lib/polars/utils/parse.rb +7 -0
- data/lib/polars/utils/reduce_balanced.rb +43 -0
- data/lib/polars/utils/various.rb +5 -0
- data/lib/polars/version.rb +1 -1
- data/lib/polars.rb +2 -1
- metadata +4 -17
- data/ext/polars/src/functions/string_cache.rs +0 -24
data/lib/polars/lazy_frame.rb
CHANGED
|
@@ -262,6 +262,59 @@ module Polars
|
|
|
262
262
|
function.(self, *args, **kwargs, &block)
|
|
263
263
|
end
|
|
264
264
|
|
|
265
|
+
# Allows to alter the lazy frame during the plan stage with the resolved schema.
|
|
266
|
+
#
|
|
267
|
+
# In contrast to `pipe`, this method does not execute `function` immediately but
|
|
268
|
+
# only during the plan stage. This allows to use the resolved schema of the input
|
|
269
|
+
# to dynamically alter the lazy frame. This also means that any exceptions raised
|
|
270
|
+
# by `function` will only be emitted during the plan stage.
|
|
271
|
+
#
|
|
272
|
+
# @note
|
|
273
|
+
# This functionality is considered **unstable**. It may be changed at any
|
|
274
|
+
# point without it being considered a breaking change.
|
|
275
|
+
#
|
|
276
|
+
# @param function [Object]
|
|
277
|
+
# Callable; will receive the frame as the first parameter and the resolved
|
|
278
|
+
# schema as the second parameter.
|
|
279
|
+
#
|
|
280
|
+
# @return [LazyFrame]
|
|
281
|
+
#
|
|
282
|
+
# @example
|
|
283
|
+
# cast_to_float_if_necessary = lambda do |lf, schema|
|
|
284
|
+
# required_casts =
|
|
285
|
+
# schema.filter_map do |name, dtype|
|
|
286
|
+
# Polars.col(name).cast(Polars::Float64) if !dtype.float?
|
|
287
|
+
# end
|
|
288
|
+
# lf.with_columns(required_casts)
|
|
289
|
+
# end
|
|
290
|
+
# lf = Polars::LazyFrame.new(
|
|
291
|
+
# {"a" => [1.0, 2.0], "b" => ["1.0", "2.5"], "c" => [2.0, 3.0]},
|
|
292
|
+
# schema: {"a" => Polars::Float64, "b" => Polars::String, "c" => Polars::Float32}
|
|
293
|
+
# )
|
|
294
|
+
# lf.pipe_with_schema(cast_to_float_if_necessary).collect
|
|
295
|
+
# # =>
|
|
296
|
+
# # shape: (2, 3)
|
|
297
|
+
# # ┌─────┬─────┬─────┐
|
|
298
|
+
# # │ a ┆ b ┆ c │
|
|
299
|
+
# # │ --- ┆ --- ┆ --- │
|
|
300
|
+
# # │ f64 ┆ f64 ┆ f32 │
|
|
301
|
+
# # ╞═════╪═════╪═════╡
|
|
302
|
+
# # │ 1.0 ┆ 1.0 ┆ 2.0 │
|
|
303
|
+
# # │ 2.0 ┆ 2.5 ┆ 3.0 │
|
|
304
|
+
# # └─────┴─────┴─────┘
|
|
305
|
+
def pipe_with_schema(function)
|
|
306
|
+
wrapper = lambda do |lf_and_schema|
|
|
307
|
+
# The last index is because we return a list for multiple inputs
|
|
308
|
+
# to make `pipe_with_schemas` (plural) work, but we don't use that
|
|
309
|
+
function.(
|
|
310
|
+
_from_rbldf(lf_and_schema[0][0]),
|
|
311
|
+
lf_and_schema[1][0]
|
|
312
|
+
)._ldf
|
|
313
|
+
end
|
|
314
|
+
|
|
315
|
+
_from_rbldf(_ldf.pipe_with_schema(wrapper))
|
|
316
|
+
end
|
|
317
|
+
|
|
265
318
|
# Creates a summary of statistics for a LazyFrame, returning a DataFrame.
|
|
266
319
|
#
|
|
267
320
|
# @param percentiles [Array]
|
|
@@ -1109,7 +1162,8 @@ module Polars
|
|
|
1109
1162
|
lazy: false,
|
|
1110
1163
|
arrow_schema: nil,
|
|
1111
1164
|
engine: "auto",
|
|
1112
|
-
optimizations: DEFAULT_QUERY_OPT_FLAGS
|
|
1165
|
+
optimizations: DEFAULT_QUERY_OPT_FLAGS,
|
|
1166
|
+
_sinked_paths_callback: nil
|
|
1113
1167
|
)
|
|
1114
1168
|
engine = _select_engine(engine)
|
|
1115
1169
|
|
|
@@ -1151,7 +1205,8 @@ module Polars
|
|
|
1151
1205
|
maintain_order: maintain_order,
|
|
1152
1206
|
sync_on_close: sync_on_close,
|
|
1153
1207
|
storage_options: storage_options,
|
|
1154
|
-
credential_provider: credential_provider_builder
|
|
1208
|
+
credential_provider: credential_provider_builder,
|
|
1209
|
+
sinked_paths_callback: _sinked_paths_callback
|
|
1155
1210
|
)
|
|
1156
1211
|
|
|
1157
1212
|
ldf_rb = _ldf.sink_parquet(
|
|
@@ -1175,6 +1230,133 @@ module Polars
|
|
|
1175
1230
|
LazyFrame._from_rbldf(ldf_rb)
|
|
1176
1231
|
end
|
|
1177
1232
|
|
|
1233
|
+
# Sink DataFrame as delta table.
|
|
1234
|
+
#
|
|
1235
|
+
# @note
|
|
1236
|
+
# This functionality is considered **unstable**. It may be changed
|
|
1237
|
+
# at any point without it being considered a breaking change.
|
|
1238
|
+
#
|
|
1239
|
+
# @param target [Object]
|
|
1240
|
+
# URI of a table or a DeltaTable object.
|
|
1241
|
+
# @param mode ['error', 'append', 'overwrite', 'ignore', 'merge']
|
|
1242
|
+
# How to handle existing data.
|
|
1243
|
+
#
|
|
1244
|
+
# - If 'error', throw an error if the table already exists (default).
|
|
1245
|
+
# - If 'append', will add new data.
|
|
1246
|
+
# - If 'overwrite', will replace table with new data.
|
|
1247
|
+
# - If 'ignore', will not write anything if table already exists.
|
|
1248
|
+
# - If 'merge', return a `TableMerger` object to merge data from the DataFrame
|
|
1249
|
+
# with the existing data.
|
|
1250
|
+
# @param storage_options [Object]
|
|
1251
|
+
# Extra options for the storage backends supported by `deltalake`.
|
|
1252
|
+
# For cloud storages, this may include configurations for authentication etc.
|
|
1253
|
+
#
|
|
1254
|
+
# - See a list of supported storage options for S3 [here](https://docs.rs/object_store/latest/object_store/aws/enum.AmazonS3ConfigKey.html#variants).
|
|
1255
|
+
# - See a list of supported storage options for GCS [here](https://docs.rs/object_store/latest/object_store/gcp/enum.GoogleConfigKey.html#variants).
|
|
1256
|
+
# - See a list of supported storage options for Azure [here](https://docs.rs/object_store/latest/object_store/azure/enum.AzureConfigKey.html#variants).
|
|
1257
|
+
# @param credential_provider [Object]
|
|
1258
|
+
# Provide a function that can be called to provide cloud storage
|
|
1259
|
+
# credentials. The function is expected to return a dictionary of
|
|
1260
|
+
# credential keys along with an optional credential expiry time.
|
|
1261
|
+
# @param delta_write_options [Hash]
|
|
1262
|
+
# Additional keyword arguments while writing a Delta lake Table.
|
|
1263
|
+
# See a list of supported write options [here](https://delta-io.github.io/delta-rs/api/delta_writer/#deltalake.write_deltalake).
|
|
1264
|
+
# @param delta_merge_options [Hash]
|
|
1265
|
+
# Keyword arguments which are required to `MERGE` a Delta lake Table.
|
|
1266
|
+
# See a list of supported merge options [here](https://delta-io.github.io/delta-rs/api/delta_table/#deltalake.DeltaTable.merge).
|
|
1267
|
+
# @param optimizations [Object]
|
|
1268
|
+
# The optimization passes done during query optimization.
|
|
1269
|
+
#
|
|
1270
|
+
# @return [Object]
|
|
1271
|
+
#
|
|
1272
|
+
# @example Sink a large than fits into memory dataset to a Delta Lake table.
|
|
1273
|
+
# lf = Polars.scan_parquet(
|
|
1274
|
+
# "/path/to/my_larger_than_ram_file.parquet"
|
|
1275
|
+
# )
|
|
1276
|
+
# table_path = "/path/to/delta-table/"
|
|
1277
|
+
# lf.sink_delta(table_path)
|
|
1278
|
+
def sink_delta(
|
|
1279
|
+
target,
|
|
1280
|
+
mode: "error",
|
|
1281
|
+
storage_options: nil,
|
|
1282
|
+
credential_provider: "auto",
|
|
1283
|
+
delta_write_options: nil,
|
|
1284
|
+
delta_merge_options: nil,
|
|
1285
|
+
optimizations: DEFAULT_QUERY_OPT_FLAGS
|
|
1286
|
+
)
|
|
1287
|
+
Polars.send(:_check_if_delta_available)
|
|
1288
|
+
|
|
1289
|
+
# TODO
|
|
1290
|
+
# _check_for_unsupported_types(collect_schema.dtypes)
|
|
1291
|
+
|
|
1292
|
+
if Utils.pathlike?(target)
|
|
1293
|
+
target = Polars.send(:_resolve_delta_lake_uri, target.to_s, strict: false)
|
|
1294
|
+
end
|
|
1295
|
+
|
|
1296
|
+
_init_credential_provider_builder = Polars.method(:_init_credential_provider_builder)
|
|
1297
|
+
|
|
1298
|
+
if !target.is_a?(DeltaLake::Table)
|
|
1299
|
+
credential_provider_builder = _init_credential_provider_builder.(
|
|
1300
|
+
credential_provider, target, storage_options, "sink_delta"
|
|
1301
|
+
)
|
|
1302
|
+
elsif !credential_provider.nil? && credential_provider != "auto"
|
|
1303
|
+
msg = "cannot use credential_provider when passing a DeltaTable object"
|
|
1304
|
+
raise ArgumentError, msg
|
|
1305
|
+
else
|
|
1306
|
+
credential_provider_builder = nil
|
|
1307
|
+
end
|
|
1308
|
+
|
|
1309
|
+
credential_provider_creds = {}
|
|
1310
|
+
|
|
1311
|
+
if credential_provider_builder
|
|
1312
|
+
raise Todo
|
|
1313
|
+
end
|
|
1314
|
+
|
|
1315
|
+
# We aren't calling into polars-native write functions so we just update
|
|
1316
|
+
# the storage_options here.
|
|
1317
|
+
storage_options =
|
|
1318
|
+
if !storage_options.nil? || !credential_provider_builder.nil?
|
|
1319
|
+
(storage_options || {}).merge(credential_provider_creds)
|
|
1320
|
+
else
|
|
1321
|
+
nil
|
|
1322
|
+
end
|
|
1323
|
+
|
|
1324
|
+
stream = collect_batches(
|
|
1325
|
+
engine: "streaming",
|
|
1326
|
+
maintain_order: true,
|
|
1327
|
+
chunk_size: nil,
|
|
1328
|
+
lazy: true,
|
|
1329
|
+
optimizations: optimizations
|
|
1330
|
+
)
|
|
1331
|
+
|
|
1332
|
+
if mode == "merge"
|
|
1333
|
+
if delta_merge_options.nil?
|
|
1334
|
+
msg = "you need to pass delta_merge_options with at least a given predicate for `MERGE` to work."
|
|
1335
|
+
raise ArgumentError, msg
|
|
1336
|
+
end
|
|
1337
|
+
if target.is_a?(::String)
|
|
1338
|
+
dt = DeltaLake::Table.new(target, storage_options: storage_options)
|
|
1339
|
+
else
|
|
1340
|
+
dt = target
|
|
1341
|
+
end
|
|
1342
|
+
|
|
1343
|
+
dt.merge(stream, **delta_merge_options)
|
|
1344
|
+
else
|
|
1345
|
+
if delta_write_options.nil?
|
|
1346
|
+
delta_write_options = {}
|
|
1347
|
+
end
|
|
1348
|
+
|
|
1349
|
+
DeltaLake.write(
|
|
1350
|
+
target,
|
|
1351
|
+
stream,
|
|
1352
|
+
mode: mode,
|
|
1353
|
+
storage_options: storage_options,
|
|
1354
|
+
**delta_write_options
|
|
1355
|
+
)
|
|
1356
|
+
nil
|
|
1357
|
+
end
|
|
1358
|
+
end
|
|
1359
|
+
|
|
1178
1360
|
# Evaluate the query in streaming mode and write to an IPC file.
|
|
1179
1361
|
#
|
|
1180
1362
|
# This allows streaming results that are larger than RAM to be written to disk.
|
|
@@ -1591,6 +1773,71 @@ module Polars
|
|
|
1591
1773
|
LazyFrame._from_rbldf(ldf_rb)
|
|
1592
1774
|
end
|
|
1593
1775
|
|
|
1776
|
+
# Evaluate the query and call a user-defined function for every ready batch.
|
|
1777
|
+
#
|
|
1778
|
+
# This allows streaming results that are larger than RAM in certain cases.
|
|
1779
|
+
#
|
|
1780
|
+
# @note
|
|
1781
|
+
# This functionality is considered **unstable**. It may be changed
|
|
1782
|
+
# at any point without it being considered a breaking change.
|
|
1783
|
+
#
|
|
1784
|
+
# @note
|
|
1785
|
+
# This method is much slower than native sinks. Only use it if you cannot
|
|
1786
|
+
# implement your logic otherwise.
|
|
1787
|
+
#
|
|
1788
|
+
# @param chunk_size [Integer]
|
|
1789
|
+
# The number of rows that are buffered before the callback is called.
|
|
1790
|
+
# @param maintain_order [Boolean]
|
|
1791
|
+
# Maintain the order in which data is processed.
|
|
1792
|
+
# Setting this to `false` will be slightly faster.
|
|
1793
|
+
# @param lazy [Boolean]
|
|
1794
|
+
# Wait to start execution until `collect` is called.
|
|
1795
|
+
# @param engine [String]
|
|
1796
|
+
# Select the engine used to process the query, optional.
|
|
1797
|
+
# At the moment, if set to `"auto"` (default), the query is run
|
|
1798
|
+
# using the polars streaming engine. Polars will also
|
|
1799
|
+
# attempt to use the engine set by the `POLARS_ENGINE_AFFINITY`
|
|
1800
|
+
# environment variable. If it cannot run the query using the
|
|
1801
|
+
# selected engine, the query is run using the polars streaming
|
|
1802
|
+
# engine.
|
|
1803
|
+
# @param optimizations [Object]
|
|
1804
|
+
# The optimization passes done during query optimization.
|
|
1805
|
+
#
|
|
1806
|
+
# This has no effect if `lazy` is set to `True`.
|
|
1807
|
+
#
|
|
1808
|
+
# @return [Object]
|
|
1809
|
+
#
|
|
1810
|
+
# @example
|
|
1811
|
+
# lf = Polars.scan_csv("/path/to/my_larger_than_ram_file.csv")
|
|
1812
|
+
# lf.sink_batches { |df| p df }
|
|
1813
|
+
def sink_batches(
|
|
1814
|
+
chunk_size: nil,
|
|
1815
|
+
maintain_order: true,
|
|
1816
|
+
lazy: false,
|
|
1817
|
+
engine: "auto",
|
|
1818
|
+
optimizations: DEFAULT_QUERY_OPT_FLAGS,
|
|
1819
|
+
&function
|
|
1820
|
+
)
|
|
1821
|
+
_wrap = lambda do |rbdf|
|
|
1822
|
+
df = Utils.wrap_df(rbdf)
|
|
1823
|
+
!!function.(df)
|
|
1824
|
+
end
|
|
1825
|
+
|
|
1826
|
+
ldf = _ldf.sink_batches(
|
|
1827
|
+
_wrap,
|
|
1828
|
+
maintain_order,
|
|
1829
|
+
chunk_size
|
|
1830
|
+
)
|
|
1831
|
+
|
|
1832
|
+
if !lazy
|
|
1833
|
+
ldf = ldf.with_optimizations(optimizations._rboptflags)
|
|
1834
|
+
lf = LazyFrame._from_rbldf(ldf)
|
|
1835
|
+
lf.collect(engine: engine)
|
|
1836
|
+
return nil
|
|
1837
|
+
end
|
|
1838
|
+
LazyFrame._from_rbldf(ldf)
|
|
1839
|
+
end
|
|
1840
|
+
|
|
1594
1841
|
# Evaluate the query in streaming mode and get a generator that returns chunks.
|
|
1595
1842
|
#
|
|
1596
1843
|
# This allows streaming results that are larger than RAM to be written to disk.
|
|
@@ -3234,6 +3481,78 @@ module Polars
|
|
|
3234
3481
|
)
|
|
3235
3482
|
end
|
|
3236
3483
|
|
|
3484
|
+
# Selects rows from this LazyFrame at the given indices.
|
|
3485
|
+
#
|
|
3486
|
+
# @note
|
|
3487
|
+
# This functionality is experimental. It may be
|
|
3488
|
+
# changed at any point without it being considered a breaking change.
|
|
3489
|
+
#
|
|
3490
|
+
# @param indices [Object]
|
|
3491
|
+
# The indices of the rows to select.
|
|
3492
|
+
#
|
|
3493
|
+
# Due to the lack of a `LazySeries` it's permitted to pass a single-width
|
|
3494
|
+
# `LazyFrame` as indices as well.
|
|
3495
|
+
# @param null_on_oob [Boolean]
|
|
3496
|
+
# If true when an index is out-of-bounds a null row will be generated
|
|
3497
|
+
# instead of raising an error.
|
|
3498
|
+
#
|
|
3499
|
+
# @return [LazyFrame]
|
|
3500
|
+
#
|
|
3501
|
+
# @example
|
|
3502
|
+
# lf = Polars::LazyFrame.new({"x" => [2, 1, 0], "s" => ["foo", "bar", "baz"]})
|
|
3503
|
+
# lf.gather([2, 0, 0]).collect
|
|
3504
|
+
# # =>
|
|
3505
|
+
# # shape: (3, 2)
|
|
3506
|
+
# # ┌─────┬─────┐
|
|
3507
|
+
# # │ x ┆ s │
|
|
3508
|
+
# # │ --- ┆ --- │
|
|
3509
|
+
# # │ i64 ┆ str │
|
|
3510
|
+
# # ╞═════╪═════╡
|
|
3511
|
+
# # │ 0 ┆ baz │
|
|
3512
|
+
# # │ 2 ┆ foo │
|
|
3513
|
+
# # │ 2 ┆ foo │
|
|
3514
|
+
# # └─────┴─────┘
|
|
3515
|
+
#
|
|
3516
|
+
# @example
|
|
3517
|
+
# lf.gather([0, 10, 1], null_on_oob: true).collect
|
|
3518
|
+
# # =>
|
|
3519
|
+
# # shape: (3, 2)
|
|
3520
|
+
# # ┌──────┬──────┐
|
|
3521
|
+
# # │ x ┆ s │
|
|
3522
|
+
# # │ --- ┆ --- │
|
|
3523
|
+
# # │ i64 ┆ str │
|
|
3524
|
+
# # ╞══════╪══════╡
|
|
3525
|
+
# # │ 2 ┆ foo │
|
|
3526
|
+
# # │ null ┆ null │
|
|
3527
|
+
# # │ 1 ┆ bar │
|
|
3528
|
+
# # └──────┴──────┘
|
|
3529
|
+
#
|
|
3530
|
+
# @example
|
|
3531
|
+
# idxs = Polars::LazyFrame.new({"i" => [1, 10, 0], "b" => [true, false, true]})
|
|
3532
|
+
# lf.gather(idxs.filter(Polars.col("b")).select(Polars.col("i"))).collect
|
|
3533
|
+
# # =>
|
|
3534
|
+
# # shape: (2, 2)
|
|
3535
|
+
# # ┌─────┬─────┐
|
|
3536
|
+
# # │ x ┆ s │
|
|
3537
|
+
# # │ --- ┆ --- │
|
|
3538
|
+
# # │ i64 ┆ str │
|
|
3539
|
+
# # ╞═════╪═════╡
|
|
3540
|
+
# # │ 1 ┆ bar │
|
|
3541
|
+
# # │ 2 ┆ foo │
|
|
3542
|
+
# # └─────┴─────┘
|
|
3543
|
+
def gather(indices, null_on_oob: false)
|
|
3544
|
+
if !indices.is_a?(LazyFrame)
|
|
3545
|
+
if indices.is_a?(::Array)
|
|
3546
|
+
indices_expr = F.lit(Series.new("", indices, dtype: Int64))
|
|
3547
|
+
else
|
|
3548
|
+
indices_expr = wrap_expr(Utils.parse_into_expression(indices))
|
|
3549
|
+
end
|
|
3550
|
+
indices = select(indices_expr)
|
|
3551
|
+
end
|
|
3552
|
+
|
|
3553
|
+
_from_rbldf(_ldf.gather(indices._ldf, null_on_oob))
|
|
3554
|
+
end
|
|
3555
|
+
|
|
3237
3556
|
# Add or overwrite multiple columns in a DataFrame.
|
|
3238
3557
|
#
|
|
3239
3558
|
# @param exprs [Object]
|
|
@@ -4398,6 +4717,8 @@ module Polars
|
|
|
4398
4717
|
# @param separator [String]
|
|
4399
4718
|
# Used as separator/delimiter in generated column names in case of multiple
|
|
4400
4719
|
# `values` columns.
|
|
4720
|
+
# @param column_naming ['auto', 'combine']
|
|
4721
|
+
# How resulting column names will be constructed.
|
|
4401
4722
|
#
|
|
4402
4723
|
# @return [LazyFrame]
|
|
4403
4724
|
#
|
|
@@ -4437,7 +4758,8 @@ module Polars
|
|
|
4437
4758
|
values: nil,
|
|
4438
4759
|
aggregate_function: nil,
|
|
4439
4760
|
maintain_order: false,
|
|
4440
|
-
separator: "_"
|
|
4761
|
+
separator: "_",
|
|
4762
|
+
column_naming: "auto"
|
|
4441
4763
|
)
|
|
4442
4764
|
if index.nil? && values.nil?
|
|
4443
4765
|
msg = "`pivot` needs either `index or `values` needs to be specified"
|
|
@@ -4511,7 +4833,8 @@ module Polars
|
|
|
4511
4833
|
values_selector._rbselector,
|
|
4512
4834
|
agg._rbexpr,
|
|
4513
4835
|
maintain_order,
|
|
4514
|
-
separator
|
|
4836
|
+
separator,
|
|
4837
|
+
column_naming
|
|
4515
4838
|
)
|
|
4516
4839
|
)
|
|
4517
4840
|
end
|
|
@@ -4527,7 +4850,8 @@ module Polars
|
|
|
4527
4850
|
#
|
|
4528
4851
|
# @param on [Object]
|
|
4529
4852
|
# Column(s) or selector(s) to use as values variables; if `on`
|
|
4530
|
-
# is empty
|
|
4853
|
+
# is empty no columns will be used. If set to `nil` (default)
|
|
4854
|
+
# all columns that are not in `index` will be used.
|
|
4531
4855
|
# @param index [Object]
|
|
4532
4856
|
# Column(s) or selector(s) to use as identifier variables.
|
|
4533
4857
|
# @param variable_name [String]
|
|
@@ -4575,12 +4899,12 @@ module Polars
|
|
|
4575
4899
|
warn "The `streamable` parameter for `LazyFrame.unpivot` is deprecated"
|
|
4576
4900
|
end
|
|
4577
4901
|
|
|
4578
|
-
selector_on = on.nil? ?
|
|
4902
|
+
selector_on = on.nil? ? nil : Utils.parse_list_into_selector(on)._rbselector
|
|
4579
4903
|
selector_index = index.nil? ? Selectors.empty : Utils.parse_list_into_selector(index)
|
|
4580
4904
|
|
|
4581
4905
|
_from_rbldf(
|
|
4582
4906
|
_ldf.unpivot(
|
|
4583
|
-
selector_on
|
|
4907
|
+
selector_on,
|
|
4584
4908
|
selector_index._rbselector,
|
|
4585
4909
|
value_name,
|
|
4586
4910
|
variable_name
|
|
@@ -4660,10 +4984,10 @@ module Polars
|
|
|
4660
4984
|
# # │ -2 ┆ 199998 │
|
|
4661
4985
|
# # └─────────┴────────┘
|
|
4662
4986
|
def map_batches(
|
|
4663
|
-
predicate_pushdown:
|
|
4664
|
-
projection_pushdown:
|
|
4665
|
-
slice_pushdown:
|
|
4666
|
-
no_optimizations:
|
|
4987
|
+
predicate_pushdown: false,
|
|
4988
|
+
projection_pushdown: false,
|
|
4989
|
+
slice_pushdown: false,
|
|
4990
|
+
no_optimizations: nil,
|
|
4667
4991
|
schema: nil,
|
|
4668
4992
|
validate_output_schema: true,
|
|
4669
4993
|
streamable: false,
|
|
@@ -4775,7 +5099,7 @@ module Polars
|
|
|
4775
5099
|
# # │ foo ┆ 1 ┆ a ┆ true ┆ [1, 2] ┆ baz │
|
|
4776
5100
|
# # │ bar ┆ 2 ┆ b ┆ null ┆ [3] ┆ womp │
|
|
4777
5101
|
# # └────────┴─────┴─────┴──────┴───────────┴───────┘
|
|
4778
|
-
def unnest(columns, *more_columns, separator: nil)
|
|
5102
|
+
def unnest(columns = nil, *more_columns, separator: nil)
|
|
4779
5103
|
subset = Utils.parse_list_into_selector(columns) | Utils.parse_list_into_selector(
|
|
4780
5104
|
more_columns
|
|
4781
5105
|
)
|
|
@@ -4794,6 +5118,10 @@ module Polars
|
|
|
4794
5118
|
# Other DataFrame that must be merged
|
|
4795
5119
|
# @param key [String]
|
|
4796
5120
|
# Key that is sorted.
|
|
5121
|
+
# @param maintain_order [Boolean]
|
|
5122
|
+
# If `true`, the output is guaranteed to have left-biased ordering
|
|
5123
|
+
# for equal keys: rows from the left frame appear before rows from
|
|
5124
|
+
# the right frame when their keys are equal.
|
|
4797
5125
|
#
|
|
4798
5126
|
# @return [LazyFrame]
|
|
4799
5127
|
#
|
|
@@ -4820,8 +5148,8 @@ module Polars
|
|
|
4820
5148
|
# # │ steve ┆ 42 │
|
|
4821
5149
|
# # │ elise ┆ 44 │
|
|
4822
5150
|
# # └────────┴─────┘
|
|
4823
|
-
def merge_sorted(other, key)
|
|
4824
|
-
_from_rbldf(_ldf.merge_sorted(other._ldf, key))
|
|
5151
|
+
def merge_sorted(other, key, maintain_order: false)
|
|
5152
|
+
_from_rbldf(_ldf.merge_sorted(other._ldf, key, maintain_order))
|
|
4825
5153
|
end
|
|
4826
5154
|
|
|
4827
5155
|
# Flag a column as sorted.
|
|
@@ -5126,6 +5454,181 @@ module Polars
|
|
|
5126
5454
|
_from_rbldf(_ldf.count)
|
|
5127
5455
|
end
|
|
5128
5456
|
|
|
5457
|
+
# Match or evolve the schema of a LazyFrame into a specific schema.
|
|
5458
|
+
#
|
|
5459
|
+
# By default, match_to_schema returns an error if the input schema does not
|
|
5460
|
+
# exactly match the target schema. It also allows columns to be freely reordered,
|
|
5461
|
+
# with additional coercion rules available through optional parameters.
|
|
5462
|
+
#
|
|
5463
|
+
# @note
|
|
5464
|
+
# This functionality is considered **unstable**. It may be changed
|
|
5465
|
+
# at any point without it being considered a breaking change.
|
|
5466
|
+
#
|
|
5467
|
+
# @param schema [Object]
|
|
5468
|
+
# Target schema to match or evolve to.
|
|
5469
|
+
# @param missing_columns [Object]
|
|
5470
|
+
# Raise of insert missing columns from the input with respect to the `schema`.
|
|
5471
|
+
#
|
|
5472
|
+
# This can also be an expression per column with what to insert if it is
|
|
5473
|
+
# missing.
|
|
5474
|
+
# @param missing_struct_fields [Object]
|
|
5475
|
+
# Raise of insert missing struct fields from the input with respect to the
|
|
5476
|
+
# `schema`.
|
|
5477
|
+
# @param extra_columns [Object]
|
|
5478
|
+
# Raise of ignore extra columns from the input with respect to the `schema`.
|
|
5479
|
+
# @param extra_struct_fields [Object]
|
|
5480
|
+
# Raise of ignore extra struct fields from the input with respect to the
|
|
5481
|
+
# `schema`.
|
|
5482
|
+
# @param integer_cast [Object]
|
|
5483
|
+
# Forbid of upcast for integer columns from the input to the respective column
|
|
5484
|
+
# in `schema`.
|
|
5485
|
+
# @param float_cast [Object]
|
|
5486
|
+
# Forbid of upcast for float columns from the input to the respective column
|
|
5487
|
+
# in `schema`.
|
|
5488
|
+
#
|
|
5489
|
+
# @return [LazyFrame]
|
|
5490
|
+
#
|
|
5491
|
+
# @example Ensuring the schema matches
|
|
5492
|
+
# lf = Polars::LazyFrame.new({"a" => [1, 2, 3], "b" => ["A", "B", "C"]})
|
|
5493
|
+
# lf.match_to_schema({"a" => Polars::Int64, "b" => Polars::String}).collect
|
|
5494
|
+
# # =>
|
|
5495
|
+
# # shape: (3, 2)
|
|
5496
|
+
# # ┌─────┬─────┐
|
|
5497
|
+
# # │ a ┆ b │
|
|
5498
|
+
# # │ --- ┆ --- │
|
|
5499
|
+
# # │ i64 ┆ str │
|
|
5500
|
+
# # ╞═════╪═════╡
|
|
5501
|
+
# # │ 1 ┆ A │
|
|
5502
|
+
# # │ 2 ┆ B │
|
|
5503
|
+
# # │ 3 ┆ C │
|
|
5504
|
+
# # └─────┴─────┘
|
|
5505
|
+
#
|
|
5506
|
+
# @example Adding missing columns
|
|
5507
|
+
# Polars::LazyFrame.new({"a" => [1, 2, 3]})
|
|
5508
|
+
# .match_to_schema(
|
|
5509
|
+
# {"a" => Polars::Int64, "b" => Polars::String},
|
|
5510
|
+
# missing_columns: "insert"
|
|
5511
|
+
# )
|
|
5512
|
+
# .collect
|
|
5513
|
+
# # =>
|
|
5514
|
+
# # shape: (3, 2)
|
|
5515
|
+
# # ┌─────┬──────┐
|
|
5516
|
+
# # │ a ┆ b │
|
|
5517
|
+
# # │ --- ┆ --- │
|
|
5518
|
+
# # │ i64 ┆ str │
|
|
5519
|
+
# # ╞═════╪══════╡
|
|
5520
|
+
# # │ 1 ┆ null │
|
|
5521
|
+
# # │ 2 ┆ null │
|
|
5522
|
+
# # │ 3 ┆ null │
|
|
5523
|
+
# # └─────┴──────┘
|
|
5524
|
+
#
|
|
5525
|
+
# @example
|
|
5526
|
+
# Polars::LazyFrame.new({"a" => [1, 2, 3]})
|
|
5527
|
+
# .match_to_schema(
|
|
5528
|
+
# {"a" => Polars::Int64, "b" => Polars::String},
|
|
5529
|
+
# missing_columns: {"b" => Polars.col("a").cast(Polars::String)}
|
|
5530
|
+
# )
|
|
5531
|
+
# .collect
|
|
5532
|
+
# # =>
|
|
5533
|
+
# # shape: (3, 2)
|
|
5534
|
+
# # ┌─────┬─────┐
|
|
5535
|
+
# # │ a ┆ b │
|
|
5536
|
+
# # │ --- ┆ --- │
|
|
5537
|
+
# # │ i64 ┆ str │
|
|
5538
|
+
# # ╞═════╪═════╡
|
|
5539
|
+
# # │ 1 ┆ 1 │
|
|
5540
|
+
# # │ 2 ┆ 2 │
|
|
5541
|
+
# # │ 3 ┆ 3 │
|
|
5542
|
+
# # └─────┴─────┘
|
|
5543
|
+
#
|
|
5544
|
+
# @example Removing extra columns
|
|
5545
|
+
# Polars::LazyFrame.new({"a" => [1, 2, 3], "b" => ["A", "B", "C"]})
|
|
5546
|
+
# .match_to_schema(
|
|
5547
|
+
# {"a" => Polars::Int64},
|
|
5548
|
+
# extra_columns: "ignore"
|
|
5549
|
+
# )
|
|
5550
|
+
# .collect
|
|
5551
|
+
# # =>
|
|
5552
|
+
# # shape: (3, 1)
|
|
5553
|
+
# # ┌─────┐
|
|
5554
|
+
# # │ a │
|
|
5555
|
+
# # │ --- │
|
|
5556
|
+
# # │ i64 │
|
|
5557
|
+
# # ╞═════╡
|
|
5558
|
+
# # │ 1 │
|
|
5559
|
+
# # │ 2 │
|
|
5560
|
+
# # │ 3 │
|
|
5561
|
+
# # └─────┘
|
|
5562
|
+
#
|
|
5563
|
+
# @example Upcasting integers and floats
|
|
5564
|
+
# Polars::LazyFrame.new(
|
|
5565
|
+
# {"a" => [1, 2, 3], "b" => [1.0, 2.0, 3.0]},
|
|
5566
|
+
# schema: {"a" => Polars::Int32, "b" => Polars::Float32}
|
|
5567
|
+
# )
|
|
5568
|
+
# .match_to_schema(
|
|
5569
|
+
# {"a" => Polars::Int64, "b" => Polars::Float64},
|
|
5570
|
+
# integer_cast: "upcast",
|
|
5571
|
+
# float_cast: "upcast"
|
|
5572
|
+
# )
|
|
5573
|
+
# .collect
|
|
5574
|
+
# # =>
|
|
5575
|
+
# # shape: (3, 2)
|
|
5576
|
+
# # ┌─────┬─────┐
|
|
5577
|
+
# # │ a ┆ b │
|
|
5578
|
+
# # │ --- ┆ --- │
|
|
5579
|
+
# # │ i64 ┆ f64 │
|
|
5580
|
+
# # ╞═════╪═════╡
|
|
5581
|
+
# # │ 1 ┆ 1.0 │
|
|
5582
|
+
# # │ 2 ┆ 2.0 │
|
|
5583
|
+
# # │ 3 ┆ 3.0 │
|
|
5584
|
+
# # └─────┴─────┘
|
|
5585
|
+
def match_to_schema(
|
|
5586
|
+
schema,
|
|
5587
|
+
missing_columns: "raise",
|
|
5588
|
+
missing_struct_fields: "raise",
|
|
5589
|
+
extra_columns: "raise",
|
|
5590
|
+
extra_struct_fields: "raise",
|
|
5591
|
+
integer_cast: "forbid",
|
|
5592
|
+
float_cast: "forbid"
|
|
5593
|
+
)
|
|
5594
|
+
prepare_missing_columns = lambda do |value|
|
|
5595
|
+
if value.is_a?(Expr)
|
|
5596
|
+
value._rbexpr
|
|
5597
|
+
else
|
|
5598
|
+
value
|
|
5599
|
+
end
|
|
5600
|
+
end
|
|
5601
|
+
|
|
5602
|
+
if schema.is_a?(Hash)
|
|
5603
|
+
schema_prep = Schema.new(schema)
|
|
5604
|
+
else
|
|
5605
|
+
schema_prep = schema
|
|
5606
|
+
end
|
|
5607
|
+
|
|
5608
|
+
if missing_columns.is_a?(Hash)
|
|
5609
|
+
missing_columns_rbexpr =
|
|
5610
|
+
missing_columns.to_h do |key, value|
|
|
5611
|
+
[key.to_s, prepare_missing_columns.(value)]
|
|
5612
|
+
end
|
|
5613
|
+
elsif missing_columns.is_a?(Expr)
|
|
5614
|
+
missing_columns_rbexpr = prepare_missing_columns.(missing_columns)
|
|
5615
|
+
else
|
|
5616
|
+
missing_columns_rbexpr = missing_columns
|
|
5617
|
+
end
|
|
5618
|
+
|
|
5619
|
+
LazyFrame._from_rbldf(
|
|
5620
|
+
_ldf.match_to_schema(
|
|
5621
|
+
schema_prep,
|
|
5622
|
+
missing_columns_rbexpr,
|
|
5623
|
+
missing_struct_fields,
|
|
5624
|
+
extra_columns,
|
|
5625
|
+
extra_struct_fields,
|
|
5626
|
+
integer_cast,
|
|
5627
|
+
float_cast
|
|
5628
|
+
)
|
|
5629
|
+
)
|
|
5630
|
+
end
|
|
5631
|
+
|
|
5129
5632
|
private
|
|
5130
5633
|
|
|
5131
5634
|
def initialize_copy(other)
|