polars-df 0.3.0 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 14ccd76535033a1f3d848fcddc415c655b7e1396549739a76b7cd475bc4bf1b9
4
- data.tar.gz: cf3459dfc3a000dacfef73859ac3a613fd73416644c2887f9aa08c84d1f0eede
3
+ metadata.gz: c85781858b193df5bb1bf3156b6ff14cee0d31ba9d70a14e0830c473d1cca589
4
+ data.tar.gz: b4333da25d4d575f1ef84a39b673244b088b346520b2b7e65d51e899e73e27b5
5
5
  SHA512:
6
- metadata.gz: b87a95fdff40f17fd5bc1f286b4f8f1ff906675c07c84769b08ecfe97347c2e15fcb61d6a93d2ba7ae7556bb937d0ddf90dbc188cee75ecf00f481a97db0bb7e
7
- data.tar.gz: c93504de6f9071e45529f7c3898100e5c9341b2f2a3f527aa8fdee6cc195055230c0c08b9a7383684489ae25c00acf7e136d8a3516b6e20b5a1d1445b55efca5
6
+ metadata.gz: 86b867790e1cde10fc813eceb2baf26912700d2db7501f670c5fae5156fcd1ce56b494d178f488d0e84a74220f3b87446df94e1822c44b3c6a869392f805c5ee
7
+ data.tar.gz: 7afe9f2b39be4045ce4fc95c1619db0fadad80eed5c4d9b25f2434379ee1aae61a87c956ec92e16cfd15bec0c780b5bf25fefe84bb858083874971bfc47860fd
data/CHANGELOG.md CHANGED
@@ -1,3 +1,9 @@
1
+ ## 0.3.1 (2023-02-21)
2
+
3
+ - Added `to_numo` method to `Series` and `DataFrame`
4
+ - Added `plot` method to `DataFrame`
5
+ - Fixed `is_datelike` method for `Datetime` and `Duration`
6
+
1
7
  ## 0.3.0 (2023-02-15)
2
8
 
3
9
  - Updated Polars to 0.27.1
data/Cargo.lock CHANGED
@@ -1430,7 +1430,7 @@ dependencies = [
1430
1430
 
1431
1431
  [[package]]
1432
1432
  name = "polars"
1433
- version = "0.3.0"
1433
+ version = "0.3.1"
1434
1434
  dependencies = [
1435
1435
  "ahash",
1436
1436
  "jemallocator",
data/README.md CHANGED
@@ -282,10 +282,10 @@ df.to_dummies
282
282
 
283
283
  ## Conversion
284
284
 
285
- Array of rows
285
+ Array of hashes
286
286
 
287
287
  ```ruby
288
- df.rows
288
+ df.rows(named: true)
289
289
  ```
290
290
 
291
291
  Hash of series
@@ -308,6 +308,12 @@ Parquet
308
308
  df.write_parquet("file.parquet")
309
309
  ```
310
310
 
311
+ Numo array
312
+
313
+ ```ruby
314
+ df.to_numo
315
+ ```
316
+
311
317
  ## Types
312
318
 
313
319
  You can specify column types when creating a data frame
@@ -343,6 +349,38 @@ Cast a column
343
349
  df["a"].cast(Polars::Int32)
344
350
  ```
345
351
 
352
+ ## Visualization
353
+
354
+ Add [Vega](https://github.com/ankane/vega-ruby) to your application’s Gemfile:
355
+
356
+ ```ruby
357
+ gem "vega"
358
+ ```
359
+
360
+ And use:
361
+
362
+ ```ruby
363
+ df.plot("a", "b")
364
+ ```
365
+
366
+ Specify the chart type (`line`, `pie`, `column`, `bar`, `area`, or `scatter`)
367
+
368
+ ```ruby
369
+ df.plot("a", "b", type: "pie")
370
+ ```
371
+
372
+ Group data
373
+
374
+ ```ruby
375
+ df.groupby("c").plot("a", "b")
376
+ ```
377
+
378
+ Stacked columns or bars
379
+
380
+ ```ruby
381
+ df.groupby("c").plot("a", "b", stacked: true)
382
+ ```
383
+
346
384
  ## History
347
385
 
348
386
  View the [changelog](CHANGELOG.md)
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "polars"
3
- version = "0.3.0"
3
+ version = "0.3.1"
4
4
  license = "MIT"
5
5
  authors = ["Andrew Kane <andrew@ankane.org>"]
6
6
  edition = "2021"
@@ -125,7 +125,13 @@ impl IntoValue for Wrap<AnyValue<'_>> {
125
125
  .unwrap(),
126
126
  AnyValue::Datetime(v, tu, tz) => {
127
127
  let t = match tu {
128
- TimeUnit::Nanoseconds => todo!(),
128
+ TimeUnit::Nanoseconds => {
129
+ let sec = v / 1000000000;
130
+ let subsec = v % 1000000000;
131
+ class::time()
132
+ .funcall::<_, _, Value>("at", (sec, subsec, Symbol::new("nsec")))
133
+ .unwrap()
134
+ }
129
135
  TimeUnit::Microseconds => {
130
136
  let sec = v / 1000000;
131
137
  let subsec = v % 1000000;
@@ -133,7 +139,13 @@ impl IntoValue for Wrap<AnyValue<'_>> {
133
139
  .funcall::<_, _, Value>("at", (sec, subsec, Symbol::new("usec")))
134
140
  .unwrap()
135
141
  }
136
- TimeUnit::Milliseconds => todo!(),
142
+ TimeUnit::Milliseconds => {
143
+ let sec = v / 1000;
144
+ let subsec = v % 1000;
145
+ class::time()
146
+ .funcall::<_, _, Value>("at", (sec, subsec, Symbol::new("millisecond")))
147
+ .unwrap()
148
+ }
137
149
  };
138
150
 
139
151
  if tz.is_some() {
@@ -175,7 +187,7 @@ impl IntoValue for Wrap<DataType> {
175
187
  DataType::Utf8 => pl.const_get::<_, Value>("Utf8").unwrap(),
176
188
  DataType::Binary => pl.const_get::<_, Value>("Binary").unwrap(),
177
189
  DataType::List(inner) => {
178
- let inner = Wrap(*inner.clone());
190
+ let inner = Wrap(*inner);
179
191
  let list_class = pl.const_get::<_, Value>("List").unwrap();
180
192
  list_class.funcall::<_, _, Value>("new", (inner,)).unwrap()
181
193
  }
@@ -183,7 +195,7 @@ impl IntoValue for Wrap<DataType> {
183
195
  DataType::Datetime(tu, tz) => {
184
196
  let datetime_class = pl.const_get::<_, Value>("Datetime").unwrap();
185
197
  datetime_class
186
- .funcall::<_, _, Value>("new", (tu.to_ascii(), tz.clone()))
198
+ .funcall::<_, _, Value>("new", (tu.to_ascii(), tz))
187
199
  .unwrap()
188
200
  }
189
201
  DataType::Duration(tu) => {
@@ -6,6 +6,7 @@ use polars::io::mmap::ReaderBytes;
6
6
  use polars::io::RowCount;
7
7
  use polars::prelude::pivot::{pivot, pivot_stable};
8
8
  use polars::prelude::*;
9
+ use polars_core::utils::try_get_supertype;
9
10
  use std::cell::RefCell;
10
11
  use std::io::{BufWriter, Cursor};
11
12
  use std::ops::Deref;
@@ -493,6 +494,25 @@ impl RbDataFrame {
493
494
  .into()
494
495
  }
495
496
 
497
+ pub fn to_numo(&self) -> Option<Value> {
498
+ let mut st = None;
499
+ for s in self.df.borrow().iter() {
500
+ let dt_i = s.dtype();
501
+ match st {
502
+ None => st = Some(dt_i.clone()),
503
+ Some(ref mut st) => {
504
+ *st = try_get_supertype(st, dt_i).ok()?;
505
+ }
506
+ }
507
+ }
508
+ let st = st?;
509
+
510
+ match st {
511
+ // TODO
512
+ _ => None,
513
+ }
514
+ }
515
+
496
516
  pub fn write_parquet(
497
517
  &self,
498
518
  rb_f: Value,
@@ -43,3 +43,11 @@ impl ComputeError {
43
43
  Error::new(exception::runtime_error(), message)
44
44
  }
45
45
  }
46
+
47
+ #[macro_export]
48
+ macro_rules! raise_err(
49
+ ($msg:expr, $err:ident) => {{
50
+ Err(PolarsError::$err($msg.into())).map_err(RbPolarsErr::from)?;
51
+ unreachable!()
52
+ }}
53
+ );
@@ -6,6 +6,7 @@ mod error;
6
6
  mod file;
7
7
  mod lazy;
8
8
  mod list_construction;
9
+ mod numo;
9
10
  mod object;
10
11
  mod prelude;
11
12
  pub(crate) mod rb_modules;
@@ -87,6 +88,7 @@ fn init() -> RbResult<()> {
87
88
  class.define_method("write_ipc", method!(RbDataFrame::write_ipc, 2))?;
88
89
  class.define_method("row_tuple", method!(RbDataFrame::row_tuple, 1))?;
89
90
  class.define_method("row_tuples", method!(RbDataFrame::row_tuples, 0))?;
91
+ class.define_method("to_numo", method!(RbDataFrame::to_numo, 0))?;
90
92
  class.define_method("write_parquet", method!(RbDataFrame::write_parquet, 5))?;
91
93
  class.define_method("add", method!(RbDataFrame::add, 1))?;
92
94
  class.define_method("sub", method!(RbDataFrame::sub, 1))?;
@@ -783,6 +785,9 @@ fn init() -> RbResult<()> {
783
785
  class.define_method("lt_eq_f64", method!(RbSeries::lt_eq_f64, 1))?;
784
786
  // class.define_method("lt_eq_str", method!(RbSeries::lt_eq_str, 1))?;
785
787
 
788
+ // npy
789
+ class.define_method("to_numo", method!(RbSeries::to_numo, 0))?;
790
+
786
791
  let class = module.define_class("RbWhen", Default::default())?;
787
792
  class.define_method("_then", method!(RbWhen::then, 1))?;
788
793
 
@@ -0,0 +1,57 @@
1
+ use magnus::{class, Module, RArray, RClass, RModule, Value};
2
+ use polars_core::prelude::*;
3
+
4
+ use crate::{raise_err, RbPolarsErr, RbResult, RbSeries};
5
+
6
+ impl RbSeries {
7
+ /// For numeric types, this should only be called for Series with null types.
8
+ /// This will cast to floats so that `nil = NAN`
9
+ pub fn to_numo(&self) -> RbResult<Value> {
10
+ let s = &self.series.borrow();
11
+ match s.dtype() {
12
+ DataType::Utf8 => {
13
+ let ca = s.utf8().unwrap();
14
+
15
+ // TODO make more efficient
16
+ let np_arr = RArray::from_iter(ca.into_iter());
17
+ class::object()
18
+ .const_get::<_, RModule>("Numo")?
19
+ .const_get::<_, RClass>("RObject")?
20
+ .funcall("cast", (np_arr,))
21
+ }
22
+ dt if dt.is_numeric() => {
23
+ if s.bit_repr_is_large() {
24
+ let s = s.cast(&DataType::Float64).unwrap();
25
+ let ca = s.f64().unwrap();
26
+ // TODO make more efficient
27
+ let np_arr = RArray::from_iter(ca.into_iter().map(|opt_v| match opt_v {
28
+ Some(v) => v,
29
+ None => f64::NAN,
30
+ }));
31
+ class::object()
32
+ .const_get::<_, RModule>("Numo")?
33
+ .const_get::<_, RClass>("DFloat")?
34
+ .funcall("cast", (np_arr,))
35
+ } else {
36
+ let s = s.cast(&DataType::Float32).unwrap();
37
+ let ca = s.f32().unwrap();
38
+ // TODO make more efficient
39
+ let np_arr = RArray::from_iter(ca.into_iter().map(|opt_v| match opt_v {
40
+ Some(v) => v,
41
+ None => f32::NAN,
42
+ }));
43
+ class::object()
44
+ .const_get::<_, RModule>("Numo")?
45
+ .const_get::<_, RClass>("SFloat")?
46
+ .funcall("cast", (np_arr,))
47
+ }
48
+ }
49
+ dt => {
50
+ raise_err!(
51
+ format!("'to_numo' not supported for dtype: {dt:?}"),
52
+ ComputeError
53
+ );
54
+ }
55
+ }
56
+ }
57
+ }
@@ -489,40 +489,52 @@ impl RbSeries {
489
489
  }
490
490
 
491
491
  pub fn to_a(&self) -> RArray {
492
- let series = self.series.borrow();
493
- if let Ok(s) = series.f32() {
494
- s.into_iter().collect()
495
- } else if let Ok(s) = series.f64() {
496
- s.into_iter().collect()
497
- } else if let Ok(s) = series.i8() {
498
- s.into_iter().collect()
499
- } else if let Ok(s) = series.i16() {
500
- s.into_iter().collect()
501
- } else if let Ok(s) = series.i32() {
502
- s.into_iter().collect()
503
- } else if let Ok(s) = series.i64() {
504
- s.into_iter().collect()
505
- } else if let Ok(s) = series.u8() {
506
- s.into_iter().collect()
507
- } else if let Ok(s) = series.u16() {
508
- s.into_iter().collect()
509
- } else if let Ok(s) = series.u32() {
510
- s.into_iter().collect()
511
- } else if let Ok(s) = series.u64() {
512
- s.into_iter().collect()
513
- } else if let Ok(s) = series.bool() {
514
- s.into_iter().collect()
515
- } else if let Ok(s) = series.utf8() {
516
- s.into_iter().collect()
517
- } else if let Ok(_s) = series.date() {
518
- let a = RArray::with_capacity(series.len());
519
- for v in series.iter() {
520
- a.push::<Value>(Wrap(v).into_value()).unwrap();
521
- }
522
- a
523
- } else {
524
- unimplemented!();
492
+ let series = &self.series.borrow();
493
+
494
+ fn to_list_recursive(series: &Series) -> RArray {
495
+ let rblist = match series.dtype() {
496
+ DataType::Boolean => RArray::from_iter(series.bool().unwrap()),
497
+ DataType::UInt8 => RArray::from_iter(series.u8().unwrap()),
498
+ DataType::UInt16 => RArray::from_iter(series.u16().unwrap()),
499
+ DataType::UInt32 => RArray::from_iter(series.u32().unwrap()),
500
+ DataType::UInt64 => RArray::from_iter(series.u64().unwrap()),
501
+ DataType::Int8 => RArray::from_iter(series.i8().unwrap()),
502
+ DataType::Int16 => RArray::from_iter(series.i16().unwrap()),
503
+ DataType::Int32 => RArray::from_iter(series.i32().unwrap()),
504
+ DataType::Int64 => RArray::from_iter(series.i64().unwrap()),
505
+ DataType::Float32 => RArray::from_iter(series.f32().unwrap()),
506
+ DataType::Float64 => RArray::from_iter(series.f64().unwrap()),
507
+ DataType::Decimal128(_) => todo!(),
508
+ DataType::Categorical(_) => {
509
+ RArray::from_iter(series.categorical().unwrap().iter_str())
510
+ }
511
+ DataType::Date => {
512
+ let a = RArray::with_capacity(series.len());
513
+ for v in series.iter() {
514
+ a.push::<Value>(Wrap(v).into_value()).unwrap();
515
+ }
516
+ return a;
517
+ }
518
+ DataType::Datetime(_, _) => {
519
+ let a = RArray::with_capacity(series.len());
520
+ for v in series.iter() {
521
+ a.push::<Value>(Wrap(v).into_value()).unwrap();
522
+ }
523
+ return a;
524
+ }
525
+ DataType::Utf8 => {
526
+ let ca = series.utf8().unwrap();
527
+ return RArray::from_iter(ca);
528
+ }
529
+ DataType::Null | DataType::Unknown => {
530
+ panic!("to_a not implemented for null/unknown")
531
+ }
532
+ _ => todo!(),
533
+ };
534
+ rblist
525
535
  }
536
+
537
+ to_list_recursive(series)
526
538
  }
527
539
 
528
540
  pub fn median(&self) -> Option<f64> {
@@ -1,6 +1,8 @@
1
1
  module Polars
2
2
  # Two-dimensional data structure representing data as a table with rows and columns.
3
3
  class DataFrame
4
+ include Plot
5
+
4
6
  # @private
5
7
  attr_accessor :_df
6
8
 
@@ -604,10 +606,10 @@ module Polars
604
606
  return Slice.new(self).apply(item)
605
607
  end
606
608
 
607
- if Utils.is_str_sequence(item, allow_str: false)
609
+ if item.is_a?(Array) && item.all? { |v| Utils.strlike?(v) }
608
610
  # select multiple columns
609
611
  # df[["foo", "bar"]]
610
- return _from_rbdf(_df.select(item))
612
+ return _from_rbdf(_df.select(item.map(&:to_s)))
611
613
  end
612
614
 
613
615
  if Utils.is_int_sequence(item)
@@ -689,7 +691,8 @@ module Polars
689
691
  # @example
690
692
  # df = Polars::DataFrame.new({"foo" => [1, 2, 3], "bar" => [4, 5, 6]})
691
693
  # df.to_hashes
692
- # [{'foo': 1, 'bar': 4}, {'foo': 2, 'bar': 5}, {'foo': 3, 'bar': 6}]
694
+ # # =>
695
+ # # [{"foo"=>1, "bar"=>4}, {"foo"=>2, "bar"=>5}, {"foo"=>3, "bar"=>6}]
693
696
  def to_hashes
694
697
  rbdf = _df
695
698
  names = columns
@@ -699,8 +702,26 @@ module Polars
699
702
  end
700
703
  end
701
704
 
702
- # def to_numo
703
- # end
705
+ # Convert DataFrame to a 2D Numo array.
706
+ #
707
+ # This operation clones data.
708
+ #
709
+ # @return [Numo::NArray]
710
+ #
711
+ # @example
712
+ # df = Polars::DataFrame.new(
713
+ # {"foo" => [1, 2, 3], "bar" => [6, 7, 8], "ham" => ["a", "b", "c"]}
714
+ # )
715
+ # df.to_numo.class
716
+ # # => Numo::RObject
717
+ def to_numo
718
+ out = _df.to_numo
719
+ if out.nil?
720
+ Numo::NArray.vstack(width.times.map { |i| to_series(i).to_numo }).transpose
721
+ else
722
+ out
723
+ end
724
+ end
704
725
 
705
726
  # no to_pandas
706
727
 
@@ -84,6 +84,8 @@ module Polars
84
84
 
85
85
  # Calendar date and time type.
86
86
  class Datetime < TemporalType
87
+ attr_reader :tu
88
+
87
89
  def initialize(time_unit = "us", time_zone = nil)
88
90
  @tu = time_unit || "us"
89
91
  @time_zone = time_zone
@@ -92,6 +94,8 @@ module Polars
92
94
 
93
95
  # Time duration/delta type.
94
96
  class Duration < TemporalType
97
+ attr_reader :tu
98
+
95
99
  def initialize(time_unit = "us")
96
100
  @tu = time_unit
97
101
  end
@@ -571,5 +571,16 @@ module Polars
571
571
  def agg_list
572
572
  agg(Polars.all.list)
573
573
  end
574
+
575
+ # Plot data.
576
+ #
577
+ # @return [Vega::LiteChart]
578
+ def plot(*args, **options)
579
+ raise ArgumentError, "Multiple groups not supported" if by.is_a?(Array) && by.size > 1
580
+ # same message as Ruby
581
+ raise ArgumentError, "unknown keyword: :group" if options.key?(:group)
582
+
583
+ Utils.wrap_df(_df).plot(*args, **options, group: by)
584
+ end
574
585
  end
575
586
  end
@@ -0,0 +1,109 @@
1
+ module Polars
2
+ module Plot
3
+ # Plot data.
4
+ #
5
+ # @return [Vega::LiteChart]
6
+ def plot(x = nil, y = nil, type: nil, group: nil, stacked: nil)
7
+ require "vega"
8
+
9
+ raise ArgumentError, "Must specify columns" if columns.size != 2 && (!x || !y)
10
+ x ||= columns[0]
11
+ y ||= columns[1]
12
+ type ||= begin
13
+ if self[x].numeric? && self[y].numeric?
14
+ "scatter"
15
+ elsif self[x].utf8? && self[y].numeric?
16
+ "column"
17
+ elsif (self[x].dtype == Date || self[x].dtype.is_a?(Datetime)) && self[y].numeric?
18
+ "line"
19
+ else
20
+ raise "Cannot determine type. Use the type option."
21
+ end
22
+ end
23
+ df = self[(group.nil? ? [x, y] : [x, y, group]).map(&:to_s).uniq]
24
+ data = df.rows(named: true)
25
+
26
+ case type
27
+ when "line", "area"
28
+ x_type =
29
+ if df[x].numeric?
30
+ "quantitative"
31
+ elsif df[x].datelike?
32
+ "temporal"
33
+ else
34
+ "nominal"
35
+ end
36
+
37
+ scale = x_type == "temporal" ? {type: "utc"} : {}
38
+ encoding = {
39
+ x: {field: x, type: x_type, scale: scale},
40
+ y: {field: y, type: "quantitative"}
41
+ }
42
+ encoding[:color] = {field: group} if group
43
+
44
+ Vega.lite
45
+ .data(data)
46
+ .mark(type: type, tooltip: true, interpolate: "cardinal", point: {size: 60})
47
+ .encoding(encoding)
48
+ .config(axis: {labelFontSize: 12})
49
+ when "pie"
50
+ raise ArgumentError, "Cannot use group option with pie chart" unless group.nil?
51
+
52
+ Vega.lite
53
+ .data(data)
54
+ .mark(type: "arc", tooltip: true)
55
+ .encoding(
56
+ color: {field: x, type: "nominal", sort: "none", axis: {title: nil}, legend: {labelFontSize: 12}},
57
+ theta: {field: y, type: "quantitative"}
58
+ )
59
+ .view(stroke: nil)
60
+ when "column"
61
+ encoding = {
62
+ x: {field: x, type: "nominal", sort: "none", axis: {labelAngle: 0}},
63
+ y: {field: y, type: "quantitative"}
64
+ }
65
+ if group
66
+ encoding[:color] = {field: group}
67
+ encoding[:xOffset] = {field: group} unless stacked
68
+ end
69
+
70
+ Vega.lite
71
+ .data(data)
72
+ .mark(type: "bar", tooltip: true)
73
+ .encoding(encoding)
74
+ .config(axis: {labelFontSize: 12})
75
+ when "bar"
76
+ encoding = {
77
+ # TODO determine label angle
78
+ y: {field: x, type: "nominal", sort: "none", axis: {labelAngle: 0}},
79
+ x: {field: y, type: "quantitative"}
80
+ }
81
+ if group
82
+ encoding[:color] = {field: group}
83
+ encoding[:yOffset] = {field: group} unless stacked
84
+ end
85
+
86
+ Vega.lite
87
+ .data(data)
88
+ .mark(type: "bar", tooltip: true)
89
+ .encoding(encoding)
90
+ .config(axis: {labelFontSize: 12})
91
+ when "scatter"
92
+ encoding = {
93
+ x: {field: x, type: "quantitative", scale: {zero: false}},
94
+ y: {field: y, type: "quantitative", scale: {zero: false}},
95
+ size: {value: 60}
96
+ }
97
+ encoding[:color] = {field: group} if group
98
+
99
+ Vega.lite
100
+ .data(data)
101
+ .mark(type: "circle", tooltip: true)
102
+ .encoding(encoding)
103
+ .config(axis: {labelFontSize: 12})
104
+ else
105
+ raise ArgumentError, "Invalid type: #{type}"
106
+ end
107
+ end
108
+ end
109
+ end
data/lib/polars/series.rb CHANGED
@@ -1776,8 +1776,9 @@ module Polars
1776
1776
  # s.is_datelike
1777
1777
  # # => true
1778
1778
  def is_datelike
1779
- [Date, Datetime, Duration, Time].include?(dtype)
1779
+ [Date, Time].include?(dtype) || dtype.is_a?(Datetime) || dtype.is_a?(Duration)
1780
1780
  end
1781
+ alias_method :datelike?, :is_datelike
1781
1782
 
1782
1783
  # Check if this Series has floating point numbers.
1783
1784
  #
@@ -1823,8 +1824,45 @@ module Polars
1823
1824
  # def view
1824
1825
  # end
1825
1826
 
1826
- # def to_numo
1827
- # end
1827
+ # Convert this Series to a Numo array. This operation clones data but is completely safe.
1828
+ #
1829
+ # @return [Numo::NArray]
1830
+ #
1831
+ # @example
1832
+ # s = Polars::Series.new("a", [1, 2, 3])
1833
+ # s.to_numo
1834
+ # # =>
1835
+ # # Numo::Int64#shape=[3]
1836
+ # # [1, 2, 3]
1837
+ def to_numo
1838
+ if !has_validity
1839
+ if is_datelike
1840
+ Numo::RObject.cast(to_a)
1841
+ elsif is_numeric
1842
+ # TODO make more efficient
1843
+ {
1844
+ UInt8 => Numo::UInt8,
1845
+ UInt16 => Numo::UInt16,
1846
+ UInt32 => Numo::UInt32,
1847
+ UInt64 => Numo::UInt64,
1848
+ Int8 => Numo::Int8,
1849
+ Int16 => Numo::Int16,
1850
+ Int32 => Numo::Int32,
1851
+ Int64 => Numo::Int64,
1852
+ Float32 => Numo::SFloat,
1853
+ Float64 => Numo::DFloat
1854
+ }.fetch(dtype).cast(to_a)
1855
+ elsif is_boolean
1856
+ Numo::Bit.cast(to_a)
1857
+ else
1858
+ _s.to_numo
1859
+ end
1860
+ elsif is_datelike
1861
+ Numo::RObject.cast(to_a)
1862
+ else
1863
+ _s.to_numo
1864
+ end
1865
+ end
1828
1866
 
1829
1867
  # Set masked values.
1830
1868
  #
@@ -1,4 +1,4 @@
1
1
  module Polars
2
2
  # @private
3
- VERSION = "0.3.0"
3
+ VERSION = "0.3.1"
4
4
  end
data/lib/polars.rb CHANGED
@@ -15,6 +15,7 @@ require_relative "polars/batched_csv_reader"
15
15
  require_relative "polars/cat_expr"
16
16
  require_relative "polars/cat_name_space"
17
17
  require_relative "polars/convert"
18
+ require_relative "polars/plot"
18
19
  require_relative "polars/data_frame"
19
20
  require_relative "polars/data_types"
20
21
  require_relative "polars/date_time_expr"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: polars-df
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Kane
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-02-16 00:00:00.000000000 Z
11
+ date: 2023-02-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rb_sys
@@ -55,6 +55,7 @@ files:
55
55
  - ext/polars/src/lazy/utils.rs
56
56
  - ext/polars/src/lib.rs
57
57
  - ext/polars/src/list_construction.rs
58
+ - ext/polars/src/numo.rs
58
59
  - ext/polars/src/object.rs
59
60
  - ext/polars/src/prelude.rs
60
61
  - ext/polars/src/rb_modules.rs
@@ -84,6 +85,7 @@ files:
84
85
  - lib/polars/list_expr.rb
85
86
  - lib/polars/list_name_space.rb
86
87
  - lib/polars/meta_expr.rb
88
+ - lib/polars/plot.rb
87
89
  - lib/polars/rolling_group_by.rb
88
90
  - lib/polars/series.rb
89
91
  - lib/polars/slice.rb