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.
Files changed (206) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +274 -0
  3. data/Cargo.lock +1465 -867
  4. data/Cargo.toml +3 -0
  5. data/LICENSE.txt +2 -2
  6. data/README.md +87 -37
  7. data/ext/polars/Cargo.toml +47 -16
  8. data/ext/polars/src/c_api/allocator.rs +7 -0
  9. data/ext/polars/src/c_api/mod.rs +1 -0
  10. data/ext/polars/src/catalog/mod.rs +1 -0
  11. data/ext/polars/src/catalog/unity.rs +470 -0
  12. data/ext/polars/src/conversion/any_value.rs +99 -84
  13. data/ext/polars/src/conversion/categorical.rs +30 -0
  14. data/ext/polars/src/conversion/chunked_array.rs +71 -62
  15. data/ext/polars/src/conversion/datetime.rs +63 -0
  16. data/ext/polars/src/conversion/mod.rs +796 -312
  17. data/ext/polars/src/dataframe/construction.rs +6 -18
  18. data/ext/polars/src/dataframe/export.rs +30 -39
  19. data/ext/polars/src/dataframe/general.rs +294 -362
  20. data/ext/polars/src/dataframe/io.rs +33 -150
  21. data/ext/polars/src/dataframe/map.rs +175 -0
  22. data/ext/polars/src/dataframe/mod.rs +37 -5
  23. data/ext/polars/src/dataframe/serde.rs +23 -8
  24. data/ext/polars/src/error.rs +44 -7
  25. data/ext/polars/src/exceptions.rs +21 -8
  26. data/ext/polars/src/expr/array.rs +86 -22
  27. data/ext/polars/src/expr/binary.rs +50 -1
  28. data/ext/polars/src/expr/bitwise.rs +39 -0
  29. data/ext/polars/src/expr/categorical.rs +20 -0
  30. data/ext/polars/src/expr/datatype.rs +51 -0
  31. data/ext/polars/src/expr/datetime.rs +99 -41
  32. data/ext/polars/src/expr/extension.rs +12 -0
  33. data/ext/polars/src/expr/general.rs +252 -128
  34. data/ext/polars/src/expr/list.rs +56 -60
  35. data/ext/polars/src/expr/meta.rs +30 -35
  36. data/ext/polars/src/expr/mod.rs +28 -6
  37. data/ext/polars/src/expr/name.rs +29 -14
  38. data/ext/polars/src/expr/rolling.rs +111 -3
  39. data/ext/polars/src/expr/selector.rs +219 -0
  40. data/ext/polars/src/expr/serde.rs +28 -0
  41. data/ext/polars/src/expr/string.rs +118 -20
  42. data/ext/polars/src/expr/struct.rs +14 -1
  43. data/ext/polars/src/file.rs +194 -86
  44. data/ext/polars/src/functions/aggregation.rs +13 -12
  45. data/ext/polars/src/functions/business.rs +2 -3
  46. data/ext/polars/src/functions/eager.rs +3 -2
  47. data/ext/polars/src/functions/io.rs +90 -18
  48. data/ext/polars/src/functions/lazy.rs +267 -118
  49. data/ext/polars/src/functions/meta.rs +8 -7
  50. data/ext/polars/src/functions/misc.rs +1 -1
  51. data/ext/polars/src/functions/mod.rs +2 -1
  52. data/ext/polars/src/functions/range.rs +88 -31
  53. data/ext/polars/src/functions/strings.rs +6 -0
  54. data/ext/polars/src/functions/utils.rs +8 -0
  55. data/ext/polars/src/interop/arrow/mod.rs +52 -1
  56. data/ext/polars/src/interop/arrow/{to_ruby.rs → to_rb.rs} +37 -7
  57. data/ext/polars/src/interop/arrow/to_rust.rs +43 -0
  58. data/ext/polars/src/interop/numo/to_numo_df.rs +1 -1
  59. data/ext/polars/src/interop/numo/to_numo_series.rs +72 -50
  60. data/ext/polars/src/io/cloud_options.rs +107 -0
  61. data/ext/polars/src/io/mod.rs +4 -0
  62. data/ext/polars/src/io/scan_options.rs +113 -0
  63. data/ext/polars/src/io/sink_options.rs +46 -0
  64. data/ext/polars/src/io/sink_output.rs +21 -0
  65. data/ext/polars/src/lazyframe/exitable.rs +39 -0
  66. data/ext/polars/src/lazyframe/general.rs +846 -368
  67. data/ext/polars/src/lazyframe/mod.rs +58 -5
  68. data/ext/polars/src/lazyframe/optflags.rs +59 -0
  69. data/ext/polars/src/lazyframe/serde.rs +36 -4
  70. data/ext/polars/src/lazyframe/sink.rs +46 -0
  71. data/ext/polars/src/lazygroupby.rs +38 -9
  72. data/ext/polars/src/lib.rs +574 -165
  73. data/ext/polars/src/map/lazy.rs +44 -74
  74. data/ext/polars/src/map/mod.rs +18 -254
  75. data/ext/polars/src/map/series.rs +241 -1087
  76. data/ext/polars/src/on_startup.rs +192 -9
  77. data/ext/polars/src/prelude.rs +1 -0
  78. data/ext/polars/src/rb_modules.rs +10 -57
  79. data/ext/polars/src/ruby/exceptions.rs +26 -0
  80. data/ext/polars/src/ruby/gvl.rs +104 -0
  81. data/ext/polars/src/ruby/lazy.rs +46 -0
  82. data/ext/polars/src/ruby/mod.rs +11 -0
  83. data/ext/polars/src/ruby/numo.rs +52 -0
  84. data/ext/polars/src/ruby/plan_callback.rs +198 -0
  85. data/ext/polars/src/ruby/rb_modules.rs +16 -0
  86. data/ext/polars/src/ruby/ruby_convert_registry.rs +51 -0
  87. data/ext/polars/src/ruby/ruby_function.rs +11 -0
  88. data/ext/polars/src/ruby/ruby_udf.rs +164 -0
  89. data/ext/polars/src/ruby/thread.rs +65 -0
  90. data/ext/polars/src/ruby/utils.rs +39 -0
  91. data/ext/polars/src/series/aggregation.rs +116 -91
  92. data/ext/polars/src/series/arithmetic.rs +16 -22
  93. data/ext/polars/src/series/comparison.rs +101 -222
  94. data/ext/polars/src/series/construction.rs +80 -70
  95. data/ext/polars/src/series/export.rs +98 -56
  96. data/ext/polars/src/series/general.rs +323 -440
  97. data/ext/polars/src/series/import.rs +22 -5
  98. data/ext/polars/src/series/map.rs +103 -0
  99. data/ext/polars/src/series/mod.rs +57 -15
  100. data/ext/polars/src/series/scatter.rs +139 -82
  101. data/ext/polars/src/sql.rs +16 -9
  102. data/ext/polars/src/testing/frame.rs +31 -0
  103. data/ext/polars/src/testing/mod.rs +5 -0
  104. data/ext/polars/src/testing/series.rs +31 -0
  105. data/ext/polars/src/timeout.rs +105 -0
  106. data/ext/polars/src/utils.rs +105 -4
  107. data/lib/polars/array_expr.rb +500 -22
  108. data/lib/polars/array_name_space.rb +384 -10
  109. data/lib/polars/batched_csv_reader.rb +48 -66
  110. data/lib/polars/binary_expr.rb +217 -0
  111. data/lib/polars/binary_name_space.rb +155 -1
  112. data/lib/polars/cat_expr.rb +224 -0
  113. data/lib/polars/cat_name_space.rb +132 -32
  114. data/lib/polars/catalog/unity/catalog_info.rb +20 -0
  115. data/lib/polars/catalog/unity/column_info.rb +31 -0
  116. data/lib/polars/catalog/unity/namespace_info.rb +21 -0
  117. data/lib/polars/catalog/unity/table_info.rb +50 -0
  118. data/lib/polars/catalog.rb +448 -0
  119. data/lib/polars/collect_batches.rb +22 -0
  120. data/lib/polars/config.rb +3 -3
  121. data/lib/polars/convert.rb +201 -36
  122. data/lib/polars/data_frame.rb +2851 -1017
  123. data/lib/polars/data_frame_plot.rb +173 -0
  124. data/lib/polars/data_type_expr.rb +52 -0
  125. data/lib/polars/data_type_group.rb +6 -0
  126. data/lib/polars/data_types.rb +118 -18
  127. data/lib/polars/date_time_expr.rb +426 -84
  128. data/lib/polars/date_time_name_space.rb +384 -111
  129. data/lib/polars/dynamic_group_by.rb +102 -10
  130. data/lib/polars/exceptions.rb +50 -5
  131. data/lib/polars/expr.rb +2159 -915
  132. data/lib/polars/extension_expr.rb +39 -0
  133. data/lib/polars/extension_name_space.rb +39 -0
  134. data/lib/polars/functions/aggregation/horizontal.rb +11 -6
  135. data/lib/polars/functions/aggregation/vertical.rb +2 -3
  136. data/lib/polars/functions/as_datatype.rb +290 -8
  137. data/lib/polars/functions/business.rb +95 -0
  138. data/lib/polars/functions/col.rb +6 -5
  139. data/lib/polars/functions/datatype.rb +62 -0
  140. data/lib/polars/functions/eager.rb +426 -24
  141. data/lib/polars/functions/escape_regex.rb +21 -0
  142. data/lib/polars/functions/lazy.rb +813 -195
  143. data/lib/polars/functions/lit.rb +21 -10
  144. data/lib/polars/functions/range/int_range.rb +74 -2
  145. data/lib/polars/functions/range/linear_space.rb +195 -0
  146. data/lib/polars/functions/range/time_range.rb +1 -1
  147. data/lib/polars/functions/repeat.rb +7 -12
  148. data/lib/polars/functions/whenthen.rb +2 -2
  149. data/lib/polars/group_by.rb +188 -58
  150. data/lib/polars/iceberg_dataset.rb +108 -0
  151. data/lib/polars/in_process_query.rb +37 -0
  152. data/lib/polars/io/cloud.rb +18 -0
  153. data/lib/polars/io/csv.rb +336 -128
  154. data/lib/polars/io/database.rb +19 -4
  155. data/lib/polars/io/delta.rb +134 -0
  156. data/lib/polars/io/iceberg.rb +34 -0
  157. data/lib/polars/io/ipc.rb +63 -63
  158. data/lib/polars/io/json.rb +16 -0
  159. data/lib/polars/io/lines.rb +172 -0
  160. data/lib/polars/io/ndjson.rb +176 -20
  161. data/lib/polars/io/parquet.rb +173 -95
  162. data/lib/polars/io/scan_options.rb +55 -0
  163. data/lib/polars/io/sink_options.rb +27 -0
  164. data/lib/polars/io/utils.rb +17 -0
  165. data/lib/polars/lazy_frame.rb +3017 -622
  166. data/lib/polars/lazy_group_by.rb +436 -2
  167. data/lib/polars/list_expr.rb +551 -59
  168. data/lib/polars/list_name_space.rb +465 -51
  169. data/lib/polars/meta_expr.rb +146 -24
  170. data/lib/polars/name_expr.rb +87 -2
  171. data/lib/polars/query_opt_flags.rb +264 -0
  172. data/lib/polars/rolling_group_by.rb +90 -5
  173. data/lib/polars/scan_cast_options.rb +86 -0
  174. data/lib/polars/schema.rb +128 -0
  175. data/lib/polars/selector.rb +245 -0
  176. data/lib/polars/selectors.rb +1048 -201
  177. data/lib/polars/series.rb +2522 -774
  178. data/lib/polars/series_plot.rb +72 -0
  179. data/lib/polars/slice.rb +1 -1
  180. data/lib/polars/sql_context.rb +13 -6
  181. data/lib/polars/string_cache.rb +19 -72
  182. data/lib/polars/string_expr.rb +561 -107
  183. data/lib/polars/string_name_space.rb +781 -109
  184. data/lib/polars/struct_expr.rb +139 -18
  185. data/lib/polars/struct_name_space.rb +19 -1
  186. data/lib/polars/testing.rb +24 -273
  187. data/lib/polars/utils/constants.rb +2 -0
  188. data/lib/polars/utils/construction/data_frame.rb +410 -0
  189. data/lib/polars/utils/construction/series.rb +350 -0
  190. data/lib/polars/utils/construction/utils.rb +9 -0
  191. data/lib/polars/utils/convert.rb +18 -8
  192. data/lib/polars/utils/deprecation.rb +11 -0
  193. data/lib/polars/utils/parse.rb +62 -9
  194. data/lib/polars/utils/reduce_balanced.rb +43 -0
  195. data/lib/polars/utils/serde.rb +22 -0
  196. data/lib/polars/utils/unstable.rb +19 -0
  197. data/lib/polars/utils/various.rb +86 -1
  198. data/lib/polars/utils.rb +63 -48
  199. data/lib/polars/version.rb +1 -1
  200. data/lib/polars.rb +85 -2
  201. metadata +80 -28
  202. data/ext/polars/src/allocator.rs +0 -13
  203. data/ext/polars/src/batched_csv.rs +0 -138
  204. data/ext/polars/src/functions/string_cache.rs +0 -25
  205. data/ext/polars/src/map/dataframe.rs +0 -338
  206. data/lib/polars/plot.rb +0 -109
