polars-df 0.25.1 → 0.26.1
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 +32 -1
- data/Cargo.lock +278 -106
- data/Cargo.toml +0 -3
- data/LICENSE.txt +1 -1
- data/README.md +7 -3
- data/ext/polars/Cargo.toml +18 -18
- data/ext/polars/src/catalog/unity.rs +15 -20
- data/ext/polars/src/conversion/any_value.rs +25 -24
- 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 +205 -142
- data/ext/polars/src/dataframe/export.rs +15 -12
- data/ext/polars/src/dataframe/general.rs +5 -4
- 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 +3 -2
- data/ext/polars/src/expr/datetime.rs +4 -4
- data/ext/polars/src/expr/general.rs +27 -15
- data/ext/polars/src/expr/list.rs +0 -26
- 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 +58 -46
- data/ext/polars/src/functions/meta.rs +6 -5
- data/ext/polars/src/functions/mod.rs +0 -1
- 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 +17 -12
- 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 +32 -16
- data/ext/polars/src/lazyframe/optflags.rs +2 -1
- data/ext/polars/src/lib.rs +21 -37
- 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 +16 -7
- data/ext/polars/src/ruby/capsule.rs +27 -0
- data/ext/polars/src/ruby/mod.rs +1 -0
- data/ext/polars/src/ruby/numo.rs +3 -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/export.rs +38 -38
- data/ext/polars/src/series/general.rs +4 -3
- 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/data_frame.rb +83 -11
- data/lib/polars/date_time_expr.rb +91 -3
- data/lib/polars/date_time_name_space.rb +7 -1
- data/lib/polars/expr.rb +122 -44
- data/lib/polars/functions/aggregation/horizontal.rb +4 -4
- data/lib/polars/functions/business.rb +2 -2
- data/lib/polars/functions/eager.rb +80 -7
- data/lib/polars/functions/lazy.rb +5 -2
- data/lib/polars/iceberg_dataset.rb +81 -14
- data/lib/polars/io/csv.rb +27 -5
- data/lib/polars/io/delta.rb +4 -0
- data/lib/polars/io/ipc.rb +1 -1
- data/lib/polars/io/lines.rb +4 -4
- data/lib/polars/io/sink_options.rb +4 -2
- data/lib/polars/lazy_frame.rb +97 -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 +22 -5
- data/lib/polars/schema.rb +9 -0
- data/lib/polars/selectors.rb +1 -1
- data/lib/polars/series.rb +106 -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 +8 -3
- 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 +5 -1
- metadata +4 -17
- data/ext/polars/src/functions/string_cache.rs +0 -24
|
@@ -226,6 +226,38 @@ module Polars
|
|
|
226
226
|
super
|
|
227
227
|
end
|
|
228
228
|
|
|
229
|
+
# Get the byte value at the given index.
|
|
230
|
+
#
|
|
231
|
+
# For example, index `0` would return the first byte of every binary value
|
|
232
|
+
# and index `-1` would return the last byte of every binary value.
|
|
233
|
+
# The behavior if an index is out of bounds is determined by the argument
|
|
234
|
+
# `null_on_oob`.
|
|
235
|
+
#
|
|
236
|
+
# @param index [Object]
|
|
237
|
+
# Index to return per binary value
|
|
238
|
+
# @param null_on_oob [Boolean]
|
|
239
|
+
# Behavior if an index is out of bounds:
|
|
240
|
+
#
|
|
241
|
+
# * true -> set as null
|
|
242
|
+
# * false -> raise an error
|
|
243
|
+
#
|
|
244
|
+
# @return [Series]
|
|
245
|
+
#
|
|
246
|
+
# @example
|
|
247
|
+
# s = Polars::Series.new("a", ["\x01\x02\x03".b, "".b, "\x04\x05".b])
|
|
248
|
+
# s.bin.get(0, null_on_oob: true)
|
|
249
|
+
# # =>
|
|
250
|
+
# # shape: (3,)
|
|
251
|
+
# # Series: 'a' [u8]
|
|
252
|
+
# # [
|
|
253
|
+
# # 1
|
|
254
|
+
# # null
|
|
255
|
+
# # 4
|
|
256
|
+
# # ]
|
|
257
|
+
def get(index, null_on_oob: false)
|
|
258
|
+
super
|
|
259
|
+
end
|
|
260
|
+
|
|
229
261
|
# Take the first `n` bytes of the binary values.
|
|
230
262
|
#
|
|
231
263
|
# @param n [Object]
|
data/lib/polars/data_frame.rb
CHANGED
|
@@ -771,7 +771,14 @@ module Polars
|
|
|
771
771
|
s.get_index_signed(row)
|
|
772
772
|
end
|
|
773
773
|
|
|
774
|
-
#
|
|
774
|
+
# Collect the underlying arrow arrays in an Arrow Table.
|
|
775
|
+
#
|
|
776
|
+
# @return [Nanoarrow::Array]
|
|
777
|
+
def to_arrow
|
|
778
|
+
require "nanoarrow"
|
|
779
|
+
|
|
780
|
+
Nanoarrow::Array.new(self)
|
|
781
|
+
end
|
|
775
782
|
|
|
776
783
|
# Convert DataFrame to a hash mapping column name to values.
|
|
777
784
|
#
|
|
@@ -810,6 +817,8 @@ module Polars
|
|
|
810
817
|
# df.to_numo.class
|
|
811
818
|
# # => Numo::RObject
|
|
812
819
|
def to_numo
|
|
820
|
+
require "numo/narray"
|
|
821
|
+
|
|
813
822
|
out = _df.to_numo
|
|
814
823
|
if out.nil?
|
|
815
824
|
Numo::NArray.vstack(width.times.map { |i| to_series(i).to_numo }).transpose
|
|
@@ -3808,6 +3817,57 @@ module Polars
|
|
|
3808
3817
|
.collect(optimizations: QueryOptFlags._eager)
|
|
3809
3818
|
end
|
|
3810
3819
|
|
|
3820
|
+
# Selects rows from this DataFrame at the given indices.
|
|
3821
|
+
#
|
|
3822
|
+
# @note
|
|
3823
|
+
# This functionality is experimental. It may be
|
|
3824
|
+
# changed at any point without it being considered a breaking change.
|
|
3825
|
+
#
|
|
3826
|
+
# @param indices [Object]
|
|
3827
|
+
# The indices of the rows to select.
|
|
3828
|
+
# @param null_on_oob [Boolean]
|
|
3829
|
+
# If true when an index is out-of-bounds a null row will be generated
|
|
3830
|
+
# instead of raising an error.
|
|
3831
|
+
#
|
|
3832
|
+
# @return [DataFrame]
|
|
3833
|
+
#
|
|
3834
|
+
# @example
|
|
3835
|
+
# df = Polars::DataFrame.new({"x" => [2, 1, 0], "s" => ["foo", "bar", "baz"]})
|
|
3836
|
+
# df.gather([2, 0, 0])
|
|
3837
|
+
# # =>
|
|
3838
|
+
# # shape: (3, 2)
|
|
3839
|
+
# # ┌─────┬─────┐
|
|
3840
|
+
# # │ x ┆ s │
|
|
3841
|
+
# # │ --- ┆ --- │
|
|
3842
|
+
# # │ i64 ┆ str │
|
|
3843
|
+
# # ╞═════╪═════╡
|
|
3844
|
+
# # │ 0 ┆ baz │
|
|
3845
|
+
# # │ 2 ┆ foo │
|
|
3846
|
+
# # │ 2 ┆ foo │
|
|
3847
|
+
# # └─────┴─────┘
|
|
3848
|
+
#
|
|
3849
|
+
# @example
|
|
3850
|
+
# df.gather([0, 10, 1], null_on_oob: true)
|
|
3851
|
+
# # =>
|
|
3852
|
+
# # shape: (3, 2)
|
|
3853
|
+
# # ┌──────┬──────┐
|
|
3854
|
+
# # │ x ┆ s │
|
|
3855
|
+
# # │ --- ┆ --- │
|
|
3856
|
+
# # │ i64 ┆ str │
|
|
3857
|
+
# # ╞══════╪══════╡
|
|
3858
|
+
# # │ 2 ┆ foo │
|
|
3859
|
+
# # │ null ┆ null │
|
|
3860
|
+
# # │ 1 ┆ bar │
|
|
3861
|
+
# # └──────┴──────┘
|
|
3862
|
+
def gather(
|
|
3863
|
+
indices,
|
|
3864
|
+
null_on_oob: false
|
|
3865
|
+
)
|
|
3866
|
+
lazy
|
|
3867
|
+
.gather(indices, null_on_oob: null_on_oob)
|
|
3868
|
+
.collect(optimizations: QueryOptFlags._eager)
|
|
3869
|
+
end
|
|
3870
|
+
|
|
3811
3871
|
# Apply a custom/user-defined function (UDF) over the rows of the DataFrame.
|
|
3812
3872
|
#
|
|
3813
3873
|
# The UDF will receive each row as a tuple of values: `udf(row)`.
|
|
@@ -4527,6 +4587,8 @@ module Polars
|
|
|
4527
4587
|
# @param separator [String]
|
|
4528
4588
|
# Used as separator/delimiter in generated column names in case of multiple
|
|
4529
4589
|
# `values` columns.
|
|
4590
|
+
# @param column_naming ['auto', 'combine']
|
|
4591
|
+
# How resulting column names will be constructed.
|
|
4530
4592
|
#
|
|
4531
4593
|
# @return [DataFrame]
|
|
4532
4594
|
#
|
|
@@ -4557,7 +4619,8 @@ module Polars
|
|
|
4557
4619
|
aggregate_function: nil,
|
|
4558
4620
|
maintain_order: true,
|
|
4559
4621
|
sort_columns: false,
|
|
4560
|
-
separator: "_"
|
|
4622
|
+
separator: "_",
|
|
4623
|
+
column_naming: "auto"
|
|
4561
4624
|
)
|
|
4562
4625
|
if on_columns.nil?
|
|
4563
4626
|
cols = select(on).unique(maintain_order: true)
|
|
@@ -4577,7 +4640,8 @@ module Polars
|
|
|
4577
4640
|
values: values,
|
|
4578
4641
|
aggregate_function: aggregate_function,
|
|
4579
4642
|
maintain_order: maintain_order,
|
|
4580
|
-
separator: separator
|
|
4643
|
+
separator: separator,
|
|
4644
|
+
column_naming: column_naming
|
|
4581
4645
|
)
|
|
4582
4646
|
.collect(optimizations: QueryOptFlags._eager)
|
|
4583
4647
|
end
|
|
@@ -4593,7 +4657,8 @@ module Polars
|
|
|
4593
4657
|
#
|
|
4594
4658
|
# @param on [Object]
|
|
4595
4659
|
# Column(s) or selector(s) to use as values variables; if `on`
|
|
4596
|
-
# is empty
|
|
4660
|
+
# is empty no columns will be used. If set to `nil` (default)
|
|
4661
|
+
# all columns that are not in `index` will be used.
|
|
4597
4662
|
# @param index [Object]
|
|
4598
4663
|
# Column(s) or selector(s) to use as identifier variables.
|
|
4599
4664
|
# @param variable_name [Object]
|
|
@@ -4627,7 +4692,7 @@ module Polars
|
|
|
4627
4692
|
# # │ z ┆ c ┆ 6 │
|
|
4628
4693
|
# # └─────┴──────────┴───────┘
|
|
4629
4694
|
def unpivot(on = nil, index: nil, variable_name: nil, value_name: nil)
|
|
4630
|
-
on = on.nil? ?
|
|
4695
|
+
on = on.nil? ? nil : Utils._expand_selectors(self, on)
|
|
4631
4696
|
index = index.nil? ? [] : Utils._expand_selectors(self, index)
|
|
4632
4697
|
|
|
4633
4698
|
_from_rbdf(_df.unpivot(on, index, value_name, variable_name))
|
|
@@ -6488,7 +6553,7 @@ module Polars
|
|
|
6488
6553
|
# # │ foo ┆ 1 ┆ a ┆ true ┆ [1, 2] ┆ baz │
|
|
6489
6554
|
# # │ bar ┆ 2 ┆ b ┆ null ┆ [3] ┆ womp │
|
|
6490
6555
|
# # └────────┴─────┴─────┴──────┴───────────┴───────┘
|
|
6491
|
-
def unnest(columns, *more_columns, separator: nil)
|
|
6556
|
+
def unnest(columns = nil, *more_columns, separator: nil)
|
|
6492
6557
|
lazy.unnest(columns, *more_columns, separator: separator).collect(optimizations: QueryOptFlags._eager)
|
|
6493
6558
|
end
|
|
6494
6559
|
|
|
@@ -6504,6 +6569,10 @@ module Polars
|
|
|
6504
6569
|
# Other DataFrame that must be merged
|
|
6505
6570
|
# @param key [String]
|
|
6506
6571
|
# Key that is sorted.
|
|
6572
|
+
# @param maintain_order [Boolean]
|
|
6573
|
+
# If `true`, the output is guaranteed to have left-biased ordering
|
|
6574
|
+
# for equal keys: rows from the left frame appear before rows from
|
|
6575
|
+
# the right frame when their keys are equal.
|
|
6507
6576
|
#
|
|
6508
6577
|
# @return [DataFrame]
|
|
6509
6578
|
#
|
|
@@ -6530,8 +6599,8 @@ module Polars
|
|
|
6530
6599
|
# # │ steve ┆ 42 │
|
|
6531
6600
|
# # │ elise ┆ 44 │
|
|
6532
6601
|
# # └────────┴─────┘
|
|
6533
|
-
def merge_sorted(other, key)
|
|
6534
|
-
lazy.merge_sorted(other.lazy, key).collect(optimizations: QueryOptFlags._eager)
|
|
6602
|
+
def merge_sorted(other, key, maintain_order: false)
|
|
6603
|
+
lazy.merge_sorted(other.lazy, key, maintain_order: maintain_order).collect(optimizations: QueryOptFlags._eager)
|
|
6535
6604
|
end
|
|
6536
6605
|
|
|
6537
6606
|
# Flag a column as sorted.
|
|
@@ -6545,14 +6614,17 @@ module Polars
|
|
|
6545
6614
|
# Column that is sorted.
|
|
6546
6615
|
# @param descending [Boolean]
|
|
6547
6616
|
# Whether the column is sorted in descending order.
|
|
6617
|
+
# @param nulls_last [Boolean]
|
|
6618
|
+
# Whether the nulls are at the end.
|
|
6548
6619
|
#
|
|
6549
6620
|
# @return [DataFrame]
|
|
6550
6621
|
def set_sorted(
|
|
6551
6622
|
column,
|
|
6552
|
-
descending: false
|
|
6623
|
+
descending: false,
|
|
6624
|
+
nulls_last: false
|
|
6553
6625
|
)
|
|
6554
6626
|
lazy
|
|
6555
|
-
.set_sorted(column, descending: descending)
|
|
6627
|
+
.set_sorted(column, descending: descending, nulls_last: nulls_last)
|
|
6556
6628
|
.collect(optimizations: QueryOptFlags._eager)
|
|
6557
6629
|
end
|
|
6558
6630
|
|
|
@@ -7111,7 +7183,7 @@ module Polars
|
|
|
7111
7183
|
end
|
|
7112
7184
|
|
|
7113
7185
|
def _select_rows_by_slice(df, key)
|
|
7114
|
-
|
|
7186
|
+
Slice.new(df).apply(key)
|
|
7115
7187
|
end
|
|
7116
7188
|
|
|
7117
7189
|
def _select_rows_by_index(df, key)
|
|
@@ -22,6 +22,8 @@ module Polars
|
|
|
22
22
|
# Which days of the week to count. The default is Monday to Friday.
|
|
23
23
|
# If you wanted to count only Monday to Thursday, you would pass
|
|
24
24
|
# `[true, true, true, true, false, false, false]`.
|
|
25
|
+
# @param holidays [Object]
|
|
26
|
+
# Holidays to exclude from the count.
|
|
25
27
|
# @param roll
|
|
26
28
|
# What to do when the start date lands on a non-business day. Options are:
|
|
27
29
|
#
|
|
@@ -44,17 +46,67 @@ module Polars
|
|
|
44
46
|
# # │ 2020-01-01 ┆ 2020-01-08 │
|
|
45
47
|
# # │ 2020-01-02 ┆ 2020-01-09 │
|
|
46
48
|
# # └────────────┴────────────┘
|
|
49
|
+
#
|
|
50
|
+
# @example You can pass a custom weekend - for example, if you only take Sunday off:
|
|
51
|
+
# week_mask = [true, true, true, true, true, true, false]
|
|
52
|
+
# df.with_columns(
|
|
53
|
+
# result: Polars.col("start").dt.add_business_days(5, week_mask: week_mask)
|
|
54
|
+
# )
|
|
55
|
+
# # =>
|
|
56
|
+
# # shape: (2, 2)
|
|
57
|
+
# # ┌────────────┬────────────┐
|
|
58
|
+
# # │ start ┆ result │
|
|
59
|
+
# # │ --- ┆ --- │
|
|
60
|
+
# # │ date ┆ date │
|
|
61
|
+
# # ╞════════════╪════════════╡
|
|
62
|
+
# # │ 2020-01-01 ┆ 2020-01-07 │
|
|
63
|
+
# # │ 2020-01-02 ┆ 2020-01-08 │
|
|
64
|
+
# # └────────────┴────────────┘
|
|
65
|
+
#
|
|
66
|
+
# @example You can also pass a list of holidays:
|
|
67
|
+
# holidays = [Date.new(2020, 1, 3), Date.new(2020, 1, 6)]
|
|
68
|
+
# df.with_columns(
|
|
69
|
+
# result: Polars.col("start").dt.add_business_days(5, holidays: holidays)
|
|
70
|
+
# )
|
|
71
|
+
# # =>
|
|
72
|
+
# # shape: (2, 2)
|
|
73
|
+
# # ┌────────────┬────────────┐
|
|
74
|
+
# # │ start ┆ result │
|
|
75
|
+
# # │ --- ┆ --- │
|
|
76
|
+
# # │ date ┆ date │
|
|
77
|
+
# # ╞════════════╪════════════╡
|
|
78
|
+
# # │ 2020-01-01 ┆ 2020-01-10 │
|
|
79
|
+
# # │ 2020-01-02 ┆ 2020-01-13 │
|
|
80
|
+
# # └────────────┴────────────┘
|
|
81
|
+
#
|
|
82
|
+
# @example Roll all dates forwards to the next business day:
|
|
83
|
+
# df = Polars::DataFrame.new({"start" => [Date.new(2020, 1, 5), Date.new(2020, 1, 6)]})
|
|
84
|
+
# df.with_columns(
|
|
85
|
+
# rolled_forwards: Polars.col("start").dt.add_business_days(0, roll: "forward")
|
|
86
|
+
# )
|
|
87
|
+
# # =>
|
|
88
|
+
# # shape: (2, 2)
|
|
89
|
+
# # ┌────────────┬─────────────────┐
|
|
90
|
+
# # │ start ┆ rolled_forwards │
|
|
91
|
+
# # │ --- ┆ --- │
|
|
92
|
+
# # │ date ┆ date │
|
|
93
|
+
# # ╞════════════╪═════════════════╡
|
|
94
|
+
# # │ 2020-01-05 ┆ 2020-01-06 │
|
|
95
|
+
# # │ 2020-01-06 ┆ 2020-01-06 │
|
|
96
|
+
# # └────────────┴─────────────────┘
|
|
47
97
|
def add_business_days(
|
|
48
98
|
n,
|
|
49
99
|
week_mask: [true, true, true, true, true, false, false],
|
|
100
|
+
holidays: [],
|
|
50
101
|
roll: "raise"
|
|
51
102
|
)
|
|
52
103
|
n_rbexpr = Utils.parse_into_expression(n)
|
|
104
|
+
holidays_rbexpr = Utils._holidays_to_expr(holidays)
|
|
53
105
|
Utils.wrap_expr(
|
|
54
106
|
_rbexpr.dt_add_business_days(
|
|
55
107
|
n_rbexpr,
|
|
56
108
|
week_mask,
|
|
57
|
-
|
|
109
|
+
holidays_rbexpr,
|
|
58
110
|
roll
|
|
59
111
|
)
|
|
60
112
|
)
|
|
@@ -580,6 +632,8 @@ module Polars
|
|
|
580
632
|
# Which days of the week to count. The default is Monday to Friday.
|
|
581
633
|
# If you wanted to count only Monday to Thursday, you would pass
|
|
582
634
|
# `[true, true, true, true, false, false, false]`.
|
|
635
|
+
# @param holidays [Object]
|
|
636
|
+
# Holidays to exclude from the count.
|
|
583
637
|
#
|
|
584
638
|
# @return [Expr]
|
|
585
639
|
#
|
|
@@ -596,13 +650,47 @@ module Polars
|
|
|
596
650
|
# # │ 2020-01-03 ┆ true │
|
|
597
651
|
# # │ 2020-01-05 ┆ false │
|
|
598
652
|
# # └────────────┴─────────────────┘
|
|
653
|
+
#
|
|
654
|
+
# @example You can pass a custom weekend - for example, if you only take Sunday off:
|
|
655
|
+
# week_mask = [true, true, true, true, true, true, false]
|
|
656
|
+
# df.with_columns(
|
|
657
|
+
# is_business_day: Polars.col("start").dt.is_business_day(week_mask: week_mask)
|
|
658
|
+
# )
|
|
659
|
+
# # =>
|
|
660
|
+
# # shape: (2, 2)
|
|
661
|
+
# # ┌────────────┬─────────────────┐
|
|
662
|
+
# # │ start ┆ is_business_day │
|
|
663
|
+
# # │ --- ┆ --- │
|
|
664
|
+
# # │ date ┆ bool │
|
|
665
|
+
# # ╞════════════╪═════════════════╡
|
|
666
|
+
# # │ 2020-01-03 ┆ true │
|
|
667
|
+
# # │ 2020-01-05 ┆ false │
|
|
668
|
+
# # └────────────┴─────────────────┘
|
|
669
|
+
#
|
|
670
|
+
# @example You can also pass a list of holidays:
|
|
671
|
+
# holidays = [Date.new(2020, 1, 3), Date.new(2020, 1, 6)]
|
|
672
|
+
# df.with_columns(
|
|
673
|
+
# is_business_day: Polars.col("start").dt.is_business_day(holidays: holidays)
|
|
674
|
+
# )
|
|
675
|
+
# # =>
|
|
676
|
+
# # shape: (2, 2)
|
|
677
|
+
# # ┌────────────┬─────────────────┐
|
|
678
|
+
# # │ start ┆ is_business_day │
|
|
679
|
+
# # │ --- ┆ --- │
|
|
680
|
+
# # │ date ┆ bool │
|
|
681
|
+
# # ╞════════════╪═════════════════╡
|
|
682
|
+
# # │ 2020-01-03 ┆ false │
|
|
683
|
+
# # │ 2020-01-05 ┆ false │
|
|
684
|
+
# # └────────────┴─────────────────┘
|
|
599
685
|
def is_business_day(
|
|
600
|
-
week_mask: [true, true, true, true, true, false, false]
|
|
686
|
+
week_mask: [true, true, true, true, true, false, false],
|
|
687
|
+
holidays: []
|
|
601
688
|
)
|
|
689
|
+
holidays_rbexpr = Utils._holidays_to_expr(holidays)
|
|
602
690
|
Utils.wrap_expr(
|
|
603
691
|
_rbexpr.dt_is_business_day(
|
|
604
692
|
week_mask,
|
|
605
|
-
|
|
693
|
+
holidays_rbexpr
|
|
606
694
|
)
|
|
607
695
|
)
|
|
608
696
|
end
|
|
@@ -31,6 +31,8 @@ module Polars
|
|
|
31
31
|
# Which days of the week to count. The default is Monday to Friday.
|
|
32
32
|
# If you wanted to count only Monday to Thursday, you would pass
|
|
33
33
|
# `[true, true, true, true, false, false, false]`.
|
|
34
|
+
# @param holidays [Object]
|
|
35
|
+
# Holidays to exclude from the count.
|
|
34
36
|
# roll
|
|
35
37
|
# What to do when the start date lands on a non-business day. Options are:
|
|
36
38
|
#
|
|
@@ -75,6 +77,7 @@ module Polars
|
|
|
75
77
|
def add_business_days(
|
|
76
78
|
n,
|
|
77
79
|
week_mask: [true, true, true, true, true, false, false],
|
|
80
|
+
holidays: [],
|
|
78
81
|
roll: "raise"
|
|
79
82
|
)
|
|
80
83
|
super
|
|
@@ -263,6 +266,8 @@ module Polars
|
|
|
263
266
|
# Which days of the week to count. The default is Monday to Friday.
|
|
264
267
|
# If you wanted to count only Monday to Thursday, you would pass
|
|
265
268
|
# `[true, true, true, true, false, false, false]`.
|
|
269
|
+
# @param holidays [Object]
|
|
270
|
+
# Holidays to exclude from the count.
|
|
266
271
|
#
|
|
267
272
|
# @return [Series]
|
|
268
273
|
#
|
|
@@ -288,7 +293,8 @@ module Polars
|
|
|
288
293
|
# # false
|
|
289
294
|
# # ]
|
|
290
295
|
def is_business_day(
|
|
291
|
-
week_mask: [true, true, true, true, true, false, false]
|
|
296
|
+
week_mask: [true, true, true, true, true, false, false],
|
|
297
|
+
holidays: []
|
|
292
298
|
)
|
|
293
299
|
super
|
|
294
300
|
end
|
data/lib/polars/expr.rb
CHANGED
|
@@ -252,6 +252,38 @@ module Polars
|
|
|
252
252
|
wrap_expr(_rbexpr.all(ignore_nulls))
|
|
253
253
|
end
|
|
254
254
|
|
|
255
|
+
# Return whether the column is empty.
|
|
256
|
+
#
|
|
257
|
+
# @note
|
|
258
|
+
# This functionality is considered **unstable**. It may be changed
|
|
259
|
+
# at any point without it being considered a breaking change.
|
|
260
|
+
#
|
|
261
|
+
# @param ignore_nulls [Boolean]
|
|
262
|
+
# If true a column containing only nulls will also be considered empty.
|
|
263
|
+
# The default is false.
|
|
264
|
+
#
|
|
265
|
+
# @return [Expr]
|
|
266
|
+
#
|
|
267
|
+
# @example
|
|
268
|
+
# df = Polars::DataFrame.new({"x" => [nil, nil]})
|
|
269
|
+
# df.select(
|
|
270
|
+
# a: Polars.col("x").is_empty,
|
|
271
|
+
# b: Polars.col("x").drop_nulls.is_empty,
|
|
272
|
+
# c: Polars.col("x").is_empty(ignore_nulls: true)
|
|
273
|
+
# )
|
|
274
|
+
# # =>
|
|
275
|
+
# # shape: (1, 3)
|
|
276
|
+
# # ┌───────┬──────┬──────┐
|
|
277
|
+
# # │ a ┆ b ┆ c │
|
|
278
|
+
# # │ --- ┆ --- ┆ --- │
|
|
279
|
+
# # │ bool ┆ bool ┆ bool │
|
|
280
|
+
# # ╞═══════╪══════╪══════╡
|
|
281
|
+
# # │ false ┆ true ┆ true │
|
|
282
|
+
# # └───────┴──────┴──────┘
|
|
283
|
+
def is_empty(ignore_nulls: false)
|
|
284
|
+
wrap_expr(_rbexpr.is_empty(ignore_nulls))
|
|
285
|
+
end
|
|
286
|
+
|
|
255
287
|
# Return indices where expression evaluates `true`.
|
|
256
288
|
#
|
|
257
289
|
# @return [Expr]
|
|
@@ -1204,6 +1236,49 @@ module Polars
|
|
|
1204
1236
|
wrap_expr(_rbexpr.round_sig_figs(digits))
|
|
1205
1237
|
end
|
|
1206
1238
|
|
|
1239
|
+
# Truncate numeric data toward zero to `decimals` number of decimal places.
|
|
1240
|
+
#
|
|
1241
|
+
# @param decimals [Integer]
|
|
1242
|
+
# Number of decimal places to truncate to.
|
|
1243
|
+
#
|
|
1244
|
+
# @return [Expr]
|
|
1245
|
+
#
|
|
1246
|
+
# @note
|
|
1247
|
+
# Truncation discards the fractional part beyond the given number of decimals.
|
|
1248
|
+
# For example, when rounding to 0 decimals 0.25, -0.25, 0.99, and -0.99 will
|
|
1249
|
+
# all round to 0. When rounding to 1 decimal 1.9999 rounds to 1.9 and -1.9999
|
|
1250
|
+
# rounds to -1.9. There is no tiebreak behaviour at midpoint values as there
|
|
1251
|
+
# is with :meth:`round` so 0.5 and -0.5 will also round to 0 when decimals=1.
|
|
1252
|
+
#
|
|
1253
|
+
# @note
|
|
1254
|
+
# This method performs numeric truncation. For truncating temporal
|
|
1255
|
+
# data (dates/datetimes), use :func:`Expr.dt.truncate` instead.
|
|
1256
|
+
#
|
|
1257
|
+
# @example
|
|
1258
|
+
# df = Polars::DataFrame.new({"n" => [-9.9999, 0.12345, 1.0251, 8.8765]})
|
|
1259
|
+
# df.with_columns(
|
|
1260
|
+
# t0: Polars.col("n").truncate(0),
|
|
1261
|
+
# t1: Polars.col("n").truncate(1),
|
|
1262
|
+
# t2: Polars.col("n").truncate(2),
|
|
1263
|
+
# t3: Polars.col("n").truncate(3),
|
|
1264
|
+
# t4: Polars.col("n").truncate(4)
|
|
1265
|
+
# )
|
|
1266
|
+
# # =>
|
|
1267
|
+
# # shape: (4, 6)
|
|
1268
|
+
# # ┌─────────┬──────┬──────┬───────┬────────┬─────────┐
|
|
1269
|
+
# # │ n ┆ t0 ┆ t1 ┆ t2 ┆ t3 ┆ t4 │
|
|
1270
|
+
# # │ --- ┆ --- ┆ --- ┆ --- ┆ --- ┆ --- │
|
|
1271
|
+
# # │ f64 ┆ f64 ┆ f64 ┆ f64 ┆ f64 ┆ f64 │
|
|
1272
|
+
# # ╞═════════╪══════╪══════╪═══════╪════════╪═════════╡
|
|
1273
|
+
# # │ -9.9999 ┆ -9.0 ┆ -9.9 ┆ -9.99 ┆ -9.999 ┆ -9.9999 │
|
|
1274
|
+
# # │ 0.12345 ┆ 0.0 ┆ 0.1 ┆ 0.12 ┆ 0.123 ┆ 0.1234 │
|
|
1275
|
+
# # │ 1.0251 ┆ 1.0 ┆ 1.0 ┆ 1.02 ┆ 1.025 ┆ 1.025 │
|
|
1276
|
+
# # │ 8.8765 ┆ 8.0 ┆ 8.8 ┆ 8.87 ┆ 8.876 ┆ 8.8765 │
|
|
1277
|
+
# # └─────────┴──────┴──────┴───────┴────────┴─────────┘
|
|
1278
|
+
def truncate(decimals = 0)
|
|
1279
|
+
Utils.wrap_expr(_rbexpr.truncate(decimals))
|
|
1280
|
+
end
|
|
1281
|
+
|
|
1207
1282
|
# Compute the dot/inner product between two Expressions.
|
|
1208
1283
|
#
|
|
1209
1284
|
# @param other [Expr]
|
|
@@ -1887,6 +1962,11 @@ module Polars
|
|
|
1887
1962
|
#
|
|
1888
1963
|
# @param indices [Expr]
|
|
1889
1964
|
# An expression that leads to a `:u32` dtyped Series.
|
|
1965
|
+
# @param null_on_oob [Boolean]
|
|
1966
|
+
# Behavior if an index is out of bounds:
|
|
1967
|
+
#
|
|
1968
|
+
# - true -> set the result to null
|
|
1969
|
+
# - false -> raise an error
|
|
1890
1970
|
#
|
|
1891
1971
|
# @return [Expr]
|
|
1892
1972
|
#
|
|
@@ -1915,13 +1995,13 @@ module Polars
|
|
|
1915
1995
|
# # │ one ┆ [2, 98] │
|
|
1916
1996
|
# # │ two ┆ [4, 99] │
|
|
1917
1997
|
# # └───────┴───────────┘
|
|
1918
|
-
def gather(indices)
|
|
1998
|
+
def gather(indices, null_on_oob: false)
|
|
1919
1999
|
if indices.is_a?(::Array)
|
|
1920
2000
|
indices_lit_rbexpr = Polars.lit(Series.new("", indices, dtype: Int64))._rbexpr
|
|
1921
2001
|
else
|
|
1922
2002
|
indices_lit_rbexpr = Utils.parse_into_expression(indices)
|
|
1923
2003
|
end
|
|
1924
|
-
wrap_expr(_rbexpr.gather(indices_lit_rbexpr))
|
|
2004
|
+
wrap_expr(_rbexpr.gather(indices_lit_rbexpr, null_on_oob))
|
|
1925
2005
|
end
|
|
1926
2006
|
|
|
1927
2007
|
# Return a single value by index.
|
|
@@ -3195,17 +3275,17 @@ module Polars
|
|
|
3195
3275
|
# )
|
|
3196
3276
|
# # =>
|
|
3197
3277
|
# # shape: (5, 2)
|
|
3198
|
-
# #
|
|
3199
|
-
# # │ foo ┆ cut
|
|
3200
|
-
# # │ --- ┆ ---
|
|
3201
|
-
# # │ i64 ┆
|
|
3202
|
-
# #
|
|
3203
|
-
# # │ -2 ┆ a
|
|
3204
|
-
# # │ -1 ┆ a
|
|
3205
|
-
# # │ 0 ┆ b
|
|
3206
|
-
# # │ 1 ┆ b
|
|
3207
|
-
# # │ 2 ┆ c
|
|
3208
|
-
# #
|
|
3278
|
+
# # ┌─────┬──────┐
|
|
3279
|
+
# # │ foo ┆ cut │
|
|
3280
|
+
# # │ --- ┆ --- │
|
|
3281
|
+
# # │ i64 ┆ enum │
|
|
3282
|
+
# # ╞═════╪══════╡
|
|
3283
|
+
# # │ -2 ┆ a │
|
|
3284
|
+
# # │ -1 ┆ a │
|
|
3285
|
+
# # │ 0 ┆ b │
|
|
3286
|
+
# # │ 1 ┆ b │
|
|
3287
|
+
# # │ 2 ┆ c │
|
|
3288
|
+
# # └─────┴──────┘
|
|
3209
3289
|
#
|
|
3210
3290
|
# @example Add both the category and the breakpoint.
|
|
3211
3291
|
# df.with_columns(
|
|
@@ -3216,7 +3296,7 @@ module Polars
|
|
|
3216
3296
|
# # ┌─────┬────────────┬────────────┐
|
|
3217
3297
|
# # │ foo ┆ breakpoint ┆ category │
|
|
3218
3298
|
# # │ --- ┆ --- ┆ --- │
|
|
3219
|
-
# # │ i64 ┆ f64 ┆
|
|
3299
|
+
# # │ i64 ┆ f64 ┆ enum │
|
|
3220
3300
|
# # ╞═════╪════════════╪════════════╡
|
|
3221
3301
|
# # │ -2 ┆ -1.0 ┆ (-inf, -1] │
|
|
3222
3302
|
# # │ -1 ┆ -1.0 ┆ (-inf, -1] │
|
|
@@ -4566,13 +4646,18 @@ module Polars
|
|
|
4566
4646
|
wrap_expr(_rbexpr._hash(k0, k1, k2, k3))
|
|
4567
4647
|
end
|
|
4568
4648
|
|
|
4569
|
-
# Reinterpret the underlying bits as a signed/unsigned integer.
|
|
4649
|
+
# Reinterpret the underlying bits as a signed/unsigned integer or float.
|
|
4650
|
+
#
|
|
4651
|
+
# This operation is only allowed for numeric types of the same size.
|
|
4652
|
+
# For lower bits numbers, you can safely use the cast operation.
|
|
4570
4653
|
#
|
|
4571
|
-
#
|
|
4572
|
-
# you can safely use that cast operation.
|
|
4654
|
+
# Either `signed` or `dtype` can be specified.
|
|
4573
4655
|
#
|
|
4574
4656
|
# @param signed [Boolean]
|
|
4575
|
-
# If true, reinterpret as
|
|
4657
|
+
# If true, reinterpret as signed integer. Otherwise, reinterpret
|
|
4658
|
+
# as unsigned integer.
|
|
4659
|
+
# @param dtype [Object]
|
|
4660
|
+
# DataType to reinterpret to.
|
|
4576
4661
|
#
|
|
4577
4662
|
# @return [Expr]
|
|
4578
4663
|
#
|
|
@@ -4581,7 +4666,7 @@ module Polars
|
|
|
4581
4666
|
# df = Polars::DataFrame.new([s])
|
|
4582
4667
|
# df.select(
|
|
4583
4668
|
# [
|
|
4584
|
-
# Polars.col("a").reinterpret(
|
|
4669
|
+
# Polars.col("a").reinterpret(dtype: Polars::Int64).alias("reinterpreted"),
|
|
4585
4670
|
# Polars.col("a").alias("original")
|
|
4586
4671
|
# ]
|
|
4587
4672
|
# )
|
|
@@ -4596,14 +4681,13 @@ module Polars
|
|
|
4596
4681
|
# # │ 1 ┆ 1 │
|
|
4597
4682
|
# # │ 2 ┆ 2 │
|
|
4598
4683
|
# # └───────────────┴──────────┘
|
|
4599
|
-
def reinterpret(signed: nil)
|
|
4600
|
-
|
|
4601
|
-
|
|
4602
|
-
|
|
4603
|
-
signed = false
|
|
4684
|
+
def reinterpret(signed: nil, dtype: nil)
|
|
4685
|
+
if signed.nil? == dtype.nil?
|
|
4686
|
+
msg = "reinterpret requires exactly one of `signed` or `dtype` to be specified"
|
|
4687
|
+
raise ArgumentError, msg
|
|
4604
4688
|
end
|
|
4605
4689
|
|
|
4606
|
-
wrap_expr(_rbexpr.reinterpret(signed))
|
|
4690
|
+
wrap_expr(_rbexpr.reinterpret(signed, dtype))
|
|
4607
4691
|
end
|
|
4608
4692
|
|
|
4609
4693
|
# Print the value that this expression evaluates to and pass on the value.
|
|
@@ -5175,7 +5259,7 @@ module Polars
|
|
|
5175
5259
|
def rolling_sum_by(
|
|
5176
5260
|
by,
|
|
5177
5261
|
window_size,
|
|
5178
|
-
min_samples:
|
|
5262
|
+
min_samples: 0,
|
|
5179
5263
|
closed: "right"
|
|
5180
5264
|
)
|
|
5181
5265
|
window_size = _prepare_rolling_by_window_args(window_size)
|
|
@@ -7362,17 +7446,11 @@ module Polars
|
|
|
7362
7446
|
# # └─────┘
|
|
7363
7447
|
def sample(
|
|
7364
7448
|
fraction: nil,
|
|
7365
|
-
with_replacement:
|
|
7449
|
+
with_replacement: false,
|
|
7366
7450
|
shuffle: false,
|
|
7367
7451
|
seed: nil,
|
|
7368
7452
|
n: nil
|
|
7369
7453
|
)
|
|
7370
|
-
# TODO update
|
|
7371
|
-
if with_replacement.nil?
|
|
7372
|
-
warn "The default `with_replacement` for `sample` method will change from `true` to `false` in a future version"
|
|
7373
|
-
with_replacement = true
|
|
7374
|
-
end
|
|
7375
|
-
|
|
7376
7454
|
if !n.nil? && !fraction.nil?
|
|
7377
7455
|
raise ArgumentError, "cannot specify both `n` and `fraction`"
|
|
7378
7456
|
end
|
|
@@ -7761,13 +7839,7 @@ module Polars
|
|
|
7761
7839
|
# # ╞═══════════╡
|
|
7762
7840
|
# # │ -6.754888 │
|
|
7763
7841
|
# # └───────────┘
|
|
7764
|
-
def entropy(base:
|
|
7765
|
-
# TODO update (including param docs)
|
|
7766
|
-
if base.nil?
|
|
7767
|
-
warn "The default `base` for `entropy` method will change from `2` to `Math::E` in a future version"
|
|
7768
|
-
base = 2
|
|
7769
|
-
end
|
|
7770
|
-
|
|
7842
|
+
def entropy(base: Math::E, normalize: true)
|
|
7771
7843
|
wrap_expr(_rbexpr.entropy(base, normalize))
|
|
7772
7844
|
end
|
|
7773
7845
|
|
|
@@ -7823,6 +7895,8 @@ module Polars
|
|
|
7823
7895
|
#
|
|
7824
7896
|
# @param descending [Boolean]
|
|
7825
7897
|
# Whether the `Series` order is descending.
|
|
7898
|
+
# @param nulls_last [Boolean]
|
|
7899
|
+
# Whether the nulls are at the end.
|
|
7826
7900
|
#
|
|
7827
7901
|
# @return [Expr]
|
|
7828
7902
|
#
|
|
@@ -7842,12 +7916,16 @@ module Polars
|
|
|
7842
7916
|
# # ╞════════╡
|
|
7843
7917
|
# # │ 3 │
|
|
7844
7918
|
# # └────────┘
|
|
7845
|
-
def set_sorted(descending: false)
|
|
7846
|
-
wrap_expr(_rbexpr.set_sorted_flag(descending))
|
|
7919
|
+
def set_sorted(descending: false, nulls_last: false)
|
|
7920
|
+
wrap_expr(_rbexpr.set_sorted_flag(descending, nulls_last))
|
|
7847
7921
|
end
|
|
7848
7922
|
|
|
7849
7923
|
# Aggregate to list.
|
|
7850
7924
|
#
|
|
7925
|
+
# @param maintain_order [Boolean]
|
|
7926
|
+
# Whether to preserve the order of elements in the list. Setting this
|
|
7927
|
+
# to `false` can improve performance, especially within `group_by`.
|
|
7928
|
+
#
|
|
7851
7929
|
# @return [Expr]
|
|
7852
7930
|
#
|
|
7853
7931
|
# @example
|
|
@@ -7867,8 +7945,8 @@ module Polars
|
|
|
7867
7945
|
# # ╞═══════════╪═══════════╡
|
|
7868
7946
|
# # │ [1, 2, 3] ┆ [4, 5, 6] │
|
|
7869
7947
|
# # └───────────┴───────────┘
|
|
7870
|
-
def implode
|
|
7871
|
-
wrap_expr(_rbexpr.implode)
|
|
7948
|
+
def implode(maintain_order: true)
|
|
7949
|
+
wrap_expr(_rbexpr.implode(maintain_order))
|
|
7872
7950
|
end
|
|
7873
7951
|
|
|
7874
7952
|
# Bin values into buckets and count their occurrences.
|