lib/polars/series.rb in polars-df-0.1.1 vs lib/polars/series.rb in polars-df-0.1.2
- old
+ new
@@ -1,9 +1,40 @@
module Polars
+ # A Series represents a single column in a polars DataFrame.
class Series
+ # @private
attr_accessor :_s
+ # Create a new Series.
+ #
+ # @param name [String, Array, nil]
+ # Name of the series. Will be used as a column name when used in a DataFrame.
+ # When not specified, name is set to an empty string.
+ # @param values [Array, nil]
+ # One-dimensional data in various forms. Supported are: Array and Series.
+ # @param dtype [Symbol, nil]
+ # Polars dtype of the Series data. If not specified, the dtype is inferred.
+ # @param strict [Boolean]
+ # Throw error on numeric overflow.
+ # @param nan_to_null [Boolean]
+ # Not used.
+ # @param dtype_if_empty [Symbol, nil]
+ # If no dtype is specified and values contains `nil` or an empty array,
+ # set the Polars dtype of the Series data. If not specified, Float32 is used.
+ #
+ # @example Constructing a Series by specifying name and values positionally:
+ # s = Polars::Series.new("a", [1, 2, 3])
+ #
+ # @example Notice that the dtype is automatically inferred as a polars Int64:
+ # s.dtype
+ # # => :i64
+ #
+ # @example Constructing a Series with a specific dtype:
+ # s2 = Polars::Series.new("a", [1, 2, 3], dtype: :f32)
+ #
+ # @example It is possible to construct a Series with values as the first positional argument. This syntax considered an anti-pattern, but it can be useful in certain scenarios. You must specify any other arguments through keywords.
+ # s3 = Polars::Series.new([1, 2, 3])
def initialize(name = nil, values = nil, dtype: nil, strict: true, nan_to_null: false, dtype_if_empty: nil)
# Handle case where values are passed as the first argument
if !name.nil? && !name.is_a?(String)
if values.nil?
values = name
@@ -33,55 +64,87 @@
else
raise ArgumentError, "Series constructor called with unsupported type; got #{values.class.name}"
end
end
+ # @private
def self._from_rbseries(s)
series = Series.allocate
series._s = s
series
end
+ # Get the data type of this Series.
+ #
+ # @return [Symbol]
def dtype
- _s.dtype.to_sym
+ _s.dtype
end
+ # Get flags that are set on the Series.
+ #
+ # @return [Hash]
def flags
{
"SORTED_ASC" => _s.is_sorted_flag,
"SORTED_DESC" => _s.is_sorted_reverse_flag
}
end
+ # Get the inner dtype in of a List typed Series.
+ #
+ # @return [Symbol]
def inner_dtype
- _s.inner_dtype&.to_sym
+ _s.inner_dtype
end
+ # Get the name of this Series.
+ #
+ # @return [String]
def name
_s.name
end
+ # Shape of this Series.
+ #
+ # @return [Array]
def shape
[_s.len]
end
- # def time_unit
- # end
+ # Get the time unit of underlying Datetime Series as `"ns"`, `"us"`, or `"ms"`.
+ #
+ # @return [String]
+ def time_unit
+ _s.time_unit
+ end
+ # Returns a string representing the Series.
+ #
+ # @return [String]
def to_s
_s.to_s
end
alias_method :inspect, :to_s
+ # Bitwise AND.
+ #
+ # @return [Series]
def &(other)
Utils.wrap_s(_s.bitand(other._s))
end
+ # Bitwise OR.
+ #
+ # @return [Series]
def |(other)
Utils.wrap_s(_s.bitor(other._s))
end
+ # Bitwise XOR.
+ #
+ # @return [Series]
def ^(other)
Utils.wrap_s(_s.bitxor(other._s))
end
# def ==(other)
@@ -100,56 +163,109 @@
# end
# def <=(other)
# end
+ # Performs addition.
+ #
+ # @return [Series]
def +(other)
Utils. wrap_s(_s.add(other._s))
end
+ # Performs subtraction.
+ #
+ # @return [Series]
def -(other)
Utils.wrap_s(_s.sub(other._s))
end
+ # Performs multiplication.
+ #
+ # @return [Series]
def *(other)
Utils.wrap_s(_s.mul(other._s))
end
+ # Performs division.
+ #
+ # @return [Series]
def /(other)
Utils.wrap_s(_s.div(other._s))
end
+ # Raises to the power of exponent.
+ #
+ # @return [Series]
def **(power)
- # if is_datelike
- # raise ArgumentError, "first cast to integer before raising datelike dtypes to a power"
- # end
+ if is_datelike
+ raise ArgumentError, "first cast to integer before raising datelike dtypes to a power"
+ end
to_frame.select(Polars.col(name).pow(power)).to_series
end
# def -@(other)
# end
+ # Returns elements of the Series.
+ #
+ # @return [Object]
def [](item)
_s.get_idx(item)
end
# def []=(key, value)
# end
+ # Return an estimation of the total (heap) allocated size of the Series.
+ #
+ # Estimated size is given in the specified unit (bytes by default).
+ #
+ # This estimation is the sum of the size of its buffers, validity, including
+ # nested arrays. Multiple arrays may share buffers and bitmaps. Therefore, the
+ # size of 2 arrays is not the sum of the sizes computed from this function. In
+ # particular, StructArray's size is an upper bound.
+ #
+ # When an array is sliced, its allocated size remains constant because the buffer
+ # unchanged. However, this function will yield a smaller number. This is because
+ # this function returns the visible size of the buffer, not its total capacity.
+ #
+ # FFI buffers are included in this estimation.
+ #
+ # @param unit ["b", "kb", "mb", "gb", "tb"]
+ # Scale the returned size to the given unit.
+ #
+ # @return [Numeric]
+ #
+ # @example
+ # s = Polars::Series.new("values", 1..1_000_000, dtype: :u32)
+ # s.estimated_size
+ # # => 4000000
+ # s.estimated_size("mb")
+ # # => 3.814697265625
def estimated_size(unit = "b")
sz = _s.estimated_size
Utils.scale_bytes(sz, to: unit)
end
+ # Compute the square root of the elements.
+ #
+ # @return [Series]
def sqrt
- self ** 0.5
+ self**0.5
end
+ # Check if any boolean value in the column is `true`.
+ #
+ # @return [Boolean]
def any
to_frame.select(Polars.col(name).any).to_series[0]
end
+ # Check if all boolean values in the column are `true`.
+ #
+ # @return [Boolean]
def all
to_frame.select(Polars.col(name).all).to_series[0]
end
# def log
@@ -165,71 +281,201 @@
# end
# def drop_nans
# end
+ # Cast this Series to a DataFrame.
+ #
+ # @return [DataFrame]
def to_frame
Utils.wrap_df(RbDataFrame.new([_s]))
end
# def describe
# end
+ # Reduce this Series to the sum value.
+ #
+ # @return [Numeric]
+ #
+ # @note
+ # Dtypes `:i8`, `:u8`, `:i16`, and `:u16` are cast to
+ # `:i64` before summing to prevent overflow issues.
+ #
+ # @example
+ # s = Polars::Series.new("a", [1, 2, 3])
+ # s.sum
+ # # => 6
def sum
_s.sum
end
+ # Reduce this Series to the mean value.
+ #
+ # @return [Float, nil]
+ #
+ # @example
+ # s = Polars::Series.new("a", [1, 2, 3])
+ # s.mean
+ # # => 2.0
def mean
_s.mean
end
+ # Reduce this Series to the product value.
+ #
+ # @return [Numeric]
def product
to_frame.select(Polars.col(name).product).to_series[0]
end
+ # Get the minimal value in this Series.
+ #
+ # @return [Object]
+ #
+ # @example
+ # s = Polars::Series.new("a", [1, 2, 3])
+ # s.min
+ # # => 1
def min
_s.min
end
+ # Get the maximum value in this Series.
+ #
+ # @return [Object]
+ #
+ # @example
+ # s = Polars::Series.new("a", [1, 2, 3])
+ # s.max
+ # # => 3
def max
_s.max
end
# def nan_max
# end
# def nan_min
# end
+ # Get the standard deviation of this Series.
+ #
+ # @param ddof [Integer]
+ # “Delta Degrees of Freedom”: the divisor used in the calculation is N - ddof,
+ # where N represents the number of elements.
+ #
+ # @return [Float, nil]
+ #
+ # @example
+ # s = Polars::Series.new("a", [1, 2, 3])
+ # s.std
+ # # => 1.0
def std(ddof: 1)
if !is_numeric
nil
else
to_frame.select(Polars.col(name).std(ddof: ddof)).to_series[0]
end
end
+ # Get variance of this Series.
+ #
+ # @param ddof [Integer]
+ # “Delta Degrees of Freedom”: the divisor used in the calculation is N - ddof,
+ # where N represents the number of elements.
+ #
+ # @return [Float, nil]
+ #
+ # @example
+ # s = Polars::Series.new("a", [1, 2, 3])
+ # s.var
+ # # => 1.0
def var(ddof: 1)
if !is_numeric
nil
else
to_frame.select(Polars.col(name).var(ddof: ddof)).to_series[0]
end
end
+ # Get the median of this Series.
+ #
+ # @return [Float, nil]
+ #
+ # @example
+ # s = Polars::Series.new("a", [1, 2, 3])
+ # s.median
+ # # => 2.0
def median
_s.median
end
+ # Get the quantile value of this Series.
+ #
+ # @param quantile [Float, nil]
+ # Quantile between 0.0 and 1.0.
+ # @param interpolation ["nearest", "higher", "lower", "midpoint", "linear"]
+ # Interpolation method.
+ #
+ # @return [Float, nil]
+ #
+ # @example
+ # s = Polars::Series.new("a", [1, 2, 3])
+ # s.quantile(0.5)
+ # # => 2.0
def quantile(quantile, interpolation: "nearest")
_s.quantile(quantile, interpolation)
end
+ # Get dummy variables.
+ #
+ # @return [DataFrame]
+ #
+ # @example
+ # s = Polars::Series.new("a", [1, 2, 3])
+ # s.to_dummies
+ # # =>
+ # # shape: (3, 3)
+ # # ┌─────┬─────┬─────┐
+ # # │ a_1 ┆ a_2 ┆ a_3 │
+ # # │ --- ┆ --- ┆ --- │
+ # # │ u8 ┆ u8 ┆ u8 │
+ # # ╞═════╪═════╪═════╡
+ # # │ 1 ┆ 0 ┆ 0 │
+ # # ├╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌┤
+ # # │ 0 ┆ 1 ┆ 0 │
+ # # ├╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌┤
+ # # │ 0 ┆ 0 ┆ 1 │
+ # # └─────┴─────┴─────┘
def to_dummies
Utils.wrap_df(_s.to_dummies)
end
+ # Count the unique values in a Series.
+ #
+ # @param sort [Boolean]
+ # Ensure the output is sorted from most values to least.
+ #
+ # @return [DataFrame]
+ #
+ # @example
+ # s = Polars::Series.new("a", [1, 2, 2, 3])
+ # s.value_counts.sort("a")
+ # # =>
+ # # shape: (3, 2)
+ # # ┌─────┬────────┐
+ # # │ a ┆ counts │
+ # # │ --- ┆ --- │
+ # # │ i64 ┆ u32 │
+ # # ╞═════╪════════╡
+ # # │ 1 ┆ 1 │
+ # # ├╌╌╌╌╌┼╌╌╌╌╌╌╌╌┤
+ # # │ 2 ┆ 2 │
+ # # ├╌╌╌╌╌┼╌╌╌╌╌╌╌╌┤
+ # # │ 3 ┆ 1 │
+ # # └─────┴────────┘
def value_counts(sort: false)
Utils.wrap_df(_s.value_counts(sort))
end
# def unique_counts
@@ -239,78 +485,392 @@
# end
# def cumulative_eval
# end
+ # Return a copy of the Series with a new alias/name.
+ #
+ # @param name [String]
+ # New name.
+ #
+ # @return [Series]
+ #
+ # @example
+ # s = Polars::Series.new("x", [1, 2, 3])
+ # s.alias("y")
def alias(name)
s = dup
s._s.rename(name)
s
end
+ # Rename this Series.
+ #
+ # @param name [String]
+ # New name.
+ # @param in_place [Boolean]
+ # Modify the Series in-place.
+ #
+ # @return [Series]
+ #
+ # @example
+ # s = Polars::Series.new("a", [1, 2, 3])
+ # s.rename("b")
def rename(name, in_place: false)
if in_place
_s.rename(name)
self
else
self.alias(name)
end
end
+ # Get the length of each individual chunk.
+ #
+ # @return [Array]
+ #
+ # @example
+ # s = Polars::Series.new("a", [1, 2, 3])
+ # s2 = Polars::Series.new("b", [4, 5, 6])
+ #
+ # @example Concatenate Series with rechunk: true
+ # Polars.concat([s, s2]).chunk_lengths
+ # # => [6]
+ #
+ # @example Concatenate Series with rechunk: false
+ # Polars.concat([s, s2], rechunk: false).chunk_lengths
+ # # => [3, 3]
def chunk_lengths
_s.chunk_lengths
end
+ # Get the number of chunks that this Series contains.
+ #
+ # @return [Integer]
+ #
+ # @example
+ # s = Polars::Series.new("a", [1, 2, 3])
+ # s2 = Polars::Series.new("b", [4, 5, 6])
+ #
+ # @example Concatenate Series with rechunk: true
+ # Polars.concat([s, s2]).n_chunks
+ # # => 1
+ #
+ # @example Concatenate Series with rechunk: false
+ # Polars.concat([s, s2], rechunk: false).n_chunks
+ # # => 2
def n_chunks
_s.n_chunks
end
+ # Get an array with the cumulative sum computed at every element.
+ #
+ # @param reverse [Boolean]
+ # reverse the operation.
+ #
+ # @return [Series]
+ #
+ # @note
+ # Dtypes `:i8`, `:u8`, `:i16`, and `:u16` are cast to
+ # `:i64` before summing to prevent overflow issues.
+ #
+ # @example
+ # s = Polars::Series.new("a", [1, 2, 3])
+ # s.cumsum
+ # # =>
+ # # shape: (3,)
+ # # Series: 'a' [i64]
+ # # [
+ # # 1
+ # # 3
+ # # 6
+ # # ]
def cumsum(reverse: false)
Utils.wrap_s(_s.cumsum(reverse))
end
+ # Get an array with the cumulative min computed at every element.
+ #
+ # @param reverse [Boolean]
+ # reverse the operation.
+ #
+ # @return [Series]
+ #
+ # @example
+ # s = Polars::Series.new("a", [3, 5, 1])
+ # s.cummin
+ # # =>
+ # # shape: (3,)
+ # # Series: 'a' [i64]
+ # # [
+ # # 3
+ # # 3
+ # # 1
+ # # ]
def cummin(reverse: false)
Utils.wrap_s(_s.cummin(reverse))
end
+ # Get an array with the cumulative max computed at every element.
+ #
+ # @param reverse [Boolean]
+ # reverse the operation.
+ #
+ # @return [Series]
+ #
+ # @example
+ # s = Polars::Series.new("a", [3, 5, 1])
+ # s.cummax
+ # # =>
+ # # shape: (3,)
+ # # Series: 'a' [i64]
+ # # [
+ # # 3
+ # # 5
+ # # 5
+ # # ]
def cummax(reverse: false)
Utils.wrap_s(_s.cummax(reverse))
end
+ # Get an array with the cumulative product computed at every element.
+ #
+ # @param reverse [Boolean]
+ # reverse the operation.
+ #
+ # @return [Series]
+ #
+ # @note
+ # Dtypes `:i8`, `:u8`, `:i16`, and `:u16` are cast to
+ # `:i64` before multiplying to prevent overflow issues.
+ #
+ # @example
+ # s = Polars::Series.new("a", [1, 2, 3])
+ # s.cumprod
+ # # =>
+ # # shape: (3,)
+ # # Series: 'a' [i64]
+ # # [
+ # # 1
+ # # 2
+ # # 6
+ # # ]
def cumprod(reverse: false)
Utils.wrap_s(_s.cumprod(reverse))
end
+ # Get the first `n` rows.
+ #
+ # Alias for {#head}.
+ #
+ # @param n [Integer]
+ # Number of rows to return.
+ #
+ # @return [Series]
+ #
+ # @example
+ # s = Polars::Series.new("a", [1, 2, 3])
+ # s.limit(2)
+ # # =>
+ # # shape: (2,)
+ # # Series: 'a' [i64]
+ # # [
+ # # 1
+ # # 2
+ # # ]
def limit(n = 10)
to_frame.select(Utils.col(name).limit(n)).to_series
end
+ # Get a slice of this Series.
+ #
+ # @param offset [Integer]
+ # Start index. Negative indexing is supported.
+ # @param length [Integer, nil]
+ # Length of the slice. If set to `nil`, all rows starting at the offset
+ # will be selected.
+ #
+ # @return [Series]
+ #
+ # @example
+ # s = Polars::Series.new("a", [1, 2, 3, 4])
+ # s.slice(1, 2)
+ # # =>
+ # # shape: (2,)
+ # # Series: 'a' [i64]
+ # # [
+ # # 2
+ # # 3
+ # # ]
def slice(offset, length = nil)
length = len if length.nil?
Utils.wrap_s(_s.slice(offset, length))
end
- def append(other)
- _s.append(other._s)
+ # Append a Series to this one.
+ #
+ # @param other [Series]
+ # Series to append.
+ # @param append_chunks [Boolean]
+ # If set to `true` the append operation will add the chunks from `other` to
+ # self. This is super cheap.
+ #
+ # If set to `false` the append operation will do the same as
+ # {DataFrame#extend} which extends the memory backed by this Series with
+ # the values from `other`.
+ #
+ # Different from `append_chunks`, `extend` appends the data from `other` to
+ # the underlying memory locations and thus may cause a reallocation (which is
+ # expensive).
+ #
+ # If this does not cause a reallocation, the resulting data structure will not
+ # have any extra chunks and thus will yield faster queries.
+ #
+ # Prefer `extend` over `append_chunks` when you want to do a query after a
+ # single append. For instance during online operations where you add `n` rows
+ # and rerun a query.
+ #
+ # Prefer `append_chunks` over `extend` when you want to append many times
+ # before doing a query. For instance, when you read in multiple files and when
+ # to store them in a single Series. In the latter case, finish the sequence
+ # of `append_chunks` operations with a `rechunk`.
+ #
+ # @return [Series]
+ #
+ # @example
+ # s = Polars::Series.new("a", [1, 2, 3])
+ # s2 = Polars::Series.new("b", [4, 5, 6])
+ # s.append(s2)
+ # # =>
+ # # shape: (6,)
+ # # Series: 'a' [i64]
+ # # [
+ # # 1
+ # # 2
+ # # 3
+ # # 4
+ # # 5
+ # # 6
+ # # ]
+ def append(other, append_chunks: true)
+ begin
+ if append_chunks
+ _s.append(other._s)
+ else
+ _s.extend(other._s)
+ end
+ rescue => e
+ if e.message == "Already mutably borrowed"
+ append(other.clone, append_chunks)
+ else
+ raise e
+ end
+ end
self
end
+ # Filter elements by a boolean mask.
+ #
+ # @param predicate [Series, Array]
+ # Boolean mask.
+ #
+ # @return [Series]
+ #
+ # @example
+ # s = Polars::Series.new("a", [1, 2, 3])
+ # mask = Polars::Series.new("", [true, false, true])
+ # s.filter(mask)
+ # # =>
+ # # shape: (2,)
+ # # Series: 'a' [i64]
+ # # [
+ # # 1
+ # # 3
+ # # ]
def filter(predicate)
+ if predicate.is_a?(Array)
+ predicate = Series.new("", predicate)
+ end
Utils.wrap_s(_s.filter(predicate._s))
end
+ # Get the first `n` rows.
+ #
+ # @param n [Integer]
+ # Number of rows to return.
+ #
+ # @return [Series]
+ #
+ # @example
+ # s = Polars::Series.new("a", [1, 2, 3])
+ # s.head(2)
+ # # =>
+ # # shape: (2,)
+ # # Series: 'a' [i64]
+ # # [
+ # # 1
+ # # 2
+ # # ]
def head(n = 10)
to_frame.select(Utils.col(name).head(n)).to_series
end
+ # Get the last `n` rows.
+ #
+ # @param n [Integer]
+ # Number of rows to return.
+ #
+ # @return [Series]
+ #
+ # @example
+ # s = Polars::Series.new("a", [1, 2, 3])
+ # s.tail(2)
+ # # =>
+ # # shape: (2,)
+ # # Series: 'a' [i64]
+ # # [
+ # # 2
+ # # 3
+ # # ]
def tail(n = 10)
to_frame.select(Utils.col(name).tail(n)).to_series
end
# def take_every
# end
+ # Sort this Series.
+ #
+ # @param reverse [Boolean]
+ # Reverse sort.
+ # @param in_place [Boolean]
+ # Sort in place.
+ #
+ # @return [Series]
+ #
+ # @example
+ # s = Polars::Series.new("a", [1, 3, 4, 2])
+ # s.sort
+ # # =>
+ # # shape: (4,)
+ # # Series: 'a' [i64]
+ # # [
+ # # 1
+ # # 2
+ # # 3
+ # # 4
+ # # ]
+ # s.sort(reverse: true)
+ # # =>
+ # # shape: (4,)
+ # # Series: 'a' [i64]
+ # # [
+ # # 4
+ # # 3
+ # # 2
+ # # 1
+ # # ]
def sort(reverse: false, in_place: false)
if in_place
self._s = _s.sort(reverse)
self
else
@@ -328,14 +888,30 @@
# end
# def arg_unique
# end
+ # Get the index of the minimal value.
+ #
+ # @return [Integer, nil]
+ #
+ # @example
+ # s = Polars::Series.new("a", [3, 2, 1])
+ # s.arg_min
+ # # => 2
def arg_min
_s.arg_min
end
+ # Get the index of the maximal value.
+ #
+ # @return [Integer, nil]
+ #
+ # @example
+ # s = Polars::Series.new("a", [3, 2, 1])
+ # s.arg_max
+ # # => 0
def arg_max
_s.arg_max
end
# def search_sorted
@@ -345,18 +921,35 @@
# end
# def take
# end
+ # Count the null values in this Series.
+ #
+ # @return [Integer]
def null_count
_s.null_count
end
+ # Return True if the Series has a validity bitmask.
+ #
+ # If there is none, it means that there are no null values.
+ # Use this to swiftly assert a Series does not have null values.
+ #
+ # @return [Boolean]
def has_validity
_s.has_validity
end
+ # Check if the Series is empty.
+ #
+ # @return [Boolean]
+ #
+ # @example
+ # s = Polars::Series.new("a", [])
+ # s.is_empty
+ # # => true
def is_empty
len == 0
end
alias_method :empty?, :is_empty
@@ -394,54 +987,139 @@
# end
# def explode
# end
+ # Check if series is equal with another Series.
+ #
+ # @param other [Series]
+ # Series to compare with.
+ # @param null_equal [Boolean]
+ # Consider null values as equal.
+ # @param strict [Boolean]
+ # Don't allow different numerical dtypes, e.g. comparing `:u32` with a
+ # `:i64` will return `false`.
+ #
+ # @return [Boolean]
+ #
+ # @example
+ # s = Polars::Series.new("a", [1, 2, 3])
+ # s2 = Polars::Series.new("b", [4, 5, 6])
+ # s.series_equal(s)
+ # # => true
+ # s.series_equal(s2)
+ # # => false
def series_equal(other, null_equal: false, strict: false)
_s.series_equal(other._s, null_equal, strict)
end
+ # Length of this Series.
+ #
+ # @return [Integer]
+ #
+ # @example
+ # s = Polars::Series.new("a", [1, 2, 3])
+ # s.len
+ # # => 3
def len
_s.len
end
+ alias_method :length, :len
# def cast
# end
# def to_physical
# end
+ # Convert this Series to a Ruby Array. This operation clones data.
+ #
+ # @return [Array]
+ #
+ # @example
+ # s = Polars::Series.new("a", [1, 2, 3])
+ # s.to_a
+ # # => [1, 2, 3]
def to_a
_s.to_a
end
+ # Create a single chunk of memory for this Series.
+ #
+ # @param in_place [Boolean]
+ # In place or not.
+ #
+ # @return [Series]
def rechunk(in_place: false)
opt_s = _s.rechunk(in_place)
in_place ? self : Utils.wrap_s(opt_s)
end
# def reverse
# end
+ # Check if this Series datatype is numeric.
+ #
+ # @return [Boolean]
+ #
+ # @example
+ # s = Polars::Series.new("a", [1, 2, 3])
+ # s.is_numeric
+ # # => true
def is_numeric
[:i8, :i16, :i32, :i64, :u8, :u16, :u32, :u64, :f32, :f64].include?(dtype)
end
alias_method :numeric?, :is_numeric
- # def is_datelike
- # end
+ # Check if this Series datatype is datelike.
+ #
+ # @return [Boolean]
+ #
+ # @example
+ # s = Polars::Series.new([Date.new(2021, 1, 1), Date.new(2021, 1, 2), Date.new(2021, 1, 3)])
+ # s.is_datelike
+ # # => true
+ def is_datelike
+ [:date, :datetime, :duration, :time].include?(dtype)
+ end
+ # Check if this Series has floating point numbers.
+ #
+ # @return [Boolean]
+ #
+ # @example
+ # s = Polars::Series.new("a", [1.0, 2.0, 3.0])
+ # s.is_float
+ # # => true
def is_float
[:f32, :f64].include?(dtype)
end
alias_method :float?, :is_float
- def is_bool
+ # Check if this Series is a Boolean.
+ #
+ # @return [Boolean]
+ #
+ # @example
+ # s = Polars::Series.new("a", [true, false, true])
+ # s.is_boolean
+ # # => true
+ def is_boolean
dtype == :bool
end
- alias_method :bool?, :is_bool
+ alias_method :boolean?, :is_boolean
+ alias_method :is_bool, :is_boolean
+ alias_method :bool?, :is_boolean
+ # Check if this Series datatype is a Utf8.
+ #
+ # @return [Boolean]
+ #
+ # @example
+ # s = Polars::Series.new("x", ["a", "b", "c"])
+ # s.is_utf8
+ # # => true
def is_utf8
dtype == :str
end
alias_method :utf8?, :is_utf8
@@ -466,19 +1144,70 @@
# end
# def fill_null
# end
+ # Rounds down to the nearest integer value.
+ #
+ # Only works on floating point Series.
+ #
+ # @return [Series]
+ #
+ # @example
+ # s = Polars::Series.new("a", [1.12345, 2.56789, 3.901234])
+ # s.floor
+ # # =>
+ # # shape: (3,)
+ # # Series: 'a' [f64]
+ # # [
+ # # 1.0
+ # # 2.0
+ # # 3.0
+ # # ]
def floor
Utils.wrap_s(_s.floor)
end
+ # Rounds up to the nearest integer value.
+ #
+ # Only works on floating point Series.
+ #
+ # @return [Series]
+ #
+ # @example
+ # s = Polars::Series.new("a", [1.12345, 2.56789, 3.901234])
+ # s.ceil
+ # # =>
+ # # shape: (3,)
+ # # Series: 'a' [f64]
+ # # [
+ # # 2.0
+ # # 3.0
+ # # 4.0
+ # # ]
def ceil
Utils.wrap_s(_s.ceil)
end
- # default to 0 like Ruby
+ # Round underlying floating point data by `decimals` digits.
+ #
+ # @param decimals [Integer]
+ # number of decimals to round by.
+ #
+ # @return [Series]
+ #
+ # @example
+ # s = Polars::Series.new("a", [1.12345, 2.56789, 3.901234])
+ # s.round(2)
+ # # =>
+ # # shape: (3,)
+ # # Series: 'a' [f64]
+ # # [
+ # # 1.12
+ # # 2.57
+ # # 3.9
+ # # ]
def round(decimals = 0)
Utils.wrap_s(_s.round(decimals))
end
# def dot
@@ -569,18 +1298,60 @@
# end
# def sample
# end
+ # Get a boolean mask of the local maximum peaks.
+ #
+ # @return [Series]
+ #
+ # @example
+ # s = Polars::Series.new("a", [1, 2, 3, 4, 5])
+ # s.peak_max
+ # # =>
+ # # shape: (5,)
+ # # Series: '' [bool]
+ # # [
+ # # false
+ # # false
+ # # false
+ # # false
+ # # true
+ # # ]
def peak_max
Utils.wrap_s(_s.peak_max)
end
+ # Get a boolean mask of the local minimum peaks.
+ #
+ # @return [Series]
+ #
+ # @example
+ # s = Polars::Series.new("a", [4, 1, 3, 2, 5])
+ # s.peak_min
+ # # =>
+ # # shape: (5,)
+ # # Series: '' [bool]
+ # # [
+ # # false
+ # # true
+ # # false
+ # # true
+ # # false
+ # # ]
def peak_min
Utils.wrap_s(_s.peak_min)
end
+ # Count the number of unique values in this Series.
+ #
+ # @return [Integer]
+ #
+ # @example
+ # s = Polars::Series.new("a", [1, 2, 2, 3])
+ # s.n_unique
+ # # => 3
def n_unique
_s.n_unique
end
# def shrink_to_fit
@@ -638,10 +1409,27 @@
# end
# def extend_constant
# end
+ # Flags the Series as sorted.
+ #
+ # Enables downstream code to user fast paths for sorted arrays.
+ #
+ # @param reverse [Boolean]
+ # If the Series order is reversed, e.g. descending.
+ #
+ # @return [Series]
+ #
+ # @note
+ # This can lead to incorrect results if this Series is not sorted!!
+ # Use with care!
+ #
+ # @example
+ # s = Polars::Series.new("a", [1, 2, 3])
+ # s.set_sorted.max
+ # # => 3
def set_sorted(reverse: false)
Utils.wrap_s(_s.set_sorted(reverse))
end
# def new_from_index
@@ -714,10 +1502,10 @@
# dtype = rb_type_to_dtype(ruby_dtype)
# elsif rb_temporal_types.include?(dtype)
# dtype = rb_type_to_dtype(dtype)
# end
- raise "todo"
+ raise Todo
else
constructor = rb_type_to_constructor(value.class)
constructor.call(name, values, strict)
end
end