@@ -0,0 +1,86 @@
1
+ module Polars
2
+ # Options for scanning files.
3
+ class ScanCastOptions
4
+ attr_reader :integer_cast, :float_cast, :datetime_cast, :missing_struct_fields, :extra_struct_fields, :categorical_to_string
5
+
6
+ # Common configuration for scanning files.
7
+ #
8
+ # @note
9
+ # This functionality is considered **unstable**. It may be changed
10
+ # at any point without it being considered a breaking change.
11
+ #
12
+ # @param integer_cast ['upcast', 'forbid']
13
+ # Configuration for casting from integer types:
14
+ #
15
+ # * `upcast`: Allow lossless casting to wider integer types.
16
+ # * `forbid`: Raises an error if dtypes do not match.
17
+ #
18
+ # @param float_cast ['upcast', 'downcast', 'forbid']
19
+ # Configuration for casting from float types:
20
+ #
21
+ # * `upcast`: Allow casting to higher precision float types.
22
+ # * `downcast`: Allow casting to lower precision float types.
23
+ # * `forbid`: Raises an error if dtypes do not match.
24
+ #
25
+ # @param datetime_cast ['nanosecond-downcast', 'convert-timezone', 'forbid']
26
+ # Configuration for casting from datetime types:
27
+ #
28
+ # * `nanosecond-downcast`: Allow nanosecond precision datetime to be
29
+ # downcasted to any lower precision. This has a similar effect to
30
+ # PyArrow's `coerce_int96_timestamp_unit`.
31
+ # * `convert-timezone`: Allow casting to a different timezone.
32
+ # * `forbid`: Raises an error if dtypes do not match.
33
+ #
34
+ # @param missing_struct_fields ['insert', 'raise']
35
+ # Configuration for behavior when struct fields defined in the schema
36
+ # are missing from the data:
37
+ #
38
+ # * `insert`: Inserts the missing fields.
39
+ # * `raise`: Raises an error.
40
+ #
41
+ # @param extra_struct_fields ['ignore', 'raise']
42
+ # Configuration for behavior when extra struct fields outside of the
43
+ # defined schema are encountered in the data:
44
+ #
45
+ # * `ignore`: Silently ignores.
46
+ # * `raise`: Raises an error.
47
+ def initialize(
48
+ integer_cast: "forbid",
49
+ float_cast: "forbid",
50
+ datetime_cast: "forbid",
51
+ missing_struct_fields: "raise",
52
+ extra_struct_fields: "raise",
53
+ categorical_to_string: "forbid",
54
+ _internal_call: false
55
+ )
56
+ if !_internal_call
57
+ warn "ScanCastOptions is considered unstable."
58
+ end
59
+
60
+ @integer_cast = integer_cast
61
+ @float_cast = float_cast
62
+ @datetime_cast = datetime_cast
63
+ @missing_struct_fields = missing_struct_fields
64
+ @extra_struct_fields = extra_struct_fields
65
+ @categorical_to_string = categorical_to_string
66
+ end
67
+
68
+ def self._default
69
+ new(_internal_call: true)
70
+ end
71
+
72
+ def self._default_iceberg
73
+ @_default_cast_options_iceberg ||= begin
74
+ ScanCastOptions.new(
75
+ integer_cast: "upcast",
76
+ float_cast: ["upcast", "downcast"],
77
+ datetime_cast: ["nanosecond-downcast", "convert-timezone"],
78
+ missing_struct_fields: "insert",
79
+ extra_struct_fields: "ignore",
80
+ categorical_to_string: "allow",
81
+ _internal_call: true
82
+ )
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,128 @@
1
+ module Polars
2
+ class Schema
3
+ include Enumerable
4
+
5
+ # Ordered mapping of column names to their data type.
6
+ #
7
+ # @param schema [Object]
8
+ # The schema definition given by column names and their associated
9
+ # Polars data type. Accepts a mapping or an enumerable of arrays.
10
+ def initialize(schema = nil, check_dtypes: true)
11
+ @schema = {}
12
+
13
+ if schema.respond_to?(:arrow_c_schema) && !schema.is_a?(Schema)
14
+ Plr.init_polars_schema_from_arrow_c_schema(@schema, schema)
15
+ return
16
+ end
17
+
18
+ input = schema || {}
19
+ input.each do |name, tp|
20
+ if !check_dtypes
21
+ @schema[name] = tp
22
+ elsif Utils.is_polars_dtype(tp)
23
+ @schema[name] = _check_dtype(tp)
24
+ else
25
+ self[name] = tp
26
+ end
27
+ end
28
+ end
29
+
30
+ # Returns the data type of the column.
31
+ #
32
+ # @return [Object]
33
+ def [](key)
34
+ @schema[key]
35
+ end
36
+
37
+ # Sets the data type of the column.
38
+ #
39
+ # @return [Object]
40
+ def []=(name, dtype)
41
+ _check_dtype(dtype)
42
+ @schema[name] = dtype
43
+ end
44
+
45
+ # @private
46
+ def arrow_c_schema
47
+ Plr.polars_schema_to_rbcapsule(self)
48
+ end
49
+
50
+ # Get the column names of the schema.
51
+ #
52
+ # @return [Array]
53
+ #
54
+ # @example
55
+ # s = Polars::Schema.new({"x" => Polars::Float64.new, "y" => Polars::Datetime.new(time_zone: "UTC")})
56
+ # s.names
57
+ # # => ["x", "y"]
58
+ def names
59
+ @schema.keys
60
+ end
61
+
62
+ # Get the data types of the schema.
63
+ #
64
+ # @return [Array]
65
+ #
66
+ # @example
67
+ # s = Polars::Schema.new({"x" => Polars::UInt8.new, "y" => Polars::List.new(Polars::UInt8)})
68
+ # s.dtypes
69
+ # # => [Polars::UInt8, Polars::List(Polars::UInt8)]
70
+ def dtypes
71
+ @schema.values
72
+ end
73
+
74
+ # Get the number of schema entries.
75
+ #
76
+ # @return [Integer]
77
+ #
78
+ # @example
79
+ # s = Polars::Schema.new({"x" => Polars::Int32.new, "y" => Polars::List.new(Polars::String)})
80
+ # s.length
81
+ # # => 2
82
+ def length
83
+ @schema.length
84
+ end
85
+
86
+ # Returns a string representing the Schema.
87
+ #
88
+ # @return [String]
89
+ def to_s
90
+ "#{self.class.name}(#{@schema})"
91
+ end
92
+ alias_method :inspect, :to_s
93
+
94
+ # @private
95
+ def each(&block)
96
+ @schema.each(&block)
97
+ end
98
+
99
+ # @private
100
+ def include?(name)
101
+ @schema.include?(name)
102
+ end
103
+
104
+ # @private
105
+ def to_h(&block)
106
+ @schema.to_h(&block)
107
+ end
108
+
109
+ private
110
+
111
+ def _check_dtype(tp)
112
+ if !tp.is_a?(DataType)
113
+ # note: if nested/decimal, or has signature params, this implies required args
114
+ if tp.nested? || tp.decimal? || _required_init_args(tp)
115
+ msg = "dtypes must be fully-specified, got: #{tp.inspect}"
116
+ raise TypeError, msg
117
+ end
118
+ tp = tp.new
119
+ end
120
+ tp
121
+ end
122
+
123
+ def _required_init_args(tp)
124
+ arity = tp.method(:new).arity
125
+ arity > 0 || arity < -1
126
+ end
127
+ end
128
+ end
@@ -0,0 +1,245 @@
1
+ module Polars
2
+ # Base column selector expression/proxy.
3
+ class Selector < Expr
4
+ # @private
5
+ attr_accessor :_rbselector
6
+
7
+ # @private
8
+ def self._from_rbselector(rbselector)
9
+ slf = new
10
+ slf._rbselector = rbselector
11
+ slf._rbexpr = RbExpr.new_selector(rbselector)
12
+ slf
13
+ end
14
+
15
+ # Returns a string representing the Selector.
16
+ #
17
+ # @return [String]
18
+ def inspect
19
+ Expr._from_rbexpr(_rbexpr).to_s
20
+ end
21
+
22
+ # @private
23
+ def self._by_dtype(dtypes)
24
+ selectors = []
25
+ concrete_dtypes = []
26
+ dtypes.each do |dt|
27
+ if Utils.is_polars_dtype(dt)
28
+ concrete_dtypes += [dt]
29
+ else
30
+ raise Todo
31
+ end
32
+ end
33
+
34
+ dtype_selector = _from_rbselector(RbSelector.by_dtype(concrete_dtypes))
35
+
36
+ if selectors.length == 0
37
+ return dtype_selector
38
+ end
39
+
40
+ selector = selectors[0]
41
+ selectors[1..].each do |s|
42
+ selector = selector | s
43
+ end
44
+ if concrete_dtypes.length == 0
45
+ selector
46
+ else
47
+ dtype_selector | selector
48
+ end
49
+ end
50
+
51
+ # @private
52
+ def self._by_name(names, strict:, expand_patterns:)
53
+ _from_rbselector(RbSelector.by_name(names, strict, expand_patterns))
54
+ end
55
+
56
+ # Invert the selector.
57
+ #
58
+ # @return [Selector]
59
+ def ~
60
+ Selectors.all - self
61
+ end
62
+
63
+ # AND.
64
+ #
65
+ # @return [Selector]
66
+ def &(other)
67
+ if Utils.is_column(other)
68
+ colname = other.meta.output_name
69
+ other = by_name(colname)
70
+ end
71
+ if Utils.is_selector(other)
72
+ Selector._from_rbselector(
73
+ _rbselector.intersect(other._rbselector)
74
+ )
75
+ else
76
+ as_expr & other
77
+ end
78
+ end
79
+
80
+ # OR.
81
+ #
82
+ # @return [Selector]
83
+ def |(other)
84
+ if Utils.is_column(other)
85
+ other = by_name(other.meta.output_name)
86
+ end
87
+ if Utils.is_selector(other)
88
+ Selector._from_rbselector(
89
+ _rbselector.union(other._rbselector)
90
+ )
91
+ else
92
+ as_expr | other
93
+ end
94
+ end
95
+
96
+ # Difference.
97
+ #
98
+ # @return [Selector]
99
+ def -(other)
100
+ if Utils.is_selector(other)
101
+ Selector._from_rbselector(
102
+ _rbselector.difference(other._rbselector)
103
+ )
104
+ else
105
+ as_expr - other
106
+ end
107
+ end
108
+
109
+ # XOR.
110
+ #
111
+ # @return [Selector]
112
+ def ^(other)
113
+ if Utils.is_column(other)
114
+ other = by_name(other.meta.output_name)
115
+ end
116
+ if Utils.is_selector(other)
117
+ Selector._from_rbselector(
118
+ _rbselector.exclusive_or(other._rbselector)
119
+ )
120
+ else
121
+ as_expr ^ other
122
+ end
123
+ end
124
+
125
+ # Exclude columns from a multi-column expression.
126
+ #
127
+ # Only works after a wildcard or regex column selection, and you cannot provide
128
+ # both string column names *and* dtypes (you may prefer to use selectors instead).
129
+ #
130
+ # @param columns [Object]
131
+ # The name or datatype of the column(s) to exclude. Accepts regular expression
132
+ # input. Regular expressions should start with `^` and end with `$`.
133
+ # @param more_columns [Array]
134
+ # Additional names or datatypes of columns to exclude, specified as positional
135
+ # arguments.
136
+ #
137
+ # @return [Selector]
138
+ #
139
+ # @example Exclude by column name(s):
140
+ # df = Polars::DataFrame.new(
141
+ # {
142
+ # "aa" => [1, 2, 3],
143
+ # "ba" => ["a", "b", nil],
144
+ # "cc" => [nil, 2.5, 1.5]
145
+ # }
146
+ # )
147
+ # df.select(Polars.cs.exclude("ba", "xx"))
148
+ # # =>
149
+ # # shape: (3, 2)
150
+ # # ┌─────┬──────┐
151
+ # # │ aa ┆ cc │
152
+ # # │ --- ┆ --- │
153
+ # # │ i64 ┆ f64 │
154
+ # # ╞═════╪══════╡
155
+ # # │ 1 ┆ null │
156
+ # # │ 2 ┆ 2.5 │
157
+ # # │ 3 ┆ 1.5 │
158
+ # # └─────┴──────┘
159
+ #
160
+ # @example Exclude using a column name, a selector, and a dtype:
161
+ # df.select(Polars.cs.exclude("aa", Polars.cs.string, Polars::UInt32))
162
+ # # =>
163
+ # # shape: (3, 1)
164
+ # # ┌──────┐
165
+ # # │ cc │
166
+ # # │ --- │
167
+ # # │ f64 │
168
+ # # ╞══════╡
169
+ # # │ null │
170
+ # # │ 2.5 │
171
+ # # │ 1.5 │
172
+ # # └──────┘
173
+ def exclude(columns, *more_columns)
174
+ exclude_cols = []
175
+ exclude_dtypes = []
176
+ ((columns.is_a?(::Array) ? columns : [columns]) + more_columns).each do |item|
177
+ if item.is_a?(::String)
178
+ exclude_cols << item
179
+ elsif Utils.is_polars_dtype(item)
180
+ exclude_dtypes << item
181
+ else
182
+ msg = (
183
+ "invalid input for `exclude`" +
184
+ "\n\nExpected one or more `str` or `DataType`; found #{item.inspect} instead."
185
+ )
186
+ raise TypeError, msg
187
+ end
188
+ end
189
+
190
+ if exclude_cols.any? && exclude_dtypes.any?
191
+ msg = "cannot exclude by both column name and dtype; use a selector instead"
192
+ raise TypeError, msg
193
+ elsif exclude_dtypes.any?
194
+ self - Selectors.by_dtype(exclude_dtypes)
195
+ else
196
+ self - Selector._by_name(exclude_cols, strict: false, expand_patterns: true)
197
+ end
198
+ end
199
+
200
+ # Materialize the `selector` as a normal expression.
201
+ #
202
+ # This ensures that the operators `|`, `&`, `~` and `-`
203
+ # are applied on the data and not on the selector sets.
204
+ #
205
+ # @return [Expr]
206
+ #
207
+ # @example Inverting the boolean selector will choose the non-boolean columns:
208
+ # df = Polars::DataFrame.new(
209
+ # {
210
+ # "colx" => ["aa", "bb", "cc"],
211
+ # "coly" => [true, false, true],
212
+ # "colz" => [1, 2, 3]
213
+ # }
214
+ # )
215
+ # df.select(~Polars.cs.boolean)
216
+ # # =>
217
+ # # shape: (3, 2)
218
+ # # ┌──────┬──────┐
219
+ # # │ colx ┆ colz │
220
+ # # │ --- ┆ --- │
221
+ # # │ str ┆ i64 │
222
+ # # ╞══════╪══════╡
223
+ # # │ aa ┆ 1 │
224
+ # # │ bb ┆ 2 │
225
+ # # │ cc ┆ 3 │
226
+ # # └──────┴──────┘
227
+ #
228
+ # @example To invert the *values* in the selected boolean columns, we need to materialize the selector as a standard expression instead:
229
+ # df.select(~Polars.cs.boolean.as_expr)
230
+ # # =>
231
+ # # shape: (3, 1)
232
+ # # ┌───────┐
233
+ # # │ coly │
234
+ # # │ --- │
235
+ # # │ bool │
236
+ # # ╞═══════╡
237
+ # # │ false │
238
+ # # │ true │
239
+ # # │ false │
240
+ # # └───────┘
241
+ def as_expr
242
+ Expr._from_rbexpr(_rbexpr)
243
+ end
244
+ end
245
+ end