tada

package module
v0.3.5 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 21, 2020 License: Apache-2.0 Imports: 19 Imported by: 0

README

tada logo

Go Report Card GoDoc Build Status codecov

tada

tada (TAble DAta) is a package that enables test-driven data pipelines in pure Go.

DISCLAIMER: still under development. API subject to breaking changes until v1. Use in production at your own risk.

tada combines concepts from pandas, spreadsheets, R, Apache Spark, and SQL. Its most common use cases are cleaning, aggregating, transforming, and analyzing data.

Some notable features of tada:

  • flexible constructor that supports most primitive data types
  • seamlessly handles null data and type conversions
  • well-suited to conventional IDE-based programming, but also supports exploratory notebook usage
  • robust datetime support
  • advanced filtering, lookups and merging, grouping, sorting, and pivoting
  • multi-level labels and columns
  • complete test coverage
  • comparable to pandas performance on key operations

The key data types are Series, DataFrames, and groupings of each. A Series is analogous to one column of a spreadsheet, and a DataFrame is analogous to a whole spreadsheet. Printing either data type will render an ASCII table.

Both Series and DataFrames have one or more "label levels". On printing, these appear as the leftmost columns in a table, and typically have values that help identify ("label") specific rows. They are analogous to the "index" concept in pandas.

For more detail and implementation notes, see this doc.

Logo: @egonelbre, licensed under CC0

Example

You start with a CSV. Like most real-world data, it is messy. This one is missing a score in the first row. And we know that scores must range between 0 and 10, so the score of -100 and 1000 in the second and third rows must also be erroneous:

var data = `name, score
            joe doe,
            john doe, -100
            jane doe, 1000
            john doe, 5
            jane doe, 8
            john doe, 7
            jane doe, 10`

You want to write and validate a function that discards erroneous data, groups by the name column, and returns the mean of the groups.

First you write a test:

func Test_TransformData(t *testing.T) {
  want := `name, mean_score
           jane doe, 9
           john doe, 6`


  // this block is equivalent to tada.ReadCSVFromString(data)
	r := strings.NewReader(data)
	cr := csv.NewReader(r)
	cr.TrimLeadingSpace = true
	records, err := cr.ReadAll()
	... handle err
	df, _ := ReadCSV(records)

  ret := TransformData(df)
  ok, diffs, err := ret.EqualsCSVFromString(want)
  ... handle err
  if !ok {
    t.Errorf("TransformData(): got %v, want %v, has diffs: \n%v", ret, want, diffs)
  }
}

Then you write the transformation steps:

func TransformData(df *tada.DataFrame) *tada.DataFrame {
  err := df.HasCols("name", "score")
    ... handle err
  df.InPlace().DropNull()
  validScore := tada.FilterFn{Float64: func(v float64) bool { return v >= 0 && v <= 10 }}
	
  df.InPlace().Filter(map[string]tada.FilterFn{"score": validScore})
  df.InPlace().Sort(tada.Sorter{Name: "name", DType: tada.String})
  return df.GroupBy("name").Mean("score")
}

Extended tutorial

Usage

Constructor:
Series

s := tada.Series([]float{1,2,3})

with one level of labels

s := tada.Series([]float{1,2,3}, []string{"foo", "bar", "baz"})

DataFrame

df := tada.DataFrame([]interface{}{[]string{"foo"}, []float{2}})

Reading from CSV

df := tada.ImportCSV("foo.csv")

See examples

Using with Jupyter notebooks

  • Follow the instructions for installing gophernotes, including jupyter.
  • Install tada from anywhere using Go modules (this will install the latest version to $GOPATH/pkg/mod/ptiger10/tada, which is what gophernotes references to import 3rd party packages): $ GO111MODULE=on go get -u github.com/ptiger10/tada
  • Run the same snippet whenever you want gophernotes to have access to the latest version of tada.
  • $ jupyter notebook (should launch a window in your default browser)
  • From Home screen -> New -> Go

One of the biggest limitations of gophernotes is that it does not provide signature hinting. This is a known issue.

Sample Notebook

Performance Tuning

  • Modify a Series or DataFrame in place (without returning a new copy) by first calling InPlace().
  • If you expect to use a column as numeric, string, or time.Time values multiple times, Cast() it to tada.Float64, tada.String, or tada.DateTime, respectively.

Documentation

Overview

Package tada (TAble DAta) enables test-driven data pipelines.

tada combines concepts from pandas, spreadsheets, R, Apache Spark, and SQL. Its most common use cases are cleaning, aggregating, transforming, and analyzing data. Some notable features of tada:

* flexible constructor that supports most primitive data types

* seamlessly handles null data and type conversions

* well-suited to conventional IDE-based programming, but also supports notebook usage

* robust datetime support

* advanced filtering, lookups and merging, grouping, sorting, and pivoting

* multi-level labels and columns

* complete test coverage

The key data types are Series, DataFrames, and groupings of each. A Series is analogous to one column of a spreadsheet, and a DataFrame is analogous to a whole spreadsheet. Printing either data type will render an ASCII table.

Both Series and DataFrames have one or more "label levels". On printing, these appear as the leftmost columns in a table, and typically have values that help identify ("label") specific rows. They are analogous to the "index" concept in pandas.

For more detail and implementation notes, see https://docs.google.com/document/d/18DvZzd6Tg6Bz0SX0fY2SrXOjE8d9xDhU6bDEnaIc_rM/

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func DisableWarnings

func DisableWarnings()

DisableWarnings prevents tada from writing warning messages to the default log writer.

func EnableWarnings

func EnableWarnings()

EnableWarnings allows tada to write warning messages to the default log writer.

func EqualDataFrames

func EqualDataFrames(a, b *DataFrame) bool

EqualDataFrames returns whether two dataframes are identical or not

func EqualSeries

func EqualSeries(a, b *Series) bool

EqualSeries returns whether two Series are identical or not.

func MakeMultiLevelLabels

func MakeMultiLevelLabels(labels []interface{}) ([]interface{}, error)

MakeMultiLevelLabels expects `labels` to be a slice of slices. It returns a product of these slices by repeating each label value n times, where n is the number of unique label values in the other slices.

For example, [["foo", "bar"], [1, 2, 3]] returns [["foo", "foo", "foo", "bar", "bar", "bar"], [1, 2, 3, 1, 2, 3]]

func PrintOptionMaxColumns added in v0.1.0

func PrintOptionMaxColumns(n int)

PrintOptionMaxColumns changes the max number of columns displayed when printing a Series or DataFrame to `n` (default: 20).

Example
df := NewDataFrame([]interface{}{
	[]float64{1, 2}, []float64{3, 4}, []float64{5, 6},
	[]float64{3, 4}, []float64{5, 6},
}).SetColNames([]string{"A", "B", "C", "D", "E"})
archive := optionMaxColumns
PrintOptionMaxColumns(2)
fmt.Println(df)
PrintOptionMaxColumns(archive)
Output:
+---++---+-----+---+
| - || A | ... | E |
|---||---|-----|---|
| 0 || 1 | ... | 5 |
| 1 || 2 |     | 6 |
+---++---+-----+---+

func PrintOptionMaxRows added in v0.1.0

func PrintOptionMaxRows(n int)

PrintOptionMaxRows changes the max number of rows displayed when printing a Series or DataFrame to `n` (default: 50).

Example
df := NewDataFrame([]interface{}{
	[]float64{1, 2, 3, 4, 5, 6, 7, 8}}).SetColNames([]string{"A"})
archive := optionMaxRows
PrintOptionMaxRows(6)
fmt.Println(df)
PrintOptionMaxRows(archive)
Output:
+-----++-----+
|  -  ||  A  |
|-----||-----|
|   0 ||   1 |
|   1 ||   2 |
|   2 ||   3 |
| ... || ... |
|   5 ||   6 |
|   6 ||   7 |
|   7 ||   8 |
+-----++-----+

func PrintOptionMergeRepeats added in v0.1.0

func PrintOptionMergeRepeats(set bool)

PrintOptionMergeRepeats (if true) instructs the String() function to merge repeated non-header values when printing a Series or DataFrame (default: true).

func PrintOptionWrapLines added in v0.1.0

func PrintOptionWrapLines(set bool)

PrintOptionWrapLines (if true) instructs the String() function to wrap overly-wide rows onto new lines instead of truncating them when printing a Series or DataFrame (default: truncate).

func ReadOptionDelimiter added in v0.1.0

func ReadOptionDelimiter(sep rune) func(*readConfig)

ReadOptionDelimiter configures a read function to use `sep` as a field delimiter for use in ImportCSV or ReadCSVFromString (default: ",").

func ReadOptionHeaders added in v0.1.0

func ReadOptionHeaders(n int) func(*readConfig)

ReadOptionHeaders configures a read function to expect `n` rows of column headers (default: 1).

func ReadOptionLabels added in v0.1.0

func ReadOptionLabels(n int) func(*readConfig)

ReadOptionLabels configures a read function to expect the first `n` columns to be label levels (default: 0).

func ReadOptionSwitchDims added in v0.1.0

func ReadOptionSwitchDims() func(*readConfig)

ReadOptionSwitchDims configures a read function to expect columns to be the major dimension of csv data (default: expects rows to be the major dimension). For example, when reading this data:

[["foo", "bar"], ["baz", "qux"]]

`default` `ReadOptionSwitchDims()` (major dimension: rows) (major dimension: columns)

	foo bar							foo baz
 baz qux							bar qux

func SetOptionAddTimeFormat

func SetOptionAddTimeFormat(format string)

SetOptionAddTimeFormat adds `format` to the list of time formats that can be parsed when converting values from string to time.Time

func SetOptionDefaultSeparator added in v0.1.0

func SetOptionDefaultSeparator(sep string)

SetOptionDefaultSeparator changes the separator used in group names and multi-level column names to `sep` (default: "|").

func WriteMockCSV

func WriteMockCSV(src [][]string, w io.Writer, n int, options ...func(*readConfig)) error

WriteMockCSV reads `src` (configured by `options`) and writes `n` mock rows to `w`, with column names and types inferred based on the data in `src`. Regardless of the major dimension of `src`, the major dimension of the output is rows. Available options: ReadOptionHeaders, ReadOptionLabels, ReadOptionSwitchDims.

Default if no options are supplied: 1 header row, no labels, rows as major dimension

Types

type ApplyFn

type ApplyFn struct {
	Float64  func(val float64) float64
	String   func(val string) string
	DateTime func(val time.Time) time.Time
}

An ApplyFn supplies logic to the Apply() function. Only the first field selected (i.e., not left nil) is used - any others are ignored. Values are coerced to the type specified in the field (e.g., DateTime -> time.Time) before the apply function is evaluated.

type ApplyFormatFn

type ApplyFormatFn struct {
	Float64  func(val float64) string
	DateTime func(val time.Time) string
}

An ApplyFormatFn supplies logic to the ApplyFormat() function. Only the first field selected (i.e., not left nil) is used - any others are ignored. Values are coerced to the type specified in the field (e.g., DateTime -> time.Time) before the formatting function is evaluated.

type Cutter

type Cutter struct {
	AndLess bool
	AndMore bool
	Labels  []string
}

Cutter supplies logic for the Cut() function. If `AndLess` is true, a bin is added that ranges between negative infinity and the first bin value. If `AndMore` is true, a bin is added that ranges between the last bin value and positive infinity. If `Labels` is not nil, then category names correspond to labels, and the number of labels must be one less than the number of bin values. Otherwise, category names are auto-generated from the range of the bin intervals.

type DType

type DType int

DType is a DataType that may be used in Sort() or Cast().

const (
	// Float64 -> float64
	Float64 DType = iota
	// String -> string
	String
	// DateTime -> time.Time
	DateTime
)

type DataFrame

type DataFrame struct {
	// contains filtered or unexported fields
}

A DataFrame is one or more columns of data with one or more levels of aligned labels. A DataFrame is analogous to a spreadsheet.

Example
df := NewDataFrame([]interface{}{
	[]float64{1, 2}, []string{"baz", "qux"}},
)
fmt.Println(df)
Output:
+---++---+-----+
| - || 0 |  1  |
|---||---|-----|
| 0 || 1 | baz |
| 1 || 2 | qux |
+---++---+-----+
Example (WithError)
df := &DataFrame{err: errors.New("foo")}
fmt.Println(df)
Output:
Error: foo
Example (WithNullValues)
df := NewDataFrame([]interface{}{[]float64{math.NaN(), 2}, []string{"foo", ""}}).SetColNames([]string{"a", "b"}).SetName("qux")
fmt.Println(df)
Output:
+---++-----+-----+
| - ||  a  |  b  |
|---||-----|-----|
| 0 || n/a | foo |
| 1 ||   2 | n/a |
+---++-----+-----+
name: qux

func ConcatSeries

func ConcatSeries(series ...*Series) (*DataFrame, error)

ConcatSeries concatenates multiple Series with identical labels into a single DataFrame. To join Series with different labels, use s.ToDataFrame() + df.Merge() (for simple cases) or df.LookupAdvanced() + df.WithCol() (for advanced cases)

func ImportCSV

func ImportCSV(path string, options ...func(*readConfig)) (*DataFrame, error)

ImportCSV reads the file at `path` into a Dataframe (configured by `options`). For advanced cases, use the standard csv library NewReader().ReadAll() + tada.ReadCSV(). Available options: ReadOptionHeaders, ReadOptionLabels, ReadOptionDelimiter, ReadOptionSwitchDims.

Default if no options are supplied: 1 header row, no labels, field delimiter is ",", rows as major dimension

If no labels are supplied, a default label level is inserted ([]int incrementing from 0). If no headers are supplied, a default level of sequential column names (e.g., 0, 1, etc) is used. Default column names are displayed on printing Label levels are named *i (e.g., *0, *1, etc) by default when first created. Default label names are hidden on printing.

func NewDataFrame

func NewDataFrame(slices []interface{}, labels ...interface{}) *DataFrame

NewDataFrame creates a new DataFrame with `slices` (akin to column values) and optional `labels`. `Slices` must be comprised of supported slices, and each `label` must be a supported slice.

If no `labels` are supplied, a default label level is inserted ([]int incrementing from 0). Columns are named sequentially (e.g., 0, 1, etc) by default. Default column names are displayed on printing. Label levels are named *n (e.g., *0, *1, etc) by default. Default label names are hidden on printing.

Supported slice types: all variants of []float, []int, & []uint, []string, []bool, []time.Time, []interface{}, and 2-dimensional variants of each (e.g., [][]string, [][]float64).

func ReadCSV

func ReadCSV(data [][]string, options ...func(*readConfig)) (ret *DataFrame, err error)

ReadCSV reads `data` into a DataFrame (configured by `options`). Often used with (encoding/csv) csv.NewReader().ReadAll() Available options: ReadOptionHeaders, ReadOptionLabels, ReadOptionSwitchDims.

Default if no options are supplied: 1 header row, no labels, rows as major dimension

If no labels are supplied, a default label level is inserted ([]int incrementing from 0). If no headers are supplied, a default level of sequential column names (e.g., 0, 1, etc) is used. Default column names are displayed on printing. Label levels are named *i (e.g., *0, *1, etc) by default when first created. Default label names are hidden on printing.

Example
data := [][]string{
	{"foo", "bar"},
	{"baz", "qux"},
	{"corge", "fred"},
}
df, _ := ReadCSV(data)
fmt.Println(df)
Output:
+---++-------+------+
| - ||  foo  | bar  |
|---||-------|------|
| 0 ||   baz |  qux |
| 1 || corge | fred |
+---++-------+------+
Example (ColsAsMajorDimension)
data := [][]string{
	{"foo", "bar"},
	{"baz", "qux"},
	{"corge", "fred"},
}
df, _ := ReadCSV(data, ReadOptionSwitchDims())
fmt.Println(df)
Output:
+---++-----+-----+-------+
| - || foo | baz | corge |
|---||-----|-----|-------|
| 0 || bar | qux |  fred |
+---++-----+-----+-------+
Example (MultipleHeaders)
data := [][]string{
	{"foo", "bar"},
	{"baz", "qux"},
	{"corge", "fred"},
}
df, _ := ReadCSV(data, ReadOptionHeaders(2))
fmt.Println(df)
Output:
+----++-------+------+
|    ||  foo  | bar  |
| *0 ||  baz  | qux  |
|----||-------|------|
|  0 || corge | fred |
+----++-------+------+
Example (NoHeaders)
data := [][]string{
	{"foo", "bar"},
	{"baz", "qux"},
	{"corge", "fred"},
}
df, _ := ReadCSV(data, ReadOptionHeaders(0))
fmt.Println(df)
Output:
+---++-------+------+
| - ||   0   |  1   |
|---||-------|------|
| 0 ||   foo |  bar |
| 1 ||   baz |  qux |
| 2 || corge | fred |
+---++-------+------+
Example (WithLabels)
data := [][]string{
	{"foo", "bar"},
	{"baz", "qux"},
	{"corge", "fred"},
}
df, _ := ReadCSV(data, ReadOptionLabels(1))
fmt.Println(df)
Output:
+-------++------+
|  foo  || bar  |
|-------||------|
|   baz ||  qux |
| corge || fred |
+-------++------+

func ReadCSVFromString added in v0.1.0

func ReadCSVFromString(data string, options ...func(*readConfig)) (*DataFrame, error)

ReadCSVFromString reads a stringified csv table into a DataFrame (configured by `options`). This function is most commonly used in conjuction with calling WriteMockCSV(), saving the result as a string, and then reading a DataFrame from that string within a test. The major dimension of the table should be rows. For advanced cases, use the standard csv library NewReader().ReadAll() + tada.ReadCSV(). Available options: ReadOptionHeaders, ReadOptionLabels, ReadOptionDelimiter.

Default if no options are supplied: 1 header row, no labels, field delimiter is ","

If no labels are supplied, a default label level is inserted ([]int incrementing from 0). If no headers are supplied, a default level of sequential column names (e.g., 0, 1, etc) is used. Default column names are displayed on printing Label levels are named *i (e.g., *0, *1, etc) by default when first created. Default label names are hidden on printing.

Example
data := `
foo,bar
baz,qux
corge,fred`

df, _ := ReadCSVFromString(data)
fmt.Println(df)
Output:
+---++-------+------+
| - ||  foo  | bar  |
|---||-------|------|
| 0 ||   baz |  qux |
| 1 || corge | fred |
+---++-------+------+
Example (WithDelimiter)
data := `foo|bar
baz|qux
corge|fred`

df, _ := ReadCSVFromString(data, ReadOptionDelimiter('|'))
fmt.Println(df)
Output:
+---++-------+------+
| - ||  foo  | bar  |
|---||-------|------|
| 0 ||   baz |  qux |
| 1 || corge | fred |
+---++-------+------+

func ReadInterface

func ReadInterface(data [][]interface{}, options ...func(*readConfig)) (ret *DataFrame, err error)

ReadInterface converts `data` to [][]string and reads into a Dataframe (configured by `options`). Google Sheets, for example, exports data as [][]interface{} with either rows or columns as the major dimension. Available options: ReadOptionHeaders, ReadOptionLabels, ReadOptionSwitchDims.

Default if no options are supplied: 1 header row, no labels, rows as major dimension

If no labels are supplied, a default label level is inserted ([]int incrementing from 0). If no headers are supplied, a default level of sequential column names (e.g., 0, 1, etc) is used. Default column names are displayed on printing Label levels are named *i (e.g., *0, *1, etc) by default when first created. Default label names are hidden on printing.

func ReadMatrix

func ReadMatrix(mat Matrix) *DataFrame

ReadMatrix reads data satisfying the gonum Matrix interface into a DataFrame. Panics if any slices in the matrix are shorter than the first slice.

func ReadStruct

func ReadStruct(slice interface{}) (*DataFrame, error)

ReadStruct reads a `slice` of structs into a DataFrame with field names converted to column names, field values converted to column values, and default labels. The structs must all be of the same type.

A default label level named *0 is inserted ([]int incrementing from 0). Default label names are hidden on printing.

func (*DataFrame) Append

func (df *DataFrame) Append(other *DataFrame) *DataFrame

Append adds the `other` labels and values as new rows to the DataFrame. If the types of any container do not match, all the values in that container are coerced to string. Returns a new DataFrame.

func (*DataFrame) Apply

func (df *DataFrame) Apply(lambdas map[string]ApplyFn) *DataFrame

Apply applies a user-defined function to every row in a container based on `lambdas`, which is a map of container names (either column or label names) to tada.ApplyFn structs. For each container name in the map, the first field selected (i.e., not left blank) in its ApplyFn struct provides the apply logic for that container. Values are converted from their original type to the selected field type. For example, {"foo": ApplyFn{Float64: lambda}} converts the values in the foo container to float64 and applies the lambda function to each row in the container, outputting a new float64 value for each row. If a value is null either before or after the lambda function is applied, it is also null after. Returns a new DataFrame.

func (*DataFrame) ApplyFormat

func (df *DataFrame) ApplyFormat(lambdas map[string]ApplyFormatFn) *DataFrame

ApplyFormat applies a user-defined formatting function to every row in a container based on `lambdas`, which is a map of container names (either column or label names) to tada.ApplyFormatFn structs. For each container name in the map, the first field selected (i.e., not left blank) in its ApplyFormatFn struct provides the formatting logic for that container. Values are converted from their original type to the selected field type and then to string. For example, {"foo": ApplyFormatFn{Float64: lambda}} converts the values in the foo container to float64 and applies the lambda function to each row in the container, outputting a new string value for each row. If a value is null either before or after the lambda function is applied, it is also null after. Returns a new DataFrame.

func (*DataFrame) At

func (df *DataFrame) At(row, column int) Element

At returns the Element at the `row` and `column` index positions. If `row` or `column` is out of range, returns an empty Element.

func (*DataFrame) Cast

func (df *DataFrame) Cast(containerAsType map[string]DType)

Cast casts the underlying container values (column or label level) to []float64, []string, or []time.Time and caches the []byte values of the container (if inexpensive). Use cast to improve performance when calling multiple operations on values.

func (*DataFrame) Col

func (df *DataFrame) Col(name string) *Series

Col finds the first column with matching `name` and returns as a Series. Similar to SelectLabels(), but selects column values instead of label values.

func (*DataFrame) Cols

func (df *DataFrame) Cols(names ...string) *DataFrame

Cols returns all columns with matching `names`.

func (*DataFrame) Copy

func (df *DataFrame) Copy() *DataFrame

Copy returns a new DataFrame with identical values as the original but no shared objects (i.e., all internals are newly allocated).

func (*DataFrame) Count

func (df *DataFrame) Count() *Series

Count counts the number of non-null values in each column.

func (*DataFrame) DeduplicateNames

func (df *DataFrame) DeduplicateNames() *DataFrame

DeduplicateNames deduplicates the names of containers (label levels and columns) from left-to-right by appending _n to duplicate names, where n is equal to the number of times that name has already appeared. Returns a new DataFrame.

func (*DataFrame) DropCol

func (df *DataFrame) DropCol(name string) *DataFrame

DropCol drops the first column matching `name`. Returns a new DataFrame.

func (*DataFrame) DropLabels

func (df *DataFrame) DropLabels(name string) *DataFrame

DropLabels drops the first label level matching `name`. Returns a new DataFrame.

func (*DataFrame) DropNull

func (df *DataFrame) DropNull(subset ...string) *DataFrame

DropNull removes rows with a null value in any column. If `subset` is supplied, removes any rows with null values in any of the specified columns. Returns a new DataFrame.

func (*DataFrame) DropRow

func (df *DataFrame) DropRow(index int) *DataFrame

DropRow removes the row at the specified index. Returns a new DataFrame.

func (*DataFrame) EqualsCSV

func (df *DataFrame) EqualsCSV(data [][]string, includeLabels bool) (bool, *tablediff.Differences, error)

EqualsCSV converts `df` to csv, compares it to `data`, and evaluates whether the stringified values match. If `includeLabels` is true, then the DataFrame's labels are included as columns. If they do not match, returns a tablediff.Differences object that can be printed to isolate their differences.

func (*DataFrame) EqualsCSVFromString added in v0.1.0

func (df *DataFrame) EqualsCSVFromString(data string, includeLabels bool) (bool, *tablediff.Differences, error)

EqualsCSVFromString converts `df` to csv, compares it to the csv read from `data`, and evaluates whether the two match. If `includeLabels` is true, then the DataFrame's labels are included as columns. If they do not match, returns a tablediff.Differences object that can be printed to isolate their differences.

func (*DataFrame) Err

func (df *DataFrame) Err() error

Err returns the most recent error attached to the DataFrame, if any.

func (*DataFrame) ExportCSV

func (df *DataFrame) ExportCSV(file string, includeLabels bool) error

ExportCSV converts a DataFrame to a [][]string with rows as the major dimension, and writes the output to a csv file. Null values are replaced with "n/a". If `includeLabels` is true, then the DataFrame's labels are written.

func (*DataFrame) FillNull

func (df *DataFrame) FillNull(how map[string]NullFiller) *DataFrame

FillNull fills null values and makes them non-null based on `how`, a map of container names (either column or label names) and tada.NullFiller structs. For each container name in the map, the first field selected (i.e., not left blank) in its NullFiller struct is the strategy used to replace null values in that container. `FillForward` fills null values with the most recent non-null value in the container. `FillBackward` fills null values with the next non-null value in the container. `FillZero` fills null values with the zero value for that container type. `FillFloat` converts the container values to float64 and fills null values with the value supplied. If no field is selected, the container values are converted to float64 and all null values are filled with 0. Returns a new DataFrame.

func (*DataFrame) Filter

func (df *DataFrame) Filter(filters map[string]FilterFn) *DataFrame

Filter returns all rows that satisfy all of the `filters`, which is a map of container names (either column or label names) and tada.FilterFn structs. For each container name in the map, the first field selected (i.e., not left blank) in its FilterFn struct provides the filter logic for that container.

Values are coerced from their original type to the selected field type for filtering, but after filtering retains their original type. For example, {"foo": FilterFn{Float64: lambda}} converts the values in the foo container to float64, applies the true/false lambda function to each row in the container, and returns the rows that return true in their original type. Rows with null values are always excluded from the filtered data. If no filter is provided, returns a new copy of the DataFrame. For equality filtering on one or more containers, see also df.FilterByValue(). Returns a new DataFrame.

Example (DateTime)
dt1 := time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC)
dt2 := dt1.AddDate(0, 0, 1)
df := NewDataFrame([]interface{}{
	[]float64{1, 2}, []string{"corge", "fred"}, []time.Time{dt1, dt2}},
).
	SetColNames([]string{"foo", "bar", "baz"})
fmt.Println(df)

afterDate := FilterFn{DateTime: func(v time.Time) bool { return v.After(dt1) }}
ret := df.Filter(map[string]FilterFn{"baz": afterDate})
fmt.Println(ret)
Output:
+---++-----+-------+----------------------+
| - || foo |  bar  |         baz          |
|---||-----|-------|----------------------|
| 0 ||   1 | corge | 2020-01-01T00:00:00Z |
| 1 ||   2 |  fred | 2020-01-02T00:00:00Z |
+---++-----+-------+----------------------+

+---++-----+------+----------------------+
| - || foo | bar  |         baz          |
|---||-----|------|----------------------|
| 1 ||   2 | fred | 2020-01-02T00:00:00Z |
+---++-----+------+----------------------+
Example (Float64)
dt1 := time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC)
dt2 := dt1.AddDate(0, 0, 1)
df := NewDataFrame([]interface{}{
	[]float64{1, 2}, []string{"corge", "fred"}, []time.Time{dt1, dt2}},
).
	SetColNames([]string{"foo", "bar", "baz"})
fmt.Println(df)

gt1 := FilterFn{Float64: func(v float64) bool { return v > 1 }}
ret := df.Filter(map[string]FilterFn{"foo": gt1})
fmt.Println(ret)
Output:
+---++-----+-------+----------------------+
| - || foo |  bar  |         baz          |
|---||-----|-------|----------------------|
| 0 ||   1 | corge | 2020-01-01T00:00:00Z |
| 1 ||   2 |  fred | 2020-01-02T00:00:00Z |
+---++-----+-------+----------------------+

+---++-----+------+----------------------+
| - || foo | bar  |         baz          |
|---||-----|------|----------------------|
| 1 ||   2 | fred | 2020-01-02T00:00:00Z |
+---++-----+------+----------------------+
Example (Interface)
dt1 := time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC)
dt2 := dt1.AddDate(0, 0, 1)
df := NewDataFrame([]interface{}{
	[]int{1, 2}, []string{"corge", "fred"}, []time.Time{dt1, dt2}},
).
	SetColNames([]string{"foo", "bar", "baz"})
fmt.Println(df)

gt1 := FilterFn{Interface: func(v interface{}) bool {
	val, ok := v.(int)
	if !ok {
		log.Fatalf("Expecting type int, got %v", reflect.TypeOf(v))
	}
	return val > 1
}}
ret := df.Filter(map[string]FilterFn{"foo": gt1})
fmt.Println(ret)
Output:
+---++-----+-------+----------------------+
| - || foo |  bar  |         baz          |
|---||-----|-------|----------------------|
| 0 ||   1 | corge | 2020-01-01T00:00:00Z |
| 1 ||   2 |  fred | 2020-01-02T00:00:00Z |
+---++-----+-------+----------------------+

+---++-----+------+----------------------+
| - || foo | bar  |         baz          |
|---||-----|------|----------------------|
| 1 ||   2 | fred | 2020-01-02T00:00:00Z |
+---++-----+------+----------------------+
Example (String)
dt1 := time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC)
dt2 := dt1.AddDate(0, 0, 1)
df := NewDataFrame([]interface{}{
	[]float64{1, 2}, []string{"corge", "fred"}, []time.Time{dt1, dt2}},
).
	SetColNames([]string{"foo", "bar", "baz"})
fmt.Println(df)

containsD := FilterFn{String: func(v string) bool { return strings.Contains(v, "d") }}
ret := df.Filter(map[string]FilterFn{"bar": containsD})
fmt.Println(ret)
Output:
+---++-----+-------+----------------------+
| - || foo |  bar  |         baz          |
|---||-----|-------|----------------------|
| 0 ||   1 | corge | 2020-01-01T00:00:00Z |
| 1 ||   2 |  fred | 2020-01-02T00:00:00Z |
+---++-----+-------+----------------------+

+---++-----+------+----------------------+
| - || foo | bar  |         baz          |
|---||-----|------|----------------------|
| 1 ||   2 | fred | 2020-01-02T00:00:00Z |
+---++-----+------+----------------------+

func (*DataFrame) FilterByValue added in v0.3.5

func (df *DataFrame) FilterByValue(filters map[string]interface{}) *DataFrame

FilterByValue returns a cross section of the rows in the DataFrame satisfying all `filters`, which is a map of of container names (either column or label names) to interface{} values. A filter is satisfied for a given row value if the stringified value in that container matches the stringified interface{} value. Returns a new DataFrame.

func (*DataFrame) FilterCols

func (df *DataFrame) FilterCols(lambda func(string) bool, level int) *DataFrame

FilterCols returns the columns with names that satisfy `lambda` at the supplied column `level`. `level` should be 0 unless df has multiple column levels.

func (*DataFrame) GetLabels added in v0.3.5

func (df *DataFrame) GetLabels() []interface{}

GetLabels returns label levels as interface{} slices within an []interface that may be supplied as optional `labels` argument to NewSeries() or NewDataFrame(). NB: If supplying this output to either of these constructors, be sure to use the spread operator (...), or else the labels will not be read as separate levels.

func (*DataFrame) GroupBy

func (df *DataFrame) GroupBy(names ...string) *GroupedDataFrame

GroupBy groups the DataFrame rows that share the same stringified value in the container(s) (columns or labels) specified by `names`.

func (*DataFrame) HasCols

func (df *DataFrame) HasCols(colNames ...string) error

HasCols returns an error if the DataFrame does not contain all of the `colNames` supplied.

func (*DataFrame) Head

func (df *DataFrame) Head(n int) *DataFrame

Head returns the first `n` rows of the DataFrame. If `n` is greater than the length of the DataFrame, returns the entire DataFrame. In either case, returns a new DataFrame.

func (*DataFrame) InPlace

func (df *DataFrame) InPlace() *DataFrameMutator

InPlace returns a DataFrameMutator, which contains most of the same methods as DataFrame but never returns a new DataFrame. If you want to save memory and improve performance and do not need to preserve the original DataFrame, consider using InPlace().

func (*DataFrame) IndexOfContainer

func (df *DataFrame) IndexOfContainer(name string, columns bool) int

IndexOfContainer returns the index position of the first container with a name matching `name` (case-sensitive). If `name` does not match any container, -1 is returned. If `columns` is true, only column names will be searched. If `columns` is false, only label level names will be searched.

func (*DataFrame) IndexOfRows

func (df *DataFrame) IndexOfRows(name string, value interface{}) []int

IndexOfRows returns the index positions of the rows with stringified value matching `value` in the container named `name`. To search Series values, supply either the Series name or an empty string ("") as `name`.

func (*DataFrame) Iterator added in v0.2.0

func (df *DataFrame) Iterator() *DataFrameIterator

Iterator returns an iterator which may be used to access the values in each row as map[string]Element.

func (*DataFrame) Len

func (df *DataFrame) Len() int

Len returns the number of rows in each column of the DataFrame.

func (*DataFrame) ListColNames added in v0.2.0

func (df *DataFrame) ListColNames() []string

ListColNames returns the name of all the columns in the DataFrame, in order. If `df` has multiple column levels, each column name is a single string with level values separated by "|" (may be changed with SetOptionDefaultSeparator). To return the names at a specific level, use ListColNamesAtLevel().

func (*DataFrame) ListColNamesAtLevel added in v0.2.0

func (df *DataFrame) ListColNamesAtLevel(level int) []string

ListColNamesAtLevel returns the name of all the columns in the DataFrame, in order, at the supplied column `level`. If `level` is out of range, returns a nil slice.

func (*DataFrame) ListLabelNames

func (df *DataFrame) ListLabelNames() []string

ListLabelNames returns the name of all the label levels in the DataFrame, in order.

func (*DataFrame) Lookup

func (df *DataFrame) Lookup(other *DataFrame) *DataFrame

Lookup performs the lookup portion of a left join of `other` onto `df` using containers with matching names as keys. To perform a different type of lookup or specify the matching keys, use df.LookupAdvanced().

Lookup identifies the row alignment between `df` and `other` and returns the aligned values. Rows are aligned when: 1) one or more containers (either column or label level) in `other` share the same name as one or more containers in `df`, and 2) the stringified values in the `other` containers match the values in the `df` containers. For the following dataframes:

`df` `other` FOO BAR FOO QUX bar 0 baz corge baz 1 qux waldo

Row 1 in `df` is "aligned" with row 0 in `other`, because those are the rows in which both share the same value ("baz") in a container with the same name ("foo"). The result of a lookup will be:

FOO BAR bar n/a baz corge

Returns a new DataFrame.

func (*DataFrame) LookupAdvanced

func (df *DataFrame) LookupAdvanced(other *DataFrame, how string, leftOn []string, rightOn []string) *DataFrame

LookupAdvanced performs the lookup portion of a join of `other` onto `df` matching on the container keys specified. Supported `how` options: left, right, inner.

LookupAdvanced identifies the row alignment between `df` and `other` and returns the aligned values. Rows are aligned when: 1) one or more containers (either column or label level) in `other` share the same name as one or more containers in `df`, and 2) the stringified values in the `other` containers match the values in the `df` containers. For the following dataframes:

`df` `other` FOO BAR FRED QUX bar 0 baz corge baz 1 qux waldo

In LookupAdvanced(other, "left", ["foo"], ["fred"]), row 1 in `df` is "aligned" with row 0 in `other`, because those are the rows in which both share the same value ("baz") in the keyed containers. The result of this lookup will be:

FOO BAR bar n/a baz corge

Returns a new DataFrame.

func (*DataFrame) Max

func (df *DataFrame) Max() *Series

Max coerces the values in each column to float64 and returns the maximum non-null value in each column.

func (*DataFrame) Mean

func (df *DataFrame) Mean() *Series

Mean coerces the values in each column to float64 and calculates the mean of each column.

func (*DataFrame) Median

func (df *DataFrame) Median() *Series

Median coerces the values in each column to float64 and calculates the median of each column.

func (*DataFrame) Merge

func (df *DataFrame) Merge(other *DataFrame) *DataFrame

Merge performs a left join of `other` onto `df` using containers with matching names as keys. To perform a different type of join or specify the matching keys, use df.LookupAdvanced() to isolate values in `other`, and append them with df.WithCol().

Merge identifies the row alignment between `df` and `other` and appends aligned values as new columns on `df`. Rows are aligned when 1) one or more containers (either column or label level) in `other` share the same name as one or more containers in `df`, and 2) the stringified values in the `other` containers match the values in the `df` containers. For the following dataframes:

`df` `other` FOO BAR FOO QUX bar 0 baz corge baz 1 qux waldo

Row 1 in `df` is "aligned" with row 0 in `other`, because those are the rows in which both share the same value ("baz") in a container with the same name ("foo"). After merging, the result will be:

`df` FOO BAR QUX bar 0 n/a baz 1 corge

Finally, all container names (columns and label names) are deduplicated after the merge so that they are unique. Returns a new DataFrame.

func (*DataFrame) Min

func (df *DataFrame) Min() *Series

Min coerces the values in each column to float64 and returns the minimum non-null value in each column.

func (*DataFrame) NUnique

func (df *DataFrame) NUnique() *Series

NUnique counts the number of unique non-null values in each column.

func (*DataFrame) Name

func (df *DataFrame) Name() string

Name returns the name of the DataFrame.

func (*DataFrame) NameOfCol added in v0.2.0

func (df *DataFrame) NameOfCol(n int) string

NameOfCol returns the name of the column at index position `n`. If n is out of range, returns "-out of range-"

func (*DataFrame) NameOfLabel

func (df *DataFrame) NameOfLabel(n int) string

NameOfLabel returns the name of the label level at index position `n`. If n is out of range, returns "-out of range-"

func (*DataFrame) Null

func (df *DataFrame) Null(subset ...string) *DataFrame

Null returns all the rows with any null values. If `subset` is supplied, returns all the rows with all non-null values in the specified columns. Returns a new DataFrame.

func (*DataFrame) PivotTable

func (df *DataFrame) PivotTable(labels, columns, values, aggFunc string) *DataFrame

PivotTable creates a spreadsheet-style pivot table as a DataFrame by grouping rows using the unique values in `labels`, reducing the values in `values` using an `aggFunc` aggregation function, then promoting the unique values in `columns` to be new columns. `labels`, `columns`, and `values` should all refer to existing container names (either columns or labels). Supported `aggFunc`s: sum, mean, median, std, count, min, max.

func (*DataFrame) PromoteToColLevel

func (df *DataFrame) PromoteToColLevel(name string) *DataFrame

PromoteToColLevel pivots an existing container (either column or label names) into a new column level. If promoting would use either the last column or index level, it returns an error. Each unique value in the stacked column is stacked above each existing column. Promotion can add new columns and remove label rows with duplicate values.

func (*DataFrame) Range

func (df *DataFrame) Range(first, last int) *DataFrame

Range returns the rows of the DataFrame starting at `first` and `ending` immediately prior to last (left-inclusive, right-exclusive). If either `first` or `last` is greater than the length of the DataFrame, a DataFrame error is returned. In all cases, returns a new DataFrame.

func (*DataFrame) Relabel

func (df *DataFrame) Relabel() *DataFrame

Relabel resets the DataFrame labels to default labels (e.g., []int from 0 to df.Len()-1, with *0 as name). Returns a new Series.

func (*DataFrame) Resample added in v0.2.6

func (df *DataFrame) Resample(how map[string]Resampler) *DataFrame

Resample coerces values to time.Time and truncates them by the logic supplied in `how`, which is a map of of container names (either column or label names) to tada.Resampler structs. For each container name in the map, the first field selected (i.e., not left blank) in its Resampler struct provides the resampling logic for that container. Returns a new DataFrame.

func (*DataFrame) ResetLabels

func (df *DataFrame) ResetLabels(index ...int) *DataFrame

ResetLabels appends the label level(s) at the supplied index levels as columns and drops the level. If no index levels are supplied, all label levels are appended as columns and dropped as levels, and replaced by a default label column. Returns a new DataFrame.

func (*DataFrame) SelectLabels

func (df *DataFrame) SelectLabels(name string) *Series

SelectLabels finds the first label level with matching `name` and returns the values as a Series. The labels in the Series are shared with the labels in the DataFrame. If label level name is default (prefixed with *), the prefix is removed.

func (*DataFrame) SetColNames

func (df *DataFrame) SetColNames(colNames []string) *DataFrame

SetColNames sets the names of all the columns in the DataFrame and returns the entire DataFrame.

Example
df := NewDataFrame([]interface{}{
	[]float64{1, 2}, []string{"baz", "qux"}},
).
	SetColNames([]string{"foo", "bar"})
fmt.Println(df)
Output:
+---++-----+-----+
| - || foo | bar |
|---||-----|-----|
| 0 ||   1 | baz |
| 1 ||   2 | qux |
+---++-----+-----+

func (*DataFrame) SetLabelNames

func (df *DataFrame) SetLabelNames(levelNames []string) *DataFrame

SetLabelNames sets the names of all the label levels in the DataFrame and returns the entire DataFrame.

Example
df := NewDataFrame([]interface{}{[]float64{1, 2}}).
	SetLabelNames([]string{"baz"})
fmt.Println(df)
Output:
+-----++---+
| baz || 0 |
|-----||---|
|   0 || 1 |
|   1 || 2 |
+-----++---+
Example (Multiple)
df := NewDataFrame(
	[]interface{}{[]float64{1, 2}},
	[]int{0, 1}, []string{"foo", "bar"},
).
	SetColNames([]string{"A"}).
	SetLabelNames([]string{"baz", "qux"})
fmt.Println(df)
Output:
+-----+-----++---+
| baz | qux || A |
|-----|-----||---|
|   0 | foo || 1 |
|   1 | bar || 2 |
+-----+-----++---+

func (*DataFrame) SetLabels

func (df *DataFrame) SetLabels(colNames ...string) *DataFrame

SetLabels appends the column(s) supplied as `colNames` as label levels and drops the column(s). The number of `colNames` supplied must be less than the number of columns in the Series. Returns a new DataFrame.

func (*DataFrame) SetName

func (df *DataFrame) SetName(name string) *DataFrame

SetName sets the name of a DataFrame and returns the entire DataFrame.

func (*DataFrame) Sort

func (df *DataFrame) Sort(by ...Sorter) *DataFrame

Sort sorts the values `by` zero or more Sorter specifications. If no Sorter is supplied, does not sort. If no DType is supplied for a Sorter, sorts as float64. DType is only used for the process of sorting. Once it has been sorted, data retains its original type. Returns a new DataFrame.

func (*DataFrame) Std

func (df *DataFrame) Std() *Series

Std coerces the values in each column to float64 and calculates the standard deviation of each column.

func (*DataFrame) String

func (df *DataFrame) String() string

String prints the DataFrame in table form, with the number of rows constrained by optionMaxRows, and the number of columns constrained by optionMaxColumns, which may be configured with PrintOptionMaxRows(n) and PrintOptionMaxColumns(n), respectively. By default, repeated values are merged together, but this behavior may be disabled with PrintOptionAutoMerge(false). By default, overly-wide non-header cells are truncated, but this behavior may be changed to wrapping with PrintOptionWrapLines(true).

func (*DataFrame) Subset

func (df *DataFrame) Subset(index []int) *DataFrame

Subset returns only the rows specified at the index positions, in the order specified. Returns a new DataFrame.

func (*DataFrame) SubsetCols

func (df *DataFrame) SubsetCols(index []int) *DataFrame

SubsetCols returns only the labels specified at the index positions, in the order specified. Returns a new DataFrame.

func (*DataFrame) SubsetLabels

func (df *DataFrame) SubsetLabels(index []int) *DataFrame

SubsetLabels returns only the labels specified at the index positions, in the order specified. Returns a new DataFrame.

func (*DataFrame) Sum

func (df *DataFrame) Sum() *Series

Sum coerces the values in each column to float64 and sums each column.

func (*DataFrame) SumColumns added in v0.1.4

func (df *DataFrame) SumColumns(name string, colNames ...string) *Series

SumColumns finds each column matching a supplied `colName`, coerces its values to float64, and adds them row-wise. The resulting Series is named `name`. If any column has a null value for a given row, that row is considered null.

func (*DataFrame) SwapLabels

func (df *DataFrame) SwapLabels(i, j string) *DataFrame

SwapLabels swaps the label levels with names `i` and `j`. Returns a new DataFrame.

func (*DataFrame) Tail

func (df *DataFrame) Tail(n int) *DataFrame

Tail returns the last `n` rows of the DataFrame. If `n` is greater than the length of the DataFrame, returns the entire DataFrame. In either case, returns a new DataFrame.

func (*DataFrame) ToCSV

func (df *DataFrame) ToCSV(includeLabels bool) [][]string

ToCSV writes a DataFrame to a [][]string with rows as the major dimension. Null values are replaced with "n/a". If `includeLabels` is true, then the DataFrame's labels are written.

func (*DataFrame) ToInterface

func (df *DataFrame) ToInterface(includeLabels bool) [][]interface{}

ToInterface exports a DataFrame to a [][]interface with rows as the major dimension. Null values are not changed, and should be handled explicitly with DropNull() or FillNull(). If `includeLabels` is true, then the DataFrame's labels are written.

func (*DataFrame) ToSeries

func (df *DataFrame) ToSeries() *Series

ToSeries converts a single-columned DataFrame to a Series that shares the same underlying values and labels.

func (*DataFrame) Transpose

func (df *DataFrame) Transpose() *DataFrame

Transpose switches all row values to column values and label names to column names. For example a DataFrame with 2 rows and 1 column has 2 columns and 1 row after transposition.

func (*DataFrame) Where added in v0.3.0

func (df *DataFrame) Where(filters map[string]FilterFn, ifTrue, ifFalse interface{}) (*Series, error)

Where iterates over the rows in `df` and evaluates whether each one satisifes `filters`, which is a map of container names (either column or label names) and tada.FilterFn structs. If yes, returns `ifTrue` at that row position. If not, returns `ifFalse` at that row position. Values are coerced from their original type to the selected field type for filtering, but after filtering retains their original type.

Returns an unnamed Series with a copy of the labels from the original Series and null status based on the supplied values. If an unsupported value type is supplied as either ifTrue or ifFalse, returns an error.

Example
df := NewDataFrame([]interface{}{
	[]int{1, 2}},
).
	SetColNames([]string{"foo"})
fmt.Println(df)

gt1 := FilterFn{Float64: func(v float64) bool { return v > 1 }}
ret, _ := df.Where(map[string]FilterFn{"foo": gt1}, true, false)
fmt.Println(ret)
Output:
+---++-----+
| - || foo |
|---||-----|
| 0 ||   1 |
| 1 ||   2 |
+---++-----+

+---++-------+
| - ||       |
|---||-------|
| 0 || false |
| 1 ||  true |
+---++-------+

func (*DataFrame) WithCol

func (df *DataFrame) WithCol(name string, input interface{}) *DataFrame

WithCol resolves as follows:

If a scalar string is supplied as `input` and a column exists that matches `name`: rename the column to match `input`. In this case, `name` must already exist.

If a slice is supplied as `input` and a column exists that matches `name`: replace the values at this column to match `input`. If a slice is supplied as `input` and a column does not exist that matches `name`: append a new column named `name` and values matching `input`. If `input` is a slice, it must be the same length as the underlying DataFrame.

In all cases, returns a new DataFrame.

Example (Append)
df := NewDataFrame([]interface{}{
	[]float64{1, 2}},
).
	SetColNames([]string{"foo"})
fmt.Println(df)

ret := df.WithCol("bar", []bool{false, true})
fmt.Println(ret)
Output:
+---++-----+
| - || foo |
|---||-----|
| 0 ||   1 |
| 1 ||   2 |
+---++-----+

+---++-----+-------+
| - || foo |  bar  |
|---||-----|-------|
| 0 ||   1 | false |
| 1 ||   2 |  true |
+---++-----+-------+
Example (Overwrite)
df := NewDataFrame([]interface{}{
	[]float64{1, 2}},
).
	SetColNames([]string{"foo"})
fmt.Println(df)

ret := df.WithCol("foo", []string{"baz", "qux"})
fmt.Println(ret)
Output:
+---++-----+
| - || foo |
|---||-----|
| 0 ||   1 |
| 1 ||   2 |
+---++-----+

+---++-----+
| - || foo |
|---||-----|
| 0 || baz |
| 1 || qux |
+---++-----+
Example (Rename)
df := NewDataFrame([]interface{}{
	[]float64{1, 2}},
).
	SetColNames([]string{"foo"})
fmt.Println(df)

ret := df.WithCol("foo", "qux")
fmt.Println(ret)
Output:
+---++-----+
| - || foo |
|---||-----|
| 0 ||   1 |
| 1 ||   2 |
+---++-----+

+---++-----+
| - || qux |
|---||-----|
| 0 ||   1 |
| 1 ||   2 |
+---++-----+

func (*DataFrame) WithLabels

func (df *DataFrame) WithLabels(name string, input interface{}) *DataFrame

WithLabels resolves as follows:

If a scalar string is supplied as `input` and a label level exists that matches `name`: rename the level to match `input`. In this case, `name` must already exist.

If a slice is supplied as `input` and a label level exists that matches `name`: replace the values at this level to match `input`. If a slice is supplied as `input` and a label level does not exist that matches `name`: append a new level named `name` and values matching `input`. If `input` is a slice, it must be the same length as the underlying DataFrame.

In all cases, returns a new DataFrame.

type DataFrameIterator added in v0.2.0

type DataFrameIterator struct {
	// contains filtered or unexported fields
}

A DataFrameIterator iterates over the rows in a DataFrame.

func (*DataFrameIterator) Next added in v0.2.0

func (iter *DataFrameIterator) Next() bool

Next advances to next row. Returns false at end of iteration.

func (*DataFrameIterator) Row added in v0.2.0

func (iter *DataFrameIterator) Row() map[string]Element

Row returns the current row in the DataFrame as map[string]Element. The map keys are the names of containers (including label levels). The value in each map is an Element containing an interface value and a boolean denoting if the value is null. If multiple columns have the same header, only the Elements of the left-most column are returned.

type DataFrameMutator

type DataFrameMutator struct {
	// contains filtered or unexported fields
}

A DataFrameMutator is used to change DataFrame values in place.

func (*DataFrameMutator) Append

func (df *DataFrameMutator) Append(other *DataFrame)

Append adds the `other` labels and values as new rows to the DataFrame. If the types of any container do not match, all the values in that container are coerced to string. Modifies the underlying DataFrame in place.

func (*DataFrameMutator) Apply

func (df *DataFrameMutator) Apply(lambdas map[string]ApplyFn)

Apply applies a user-defined function to every row in a container based on `lambdas`, which is a map of container names (either column or label names) to tada.ApplyFn structs. For each container name in the map, the first field selected (i.e., not left blank) in its ApplyFn struct provides the apply logic for that container. Values are converted from their original type to the selected field type. For example, {"foo": ApplyFn{Float64: lambda}} converts the values in the foo container to float64 and applies the lambda function to each row in the container, outputting a new float64 value for each row. If a value is null either before or after the lambda function is applied, it is also null after. Modifies the underlying DataFrame in place.

func (*DataFrameMutator) ApplyFormat

func (df *DataFrameMutator) ApplyFormat(lambdas map[string]ApplyFormatFn)

ApplyFormat applies a user-defined formatting function to every row in a container based on `lambdas`, which is a map of container names (either column or label names) to tada.ApplyFormatFn structs. For each container name in the map, the first field selected (i.e., not left blank) in its ApplyFormatFn struct provides the formatting logic for that container. Values are converted from their original type to the selected field type and then to string. For example, {"foo": ApplyFormatFn{Float64: lambda}} converts the values in the foo container to float64 and applies the lambda function to each row in the container, outputting a new string value for each row. If a value is null either before or after the lambda function is applied, it is also null after. Modifies the underlying DataFrame in place.

func (*DataFrameMutator) DeduplicateNames

func (df *DataFrameMutator) DeduplicateNames()

DeduplicateNames deduplicates the names of containers (label levels and columns) from left-to-right by appending _n to duplicate names, where n is equal to the number of times that name has already appeared. Modifies the underlying DataFrame in place.

func (*DataFrameMutator) DropCol

func (df *DataFrameMutator) DropCol(name string)

DropCol drops the first column matching `name`. Modifies the underlying DataFrame in place.

func (*DataFrameMutator) DropLabels

func (df *DataFrameMutator) DropLabels(name string)

DropLabels drops the first label level matching `name`. Modifies the underlying DataFrame in place.

func (*DataFrameMutator) DropNull

func (df *DataFrameMutator) DropNull(subset ...string)

DropNull removes rows with a null value in any column. If `subset` is supplied, removes any rows with null values in any of the specified columns. Modifies the underlying DataFrame.

func (*DataFrameMutator) DropRow

func (df *DataFrameMutator) DropRow(index int)

DropRow removes the row at the specified index. Modifies the underlying DataFrame in place.

func (*DataFrameMutator) FillNull

func (df *DataFrameMutator) FillNull(how map[string]NullFiller)

FillNull fills null values and makes them non-null based on `how`. How is a map of container names (either column or label names) and `NullFillers`. For each container name supplied, the first field selected (i.e., not left blank) in the `NullFiller` is the strategy used to replace null values. `FillForward` fills null values with the most recent non-null value in the container. `FillBackward` fills null values with the next non-null value in the container. `FillZero` fills null values with the zero value for that container type. `FillFloat` converts the container values to float64 and fills null values with the value supplied. If no field is selected, the container values are converted to float64 and all null values are filled with 0. Modifies the underlying DataFrame.

func (*DataFrameMutator) Filter

func (df *DataFrameMutator) Filter(filters map[string]FilterFn)

Filter returns all rows that satisfy all of the `filters`, which is a map of container names (either column or label names) and tada.FilterFn structs. For each container name in the map, the first field selected (i.e., not left blank) in its FilterFn struct provides the filter logic for that container.

Values are coerced from their original type to the selected field type for filtering, but after filtering retains their original type. For example, {"foo": FilterFn{Float64: lambda}} converts the values in the foo container to float64, applies the true/false lambda function to each row in the container, and returns the rows that return true in their original type. Rows with null values are always excluded from the filtered data. If no filter is provided, does nothing. For equality filtering on one or more containers, see also df.FilterByValue(). Modifies the underlying DataFrame in place.

func (*DataFrameMutator) FilterByValue added in v0.3.5

func (df *DataFrameMutator) FilterByValue(filters map[string]interface{})

FilterByValue returns the rows in the DataFrame satisfying all `filters`, which is a map of of container names (either column or label names) to interface{} values. A filter is satisfied for a given row value if the stringified value in that container at that row matches the stringified interface{} value. Modifies the underlying DataFrame in place.

func (*DataFrameMutator) FilterCols added in v0.2.0

func (df *DataFrameMutator) FilterCols(lambda func(string) bool, level int)

FilterCols returns the columns with names that satisfy `lambda` at the supplied column `level`. `level` should be 0 unless df has multiple column levels.

func (*DataFrameMutator) Merge

func (df *DataFrameMutator) Merge(other *DataFrame)

Merge performs a left join of `other` onto `df` using containers with matching names as keys. To perform a different type of join or specify the matching keys, use df.LookupAdvanced() to isolate values in `other`, and append them with df.WithCol().

Merge identifies the row alignment between `df` and `other` and appends aligned values as new columns on `df`. Rows are aligned when: 1) one or more containers (either column or label level) in `other` share the same name as one or more containers in `df`, and 2) the stringified values in the `other` containers match the values in the `df` containers. For the following dataframes:

`df` `other` FOO BAR FOO QUX bar 0 baz corge baz 1 qux waldo

Row 1 in `df` is "aligned" with row 0 in `other`, because those are the rows in which both share the same value ("baz") in a container with the same name ("foo"). After merging, the result will be:

`df` FOO BAR QUX bar 0 n/a baz 1 corge

Finally, all container names (columns and label names) are deduplicated after the merge so that they are unique. Modifies the underlying DataFrame in place.

func (*DataFrameMutator) Relabel

func (df *DataFrameMutator) Relabel()

Relabel resets the DataFrame labels to default labels (e.g., []int from 0 to df.Len()-1, with *0 as name). Modifies the underlying DataFrame in place.

func (*DataFrameMutator) Resample added in v0.2.6

func (df *DataFrameMutator) Resample(how map[string]Resampler)

Resample coerces values to time.Time and truncates them by the logic supplied in `how`, which is a map of of container names (either column or label names) to tada.Resampler structs. For each container name in the map, the first field selected (i.e., not left blank) in its Resampler struct provides the resampling logic for that container. Modifies the underlying DataFrame in place.

func (*DataFrameMutator) ResetLabels

func (df *DataFrameMutator) ResetLabels(labelLevels ...int)

ResetLabels appends the label level(s) at the supplied index levels as columns and drops the level. If no index levels are supplied, all label levels are appended as columns and dropped as levels, and replaced by a default label column. Modifies the underlying DataFrame in place.

func (*DataFrameMutator) SetLabels

func (df *DataFrameMutator) SetLabels(colNames ...string)

SetLabels appends the column(s) supplied as `colNames` as label levels and drops the column(s). The number of `colNames` supplied must be less than the number of columns in the Series. Modifies the underlying DataFrame in place.

func (*DataFrameMutator) Sort

func (df *DataFrameMutator) Sort(by ...Sorter)

Sort sorts the values `by` zero or more Sorter specifications. If no Sorter is supplied, does not sort. If no DType is supplied for a Sorter, sorts as float64. Modifies the underlying DataFrame in place.

func (*DataFrameMutator) Subset

func (df *DataFrameMutator) Subset(index []int)

Subset returns only the rows specified at the index positions, in the order specified. Modifies the underlying DataFrame in place.

func (*DataFrameMutator) SubsetCols

func (df *DataFrameMutator) SubsetCols(index []int)

SubsetCols returns only the labels specified at the index positions, in the order specified. Modifies the underlying DataFrame in place.

func (*DataFrameMutator) SubsetLabels

func (df *DataFrameMutator) SubsetLabels(index []int)

SubsetLabels returns only the labels specified at the index positions, in the order specified. Modifies the underlying DataFrame in place.

func (*DataFrameMutator) SwapLabels

func (df *DataFrameMutator) SwapLabels(i, j string)

SwapLabels swaps the label levels with names `i` and `j`. Modifies the underlying DataFrame in place.

func (*DataFrameMutator) WithCol

func (df *DataFrameMutator) WithCol(name string, input interface{})

WithCol resolves as follows:

If a scalar string is supplied as `input` and a column exists that matches `name`: rename the column to match `input`. In this case, `name` must already exist.

If a slice is supplied as `input` and a column exists that matches `name`: replace the values at this column to match `input`. If a slice is supplied as `input` and a column does not exist that matches `name`: append a new column named `name` and values matching `input`. If `input` is a slice, it must be the same length as the underlying DataFrame.

In all cases, modifies the underlying DataFrame in place.

Example (Rename)
df := NewDataFrame([]interface{}{
	[]float64{1, 2}},
).
	SetColNames([]string{"foo"})
fmt.Println(df)

df.InPlace().WithCol("foo", "qux")
fmt.Println(df)
Output:
+---++-----+
| - || foo |
|---||-----|
| 0 ||   1 |
| 1 ||   2 |
+---++-----+

+---++-----+
| - || qux |
|---||-----|
| 0 ||   1 |
| 1 ||   2 |
+---++-----+

func (*DataFrameMutator) WithLabels

func (df *DataFrameMutator) WithLabels(name string, input interface{})

WithLabels resolves as follows:

If a scalar string is supplied as `input` and a label level exists that matches `name`: rename the level to match `input`. In this case, `name` must already exist.

If a slice is supplied as `input` and a label level exists that matches `name`: replace the values at this level to match `input`. If a slice is supplied as `input` and a label level does not exist that matches `name`: append a new level named `name` and values matching `input`. If `input` is a slice, it must be the same length as the underlying DataFrame.

In all cases, modifies the underlying DataFrame in place.

type Element

type Element struct {
	Val    interface{}
	IsNull bool
}

An Element is one value in either a Series or DataFrame.

type FilterFn

type FilterFn struct {
	Float64   func(val float64) bool
	String    func(val string) bool
	DateTime  func(val time.Time) bool
	Interface func(val interface{}) bool
}

A FilterFn supplies logic to the Filter() function. Only the first field selected (i.e., not left nil) is used - any others are ignored. Values are coerced to the type specified in the field (e.g., DateTime -> time.Time) before the filter function is evaluated. Once it has been filtered, data retains its original type.

type GroupReduceFn

type GroupReduceFn struct {
	Float64   func(slice []float64) float64
	String    func(slice []string) string
	DateTime  func(slice []time.Time) time.Time
	Interface func(slice interface{}) interface{}
}

A GroupReduceFn supplies logic to the Reduce() function. Only the first field selected (i.e., not left nil) is used - any others are ignored. If Interface is selected, the slice of values retains its original type (as interface{}, so must be type-asserted), and all output values must have the same type (though this may be different than the original type). Otherwise, values are coerced to the type specified in the field (e.g., DateTime -> time.Time) before the reduce function is evaluated.

type GroupedDataFrame

type GroupedDataFrame struct {
	// contains filtered or unexported fields
}

A GroupedDataFrame is a collection of row positions sharing the same group key. A GroupedDataFrame has a reference to an underlying DataFrame, which is used for reduce operations.

func (*GroupedDataFrame) Col

func (g *GroupedDataFrame) Col(colName string) *GroupedSeries

Col isolates the Series at `containerName`, which may be either a label level or column in the underlying DataFrame. Returns a GroupedSeries with the same groups and labels as in the GroupedDataFrame.

func (*GroupedDataFrame) Count

func (g *GroupedDataFrame) Count(colNames ...string) *DataFrame

Count returns the number of non-null values in each group for the columns in `colNames`.

func (*GroupedDataFrame) Earliest

func (g *GroupedDataFrame) Earliest(colNames ...string) *DataFrame

Earliest coerces the column values in `colNames` to time.Time and calculates the earliest timestamp of each group.

func (*GroupedDataFrame) Err

func (g *GroupedDataFrame) Err() error

Err returns the underlying error, if any

func (*GroupedDataFrame) First

func (g *GroupedDataFrame) First(colNames ...string) *DataFrame

First returns the first row within each group for the columns in `colNames`.

func (*GroupedDataFrame) GetGroup

func (g *GroupedDataFrame) GetGroup(group string) *DataFrame

GetGroup returns the grouped rows sharing the same `group` key as a new DataFrame.

func (*GroupedDataFrame) HavingCount

func (g *GroupedDataFrame) HavingCount(lambda func(int) bool) *GroupedDataFrame

HavingCount removes any groups from `g` that do not satisfy the boolean function supplied in `lambda`. For each group, the input into `lambda` is the total number of values in the group (null or not-null).

func (*GroupedDataFrame) Iterator added in v0.2.0

Iterator returns an iterator which may be used to access each group of rows as a new DataFrame, in the order in which the groups originally appeared.

func (*GroupedDataFrame) Last

func (g *GroupedDataFrame) Last(colNames ...string) *DataFrame

Last returns the last row within each group for the columns in `colNames`.

func (*GroupedDataFrame) Latest

func (g *GroupedDataFrame) Latest(colNames ...string) *DataFrame

Latest coerces the column values in `colNames` to time.Time and calculates the latest timestamp of each group.

func (*GroupedDataFrame) Len

func (g *GroupedDataFrame) Len() int

Len returns the number of group labels.

func (*GroupedDataFrame) ListGroups

func (g *GroupedDataFrame) ListGroups() []string

ListGroups returns a list of group keys in the order in which they originally appeared.

func (*GroupedDataFrame) Max

func (g *GroupedDataFrame) Max(colNames ...string) *DataFrame

Max coerces the column values in `colNames` to float64 and calculates the maximum of each group.

func (*GroupedDataFrame) Mean

func (g *GroupedDataFrame) Mean(colNames ...string) *DataFrame

Mean coerces the column values in `colNames` to float64 and calculates the mean of each group.

func (*GroupedDataFrame) Median

func (g *GroupedDataFrame) Median(colNames ...string) *DataFrame

Median coerces the column values in `colNames` to float64 and calculates the median of each group.

func (*GroupedDataFrame) Min

func (g *GroupedDataFrame) Min(colNames ...string) *DataFrame

Min coerces the column values in `colNames` to float64 and calculates the minimum of each group.

func (*GroupedDataFrame) NUnique

func (g *GroupedDataFrame) NUnique(colNames ...string) *DataFrame

NUnique returns the number of unique, non-null values in each group for the columns in `colNames`.

func (*GroupedDataFrame) Nth

func (g *GroupedDataFrame) Nth(index int, colNames ...string) *DataFrame

Nth returns the row at position `n` (if it exists) within each group for the columns in `colNames`.

func (*GroupedDataFrame) Reduce

func (g *GroupedDataFrame) Reduce(name string, cols []string, lambda GroupReduceFn) *DataFrame

Reduce iterates over the groups in `g` and reduces each group of values into a single value applying the function supplied in `lambda` to the column values in `cols`. Reduce returns a new DataFrame named `name` where each reduced group is represented by a single row. The reduction `lambda` function is the first field selected (i.e., not left blank) in the GroupReduceFn.

func (*GroupedDataFrame) SliceLabels

func (g *GroupedDataFrame) SliceLabels() []interface{}

SliceLabels returns the grouped label levels as interface{} slices within an []interface that may be supplied as optional `labels` argument to NewSeries() or NewDataFrame().

func (*GroupedDataFrame) Std

func (g *GroupedDataFrame) Std(colNames ...string) *DataFrame

Std coerces the column values in `colNames` to float64 and calculates the standard deviation of each group.

func (*GroupedDataFrame) Sum

func (g *GroupedDataFrame) Sum(colNames ...string) *DataFrame

Sum coerces the column values in `colNames` to float64 and calculates the sum of each group.

type GroupedDataFrameIterator added in v0.2.0

type GroupedDataFrameIterator struct {
	// contains filtered or unexported fields
}

GroupedDataFrameIterator iterates over all DataFrames in the group.

func (*GroupedDataFrameIterator) DataFrame added in v0.2.0

func (g *GroupedDataFrameIterator) DataFrame() *DataFrame

DataFrame returns the current grouped DataFrame.

func (*GroupedDataFrameIterator) Next added in v0.2.0

func (g *GroupedDataFrameIterator) Next() bool

Next advances to next grouped DataFrame. Returns false at end of iteration.

type GroupedSeries

type GroupedSeries struct {
	// contains filtered or unexported fields
}

A GroupedSeries is a collection of row positions sharing the same group key. A GroupedSeries has a reference to an underlying Series, which is used for reduce operations.

func (*GroupedSeries) Align

func (g *GroupedSeries) Align() *GroupedSeries

Align changes subsequent reduce operations for this group to return a Series aligned with the original Series labels (the default behavior is to return a Series with one label per group). If the original Series is:

FOO baz 0 baz 1 bar 2 bar 4

and it is grouped by the "foo" label, then the default g.Sum() reducer would return:

FOO baz 1 bar 6

After g.Align(), the g.Sum() reducer would return:

FOO baz 1 baz 1 bar 6 bar 6

Example (Mean)
s := NewSeries([]float64{1, 2, 3, 4}, []int{0, 1, 0, 1}).
	SetName("foo").
	SetLabelNames([]string{"baz"})
fmt.Println(s)

// here, s.GroupBy("baz") is equivalent to s.GroupBy()
g := s.GroupBy("baz")
fmt.Println(g.Align().Mean())
Output:
+-----++-----+
| baz || foo |
|-----||-----|
|   0 ||   1 |
|   1 ||   2 |
|   0 ||   3 |
|   1 ||   4 |
+-----++-----+

+-----++----------+
| baz || mean_foo |
|-----||----------|
|   0 ||        2 |
|   1 ||        3 |
|   0 ||        2 |
|   1 ||        3 |
+-----++----------+

func (*GroupedSeries) Count

func (g *GroupedSeries) Count() *Series

Count returns the number of non-null values in each group.

func (*GroupedSeries) Earliest

func (g *GroupedSeries) Earliest() *Series

Earliest coerces the Series values to time.Time and calculates the earliest timestamp in each group.

func (*GroupedSeries) Err

func (g *GroupedSeries) Err() error

Err returns the underlying error, if any.

func (*GroupedSeries) First

func (g *GroupedSeries) First() *Series

First returns the first row in each group.

func (*GroupedSeries) GetGroup

func (g *GroupedSeries) GetGroup(group string) *Series

GetGroup returns the grouped rows sharing the same `group` key as a new Series.

func (*GroupedSeries) HavingCount

func (g *GroupedSeries) HavingCount(lambda func(int) bool) *GroupedSeries

HavingCount removes any groups from `g` that do not satisfy the boolean function supplied in `lambda`. For each group, the input into `lambda` is the total number of values in the group (null or not-null).

Example (Sum)
s := NewSeries([]float64{1, 2, 3, 4}, []int{0, 1, 1, 1}).
	SetName("foo").
	SetLabelNames([]string{"baz"})
fmt.Println(s)

countOf3 := func(n int) bool { return n == 3 }
g := s.GroupBy("baz")
fmt.Println(g.HavingCount(countOf3).Sum())
Output:
+-----++-----+
| baz || foo |
|-----||-----|
|   0 ||   1 |
|   1 ||   2 |
|     ||   3 |
|     ||   4 |
+-----++-----+

+-----++---------+
| baz || sum_foo |
|-----||---------|
|   1 ||       9 |
+-----++---------+

func (*GroupedSeries) Iterator added in v0.2.0

func (g *GroupedSeries) Iterator() *GroupedSeriesIterator

Iterator returns an iterator which may be used to access each group of rows as a new Series, in the order in which the groups originally appeared.

func (*GroupedSeries) Last

func (g *GroupedSeries) Last() *Series

Last returns the last row in each group.

func (*GroupedSeries) Latest

func (g *GroupedSeries) Latest() *Series

Latest coerces the Series values to time.Time and calculates the latest timestamp in each group.

func (*GroupedSeries) Len

func (g *GroupedSeries) Len() int

Len returns the number of group labels.

func (*GroupedSeries) ListGroups

func (g *GroupedSeries) ListGroups() []string

ListGroups returns a list of group keys in the order in which they originally appeared.

func (*GroupedSeries) Max

func (g *GroupedSeries) Max() *Series

Max coerces values to float64 and calculates the maximum of each group.

func (*GroupedSeries) Mean

func (g *GroupedSeries) Mean() *Series

Mean coerces values to float64 and calculates the mean of each group.

Example
s := NewSeries([]float64{1, 2, 3, 4}, []int{0, 1, 0, 1}).
	SetName("foo").
	SetLabelNames([]string{"baz"})
fmt.Println(s)

// here, s.GroupBy("baz") is equivalent to s.GroupBy()
g := s.GroupBy("baz")
fmt.Println(g.Mean())
Output:
+-----++-----+
| baz || foo |
|-----||-----|
|   0 ||   1 |
|   1 ||   2 |
|   0 ||   3 |
|   1 ||   4 |
+-----++-----+

+-----++----------+
| baz || mean_foo |
|-----||----------|
|   0 ||        2 |
|   1 ||        3 |
+-----++----------+

func (*GroupedSeries) Median

func (g *GroupedSeries) Median() *Series

Median coerces values to float64 and calculates the median of each group.

func (*GroupedSeries) Min

func (g *GroupedSeries) Min() *Series

Min coerces values to float64 and calculates the minimum of each group.

func (*GroupedSeries) NUnique

func (g *GroupedSeries) NUnique() *Series

NUnique returns the number of unique values in each group.

func (*GroupedSeries) Nth

func (g *GroupedSeries) Nth(n int) *Series

Nth returns the row at position `n` (if it exists) within each group.

func (*GroupedSeries) Reduce

func (g *GroupedSeries) Reduce(name string, lambda GroupReduceFn) *Series

Reduce iterates over the groups in `g` and reduces each group of values into a single value using the function supplied in `lambda`. Reduce returns a new Series named `name` where each reduced group is represented by a single row. The reduction `lambda` function is the first field selected (i.e., not left blank) in the GroupReduceFn.

Example (Float64)
s := NewSeries([]float64{1, 2, 3, 4, 5, 6}, []int{0, 0, 0, 1, 1, 1}).
	SetName("foo").
	SetLabelNames([]string{"baz"})
fmt.Println(s)

g := s.GroupBy("baz")
maxOdd := GroupReduceFn{Float64: func(vals []float64) float64 {
	max := math.Inf(-1)
	for i := range vals {
		if int(vals[i])%2 == 1 && vals[i] > max {
			max = vals[i]
		}
	}
	return max
}}
fmt.Println(g.Reduce("max_odd", maxOdd))
Output:
+-----++-----+
| baz || foo |
|-----||-----|
|   0 ||   1 |
|     ||   2 |
|     ||   3 |
|   1 ||   4 |
|     ||   5 |
|     ||   6 |
+-----++-----+

+-----++-------------+
| baz || max_odd_foo |
|-----||-------------|
|   0 ||           3 |
|   1 ||           5 |
+-----++-------------+

func (*GroupedSeries) SliceLabels

func (g *GroupedSeries) SliceLabels() []interface{}

SliceLabels returns the grouped label levels as interface{} slices within an []interface returns the group's labels as slices within an []interface that may be supplied as optional `labels` argument to NewSeries() or NewDataFrame().

func (*GroupedSeries) Std

func (g *GroupedSeries) Std() *Series

Std coerces values to float64 and calculates the standard deviation of each group.

func (*GroupedSeries) String

func (g *GroupedSeries) String() string

func (*GroupedSeries) Sum

func (g *GroupedSeries) Sum() *Series

Sum coerces values to float64 and calculates the sum of each group.

func (*GroupedSeries) Transform

func (g *GroupedSeries) Transform(name string, lambda func(interface{}) interface{}) *Series

Transform applies `lambda` to every group and returns the modified values in the same order as the original Series values, preserving the original Series labels and named `name`. Each input into each `lambda` call will be a slice of values that may then be type-asserted by the user. The output of each `lambda` call must be a slice that is the same length as the input. All outputs must be of the same type (though this may be a different type than the input).

Example (Zscore)
s := NewSeries([]float64{1, 2, 3, 4}, []int{0, 0, 1, 1}).
	SetName("foo").
	SetLabelNames([]string{"baz"})
fmt.Println(s)

g := s.GroupBy()
zScore := func(input interface{}) interface{} {
	// in normal usage, check the type assertion and handle an error
	vals, _ := input.([]float64)
	var sum float64
	for i := range vals {
		sum += vals[i]
	}
	mean := sum / float64(len(vals))

	var variance float64
	for i := range vals {
		variance += math.Pow((vals[i] - mean), 2)
	}
	std := math.Pow(variance/float64(len(vals)), 0.5)

	ret := make([]float64, len(vals))
	for i := range vals {
		ret[i] = (vals[i] - mean) / std
	}
	return ret
}
fmt.Println(g.Transform("z_score", zScore))
Output:
+-----++-----+
| baz || foo |
|-----||-----|
|   0 ||   1 |
|     ||   2 |
|   1 ||   3 |
|     ||   4 |
+-----++-----+

+-----++---------+
| baz || z_score |
|-----||---------|
|   0 ||      -1 |
|     ||       1 |
|   1 ||      -1 |
|     ||       1 |
+-----++---------+

type GroupedSeriesIterator added in v0.2.0

type GroupedSeriesIterator struct {
	// contains filtered or unexported fields
}

GroupedSeriesIterator iterates over all Series in the group.

func (*GroupedSeriesIterator) Next added in v0.2.0

func (g *GroupedSeriesIterator) Next() bool

Next advances to next grouped Series. Returns false at end of iteration.

func (*GroupedSeriesIterator) Series added in v0.2.0

func (g *GroupedSeriesIterator) Series() *Series

Series returns the current grouped Series.

type Matrix

type Matrix interface {
	Dims() (r, c int)
	At(i, j int) float64
}

Matrix is an interface which is compatible with gonum's mat.Matrix interface

type NullFiller

type NullFiller struct {
	FillForward  bool
	FillBackward bool
	FillZero     bool
	FillFloat    float64
}

NullFiller fills every row with a null value and changes the row status to not-null. If multiple fields are provided, resolves in the following order: 1) `FillForward` - fills with the last valid value, 2) `FillBackward` - fills with the next valid value, 3) `FillZero` - fills with the zero type of the slice, 4) `FillFloat` - coerces to float64 and fills with the value provided.

type Resampler

type Resampler struct {
	ByYear      bool
	ByMonth     bool
	ByDay       bool
	ByWeek      bool
	StartOfWeek time.Weekday
	ByDuration  time.Duration
	Location    *time.Location
}

Resampler supplies logic for the Resample() function. Only the first non-Location field selected (i.e., not left nil) is used - any others are ignored (except for `ByWeek`, which may be modified by `StartOfWeek`). `ByYear` truncates the timestamp by year. `ByMonth` truncates the timestamp by month. `ByDay` truncates the timestamp by day. `ByWeek` returns the first day of the most recent week (starting on `StartOfWeek`) relative to timestamp. Otherwise, truncates the timestamp `ByDuration`. If `Location` is not provided, time.UTC is used as the default location.

type Series

type Series struct {
	// contains filtered or unexported fields
}

A Series is a single column of data with one or more levels of aligned labels.

Example
s := NewSeries([]float64{1, 2}).SetName("foo")
fmt.Println(s)
Output:
+---++-----+
| - || foo |
|---||-----|
| 0 ||   1 |
| 1 ||   2 |
+---++-----+
Example (NestedSlice)
s := NewSeries([][]string{{"foo", "bar"}, {"baz"}, {}}).
	SetName("a")
fmt.Println(s)
Output:
+---++-----------+
| - ||     a     |
|---||-----------|
| 0 || [foo bar] |
| 1 ||     [baz] |
| 2 ||       n/a |
+---++-----------+
Example (WithError)
s := &Series{err: errors.New("foo")}
fmt.Println(s)
Output:
Error: foo
Example (WithNullValues)
s := NewSeries([]string{"foo", ""})
fmt.Println(s)
Output:
+---++-----+
| - ||  0  |
|---||-----|
| 0 || foo |
| 1 || n/a |
+---++-----+
Example (Zscore)
s := NewSeries([]float64{1, 2, 3, 4, 5}).SetName("foo")
fmt.Println(s)

vals := s.GetValuesFloat64()
ret := make([]float64, s.Len())
mean := s.Mean()
std := s.Std()
for i := range vals {
	ret[i] = (vals[i] - mean) / std
}

newS := NewSeries(ret, s.GetLabels()...).SetName("zscore_foo")
decimalFormat := ApplyFormatFn{Float64: func(v float64) string { return strconv.FormatFloat(v, 'f', 2, 64) }}
newS.InPlace().ApplyFormat(decimalFormat)
fmt.Println(newS)
Output:
+---++-----+
| - || foo |
|---||-----|
| 0 ||   1 |
| 1 ||   2 |
| 2 ||   3 |
| 3 ||   4 |
| 4 ||   5 |
+---++-----+

+---++------------+
| - || zscore_foo |
|---||------------|
| 0 ||      -1.41 |
| 1 ||      -0.71 |
| 2 ||       0.00 |
| 3 ||       0.71 |
| 4 ||       1.41 |
+---++------------+

func NewSeries

func NewSeries(slice interface{}, labels ...interface{}) *Series

NewSeries constructs a Series from a `slice` of values and optional `label` slices. // `Slice` and all `labels` must be supported slices.

If no `labels` are supplied, a default label level is inserted ([]int incrementing from 0). Series values are named 0 by default. The default values name is displayed on printing. Label levels are named *n (e.g., *0, *1, etc) by default. Default label names are hidden on printing.

Supported slice types: all variants of []float, []int, & []uint, []string, []bool, []time.Time, []interface{}, and 2-dimensional variants of each (e.g., [][]string, [][]float64).

func (*Series) Add

func (s *Series) Add(other *Series, ignoreNulls bool) *Series

Add coerces `other` and `s` to float64 values, aligns `other` with `s`, and adds the values in aligned rows, using the labels in `s` as an anchor. If `ignoreNulls` is true, then missing or null values are treated as 0. Otherwise, if a row in `s` does not align with any row in `other`, or if row does align but either value is null, then the resulting value is null.

func (*Series) Append

func (s *Series) Append(other *Series) *Series

Append adds the `other` labels and values as new rows to the Series. If the types of any container do not match, all the values in that container are coerced to string. Returns a new Series.

func (*Series) Apply

func (s *Series) Apply(lambda ApplyFn) *Series

Apply applies a user-defined function to every row in the Series based on `lambda`. The first field selected (i.e., not left blank) in the ApplyFn struct provides the apply logic. Values are converted from their original type to the selected field type. For example, {ApplyFn{Float64: lambda}} converts the Series values to float64 and applies the lambda function to each row in the container, outputting a new float64 value for each row. If a value is null either before or after the lambda function is applied, it is also null after. Returns a new Series.

Example (Float64)
s := NewSeries([]int{1, 2, 3}).SetName("foo")
fmt.Println(s)

// coerces to float64, applies func
times2 := ApplyFn{Float64: func(v float64) float64 { return v * 2 }}
fmt.Println(s.Apply(times2))
Output:
+---++-----+
| - || foo |
|---||-----|
| 0 ||   1 |
| 1 ||   2 |
| 2 ||   3 |
+---++-----+

+---++-----+
| - || foo |
|---||-----|
| 0 ||   2 |
| 1 ||   4 |
| 2 ||   6 |
+---++-----+

func (*Series) ApplyFormat

func (s *Series) ApplyFormat(lambda ApplyFormatFn) *Series

ApplyFormat applies a user-defined formatting function to every row in the Series based on `lambda`. The first field selected (i.e., not left blank) in the ApplyFormatFn struct provides the formatting logic. Values are converted from their original type to the selected field type and then to string. For example, {ApplyFn{Float64: lambda}} converts the Series values to float64 and applies the lambda function to each row in the container, outputting a new string value for each row. If a value is null either before or after the lambda function is applied, it is also null after. Returns a new Series.

Example (DateTime)
s := NewSeries([]time.Time{time.Date(2020, 1, 15, 0, 0, 0, 0, time.UTC)}).SetName("foo")
fmt.Println(s)

monthFormat := ApplyFormatFn{DateTime: func(v time.Time) string { return v.Format("2006-01") }}
fmt.Println(s.ApplyFormat(monthFormat))
Output:
+---++----------------------+
| - ||         foo          |
|---||----------------------|
| 0 || 2020-01-15T00:00:00Z |
+---++----------------------+

+---++---------+
| - ||   foo   |
|---||---------|
| 0 || 2020-01 |
+---++---------+
Example (Float64)
s := NewSeries([]float64{1, 2.5, 3.1415}).SetName("foo")
fmt.Println(s)

decimalFormat := ApplyFormatFn{Float64: func(v float64) string { return strconv.FormatFloat(v, 'f', 2, 64) }}
fmt.Println(s.ApplyFormat(decimalFormat))
Output:
+---++--------+
| - ||  foo   |
|---||--------|
| 0 ||      1 |
| 1 ||    2.5 |
| 2 || 3.1415 |
+---++--------+

+---++------+
| - || foo  |
|---||------|
| 0 || 1.00 |
| 1 || 2.50 |
| 2 || 3.14 |
+---++------+

func (*Series) At

func (s *Series) At(index int) Element

At returns the Element at the `index` position. If `index` is out of range, returns an empty Element.

func (*Series) Cast

func (s *Series) Cast(containerAsType map[string]DType)

Cast casts the underlying container values (either label levels or Series values) to []float64, []string, or []time.Time. To apply to Series values, supply empty string name ("") or the Series name. Use cast to improve performance when calling multiple operations on values.

func (*Series) Copy

func (s *Series) Copy() *Series

Copy returns a deep copy of a Series with no shared references to the original.

func (*Series) Count

func (s *Series) Count() int

Count counts the number of non-null Series values.

func (*Series) CumSum

func (s *Series) CumSum() *Series

CumSum coerces the Series values to float64 and returns the cumulative sum at each row position.

func (*Series) Cut

func (s *Series) Cut(bins []float64, config *Cutter) *Series

Cut coerces the Series values to float64 and categorizes each row based on which `bin` interval it falls within. `bins` should be a slice of sequential edges that form intervals (left exclusive, right inclusive). For example, [1, 3, 5] represents the intervals 1-3 (excluding 1, including 3), and 3-5 (excluding 3, including 5). If these bins were supplied for a Series with values [3, 4], the returned Series would have values ["1-3", "3-5"]. For default behavior, supply nil as `config`. To categorize values below or above the bin range, or to supply custom labels, supply a tada.Cutter as `config`. If custom labels are supplied, the length must be 1 less than the total number of bin edges.

func (*Series) DType

func (s *Series) DType() string

DType returns the slice type of the underlying Series values

func (*Series) Divide

func (s *Series) Divide(other *Series, ignoreNulls bool) *Series

Divide coerces `other` and `s` to float64 values, aligns `other` with `s`, and divides the aligned values of `s` by `s`, using the labels in `s` as an anchor. Dividing by 0 always returns a null value. If `ignoreNulls` is true, then missing or null values are treated as 0. Otherwise, if a row in `s` does not align with any row in `other`, or if row does align but either value is null, then the resulting value is null.

func (*Series) DropLabels

func (s *Series) DropLabels(name string) *Series

DropLabels removes the first label level matching `name`. Returns a new Series.

func (*Series) DropNull

func (s *Series) DropNull() *Series

DropNull returns all the rows with non-null values. Returns a new Series.

func (*Series) DropRow

func (s *Series) DropRow(index int) *Series

DropRow removes the row at the specified index. Returns a new Series.

func (*Series) Earliest

func (s *Series) Earliest() time.Time

Earliest coerces the Series values to time.Time and calculates the earliest timestamp.

func (*Series) EqualsCSV

func (s *Series) EqualsCSV(csv [][]string, includeLabels bool) (bool, *tablediff.Differences)

EqualsCSV converts a Series to csv, compares it to another csv, and evaluates whether the two match and isolates their differences. If `includeLabels` is true, then the Series' labels are included as columns.

func (*Series) Err

func (s *Series) Err() error

Err returns the most recent error attached to the Series, if any.

func (*Series) FillNull

func (s *Series) FillNull(how NullFiller) *Series

FillNull fills all the null values and makes them not-null. Returns a new Series.

func (*Series) Filter

func (s *Series) Filter(filters map[string]FilterFn) *Series

Filter returns all rows that satisfy all of the `filters`, which is a map of container names (either the Series name or label name) and tada.FilterFn structs. Filter may be applied to the Series values by supplying either the Series name or an empty string ("") as a key. For each container name in the map, the first field selected (i.e., not left blank) in its FilterFn struct provides the filter logic for that container.

Values are coerced from their original type to the selected field type for filtering, but after filtering retains their original type. For example, {"foo": FilterFn{Float64: lambda}} converts the values in the foo container to float64, applies the true/false lambda function to each row in the container, and returns the rows that return true in their original type. Rows with null values are always excluded from the filtered data. If no filter is provided, returns a new copy of the Series. For equality filtering on one or more containers, see also s.FilterByValue(). Returns a new Series.

func (*Series) FilterByValue added in v0.3.5

func (s *Series) FilterByValue(filters map[string]interface{}) *Series

FilterByValue returns a cross section of the rows in the Series satisfying all `filters`, which is a map of of container names (either the Series name or label name) to interface{} values. A filter is satisfied for a given row value if the stringified value in that container matches the stringified interface{} value. FilterByValue may be applied to the Series values by supplying either the Series name or an empty string ("") as a key. Returns a new Series.

func (*Series) GetLabels added in v0.3.5

func (s *Series) GetLabels() []interface{}

GetLabels returns label levels as interface{} slices within an []interface that may be supplied as optional `labels` argument to NewSeries() or NewDataFrame().

func (*Series) GetValues

func (s *Series) GetValues() interface{}

GetValues returns a copy of the underlying Series data as an interface.

func (*Series) GetValuesFloat64 added in v0.3.5

func (s *Series) GetValuesFloat64() []float64

GetValuesFloat64 coerces the Series values into []float64.

func (*Series) GetValuesString added in v0.3.5

func (s *Series) GetValuesString() []string

GetValuesString coerces the Series values into []string.

func (*Series) GetValuesTime added in v0.3.5

func (s *Series) GetValuesTime() []time.Time

GetValuesTime coerces the Series values into []time.Time.

func (*Series) GroupBy

func (s *Series) GroupBy(names ...string) *GroupedSeries

GroupBy groups the Series rows that share the same stringified value in the container(s) (columns or labels) specified by `names`.

Example
s := NewSeries([]float64{1, 2, 3, 4}, []string{"foo", "foo", "bar", "bar"})
fmt.Println(s.GroupBy("*0"))
Output:
Groups: foo,bar
Example (CompoundGroup)
s := NewSeries([]float64{1, 2}, []string{"foo", "foo"}, []string{"bar", "bar"})
fmt.Println(s.GroupBy("*0", "*1"))
Output:
Groups: foo|bar

func (*Series) Head

func (s *Series) Head(n int) *Series

Head returns the first `n` rows of the Series. If `n` is greater than the length of the Series, returns the entire Series. In either case, returns a new Series.

func (*Series) InPlace

func (s *Series) InPlace() *SeriesMutator

InPlace returns a SeriesMutator, which contains most of the same methods as Series but never returns a new Series. If you want to save memory and improve performance and do not need to preserve the original Series, consider using InPlace().

func (*Series) IndexOfLabel

func (s *Series) IndexOfLabel(name string) int

IndexOfLabel returns the index position of the first label level with a name matching `name` (case-sensitive). If `name` does not match any container, -1 is returned.

func (*Series) IndexOfRows

func (s *Series) IndexOfRows(name string, value interface{}) []int

IndexOfRows returns the index positions of the rows with stringified value matching `value` in the container named `name`. To search Series values, supply either the Series name or an empty string ("") as `name`.

func (*Series) Iterator added in v0.2.0

func (s *Series) Iterator() *SeriesIterator

Iterator returns an iterator which may be used to access the values in each row as map[string]Element.

func (*Series) Latest

func (s *Series) Latest() time.Time

Latest coerces the Series values to time.Time and calculates the latest timestamp.

func (*Series) Len

func (s *Series) Len() int

Len returns the number of rows in the Series.

func (*Series) ListLabelNames

func (s *Series) ListLabelNames() []string

ListLabelNames returns the name and position of all the label levels in the Series

func (*Series) Lookup

func (s *Series) Lookup(other *Series) *Series

Lookup performs the lookup portion of a left join of `other` onto `s` using containers with matching names as keys. To perform a different type of lookup or specify the matching keys, use s.LookupAdvanced().

Lookup identifies the row alignment between `s` and `other` and returns the aligned values. Rows are aligned when: 1) one or more containers (either column or label level) in `other` share the same name as one or more containers in `s`, and 2) the stringified values in the `other` containers match the values in the `s` containers. For the following dataframes:

`s` `other` FOO BAR FOO QUX bar 0 baz corge baz 1 qux waldo

Row 1 in `s` is "aligned" with row 0 in `other`, because those are the rows in which both share the same value ("baz") in a container with the same name ("foo"). The result of a lookup will be:

FOO BAR bar n/a baz corge

Returns a new DataFrame.

Example
s := NewSeries([]float64{1, 2}, []int{0, 1}).SetName("foo")
fmt.Println("--original Series--")
fmt.Println(s)

s2 := NewSeries([]float64{4, 5}, []int{0, 10})
fmt.Println("--Series to lookup--")
fmt.Println(s2)

fmt.Println("--result--")
fmt.Println(s.Lookup(s2))
Output:
--original Series--
+---++-----+
| - || foo |
|---||-----|
| 0 ||   1 |
| 1 ||   2 |
+---++-----+

--Series to lookup--
+----++---+
| -  || 0 |
|----||---|
|  0 || 4 |
| 10 || 5 |
+----++---+

--result--
+---++-----+
| - || foo |
|---||-----|
| 0 ||   4 |
| 1 || n/a |
+---++-----+

func (*Series) LookupAdvanced

func (s *Series) LookupAdvanced(other *Series, how string, leftOn []string, rightOn []string) *Series

LookupAdvanced performs the lookup portion of a join of `other` onto `s` matching on the container keys specified. Supported `how` options: left, right, inner.

LookupAdvanced identifies the row alignment between `s` and `other` and returns the aligned values. Rows are aligned when: 1) one or more containers (either values or label level) in `other` share the same name as one or more containers in `s`, and 2) the stringified values in the `other` containers match the values in the `s` containers. For the following dataframes:

`s` `other` FOO BAR FRED QUX bar 0 baz corge baz 1 qux waldo

In LookupAdvanced(other, "left", ["foo"], ["fred"]), row 1 in `s` is "aligned" with row 0 in `other`, because those are the rows in which both share the same value ("baz") in the keyed containers. The result of this lookup will be:

FOO BAR bar n/a baz corge

Returns a new Series.

Example
s := NewSeries([]float64{1, 2}, []string{"foo", "bar"}, []int{0, 1})
fmt.Println("--original Series--")
fmt.Println(s)

s2 := NewSeries([]float64{4, 5}, []int{0, 10}, []string{"baz", "bar"})
fmt.Println("--Series to lookup--")
fmt.Println(s2)

fmt.Println("--result--")
fmt.Println(s.LookupAdvanced(s2, "inner", []string{"*1"}, []string{"*0"}))
Output:
--original Series--
+-----+---++---+
|  -  | - || 0 |
|-----|---||---|
| foo | 0 || 1 |
| bar | 1 || 2 |
+-----+---++---+

--Series to lookup--
+----+-----++---+
| -  |  -  || 0 |
|----|-----||---|
|  0 | baz || 4 |
| 10 | bar || 5 |
+----+-----++---+

--result--
+-----+---++---+
|  -  | - || 0 |
|-----|---||---|
| foo | 0 || 4 |
+-----+---++---+

func (*Series) Max

func (s *Series) Max() float64

Max coerces the Series values to float64 and calculates the maximum.

func (*Series) Mean

func (s *Series) Mean() float64

Mean coerces the Series values to float64 and calculates the mean.

func (*Series) Median

func (s *Series) Median() float64

Median coerces the Series values to float64 and calculates the median.

func (*Series) Merge

func (s *Series) Merge(other *Series) *DataFrame

Merge converts `s` and `other` to dataframes. and then performs a left join of `other` onto `df` using containers with matching names as keys. To perform a different type of join or specify the matching keys, use s.ToDataFrame() + df.LookupAdvanced() to isolate values in `other`, and append them with df.WithCol().

Merge identifies the row alignment between `s` and `other` and appends aligned values as new columns on `s`. Rows are aligned when: 1) one or more containers (either column or label level) in `other` share the same name as one or more containers in `s`, and 2) the stringified values in the `other` containers match the values in the `s` containers. For the following dataframes:

`s` `other` FOO BAR FOO QUX bar 0 baz corge baz 1 qux waldo

Row 1 in `s` is "aligned" with row 0 in `other`, because those are the rows in which both share the same value ("baz") in a container with the same name ("foo"). After merging, the result will be:

`s` FOO BAR QUX bar 0 n/a baz 1 corge

Finally, all container names (either the Series name or label name) are deduplicated after the merge so that they are unique. Returns a new DataFrame.

Example
s := NewSeries([]float64{1, 2}, []int{0, 1}).SetName("foo")
fmt.Println("--original Series--")
fmt.Println(s)

s2 := NewSeries([]float64{4, 5}, []int{0, 10}).SetName("bar")
fmt.Println("--Series to merge--")
fmt.Println(s2)

fmt.Println("--result--")
fmt.Println(s.Merge(s2))
Output:
--original Series--
+---++-----+
| - || foo |
|---||-----|
| 0 ||   1 |
| 1 ||   2 |
+---++-----+

--Series to merge--
+----++-----+
| -  || bar |
|----||-----|
|  0 ||   4 |
| 10 ||   5 |
+----++-----+

--result--
+---++-----+-----+
| - || foo | bar |
|---||-----|-----|
| 0 ||   1 |   4 |
| 1 ||   2 | n/a |
+---++-----+-----+

func (*Series) Min

func (s *Series) Min() float64

Min coerces the Series values to float64 and calculates the minimum.

func (*Series) Multiply

func (s *Series) Multiply(other *Series, ignoreNulls bool) *Series

Multiply coerces `other` and `s` to float64 values, aligns `other` with `s`, and multiplies the values in aligned rows, using the labels in `s` as an anchor. If `ignoreNulls` is true, then missing or null values are treated as 0. Otherwise, if a row in `s` does not align with any row in `other`, or if row does align but either value is null, then the resulting value is null.

func (*Series) NUnique

func (s *Series) NUnique() int

NUnique counts the number of unique, non-null Series values.

func (*Series) Name

func (s *Series) Name() string

Name returns the name of the Series

func (*Series) NameOfLabel

func (s *Series) NameOfLabel(n int) string

NameOfLabel returns the name of the label level at index position `n`. If n is out of range, returns "-out of range-"

func (*Series) Null

func (s *Series) Null() *Series

Null returns all the rows with null values. Returns a new Series.

func (*Series) Percentile

func (s *Series) Percentile() *Series

Percentile coerces the Series values to float64 returns the percentile rank of each value (i.e., the % of values in the Series that are below it).

func (*Series) PercentileCut

func (s *Series) PercentileCut(bins []float64, labels []string) *Series

PercentileCut coerces the Series values to float64 and categorizes each value based on which percentile `bin` interval it falls within. `bins` should be a slice of sequential percentile edges (between 0 and 1) that form intervals (left inclusive, right exclusive). For example, [0, .5, 1] represents the percentile intervals 0-50% (excluding 50%) and 50%-100%. If these bins were supplied for a Series with values [1, 1000], the returned Series would have values [0-.5, .5-1], because 1 is in the bottom 50% of values and 1000 is in the top 50% of values. If `labels` is not nil, then category names correspond to labels, and the number of labels must be one less than the number of bin values. Otherwise, category names are auto-generated from the range of the bin intervals.

func (*Series) Range

func (s *Series) Range(first, last int) *Series

Range returns the rows of the Series starting at `first` and `ending` immediately prior to last (left-inclusive, right-exclusive). If either `first` or `last` is out of range, a Series error is returned. In all cases, returns a new Series.

func (*Series) Rank

func (s *Series) Rank() *Series

Rank coerces the Series values to float64 and returns the rank of each (in ascending order - where 1 is the rank of the lowest value). Rows with the same value share the same rank.

func (*Series) Relabel

func (s *Series) Relabel() *Series

Relabel resets the Series labels to default labels (e.g., []int from 0 to df.Len()-1, with *0 as name). Returns a new Series.

func (*Series) Resample

func (s *Series) Resample(by Resampler) *Series

Resample coerces the Series values to time.Time and truncates them `by` the logic supplied in tada.Resampler. Returns a new Series.

Example (ByHalfHour)
s := NewSeries([]time.Time{
	time.Date(2020, 1, 15, 12, 15, 0, 0, time.UTC),
	time.Date(2020, 1, 15, 12, 45, 0, 0, time.UTC),
}).SetName("foo")
fmt.Println(s)

byHalfHour := Resampler{ByDuration: 30 * time.Minute}
fmt.Println(s.Resample(byHalfHour))
Output:
+---++----------------------+
| - ||         foo          |
|---||----------------------|
| 0 || 2020-01-15T12:15:00Z |
| 1 || 2020-01-15T12:45:00Z |
+---++----------------------+

+---++----------------------+
| - ||         foo          |
|---||----------------------|
| 0 || 2020-01-15T12:00:00Z |
| 1 || 2020-01-15T12:30:00Z |
+---++----------------------+
Example (ByHour)
s := NewSeries([]time.Time{time.Date(2020, 1, 15, 12, 30, 0, 0, time.UTC)}).SetName("foo")
fmt.Println(s)

byHour := Resampler{ByDuration: time.Hour}
fmt.Println(s.Resample(byHour))
Output:
+---++----------------------+
| - ||         foo          |
|---||----------------------|
| 0 || 2020-01-15T12:30:00Z |
+---++----------------------+

+---++----------------------+
| - ||         foo          |
|---||----------------------|
| 0 || 2020-01-15T12:00:00Z |
+---++----------------------+
Example (ByMonth)
s := NewSeries([]time.Time{time.Date(2020, 1, 15, 12, 30, 0, 0, time.UTC)}).SetName("foo")
fmt.Println(s)

byMonth := Resampler{ByMonth: true}
fmt.Println(s.Resample(byMonth))
Output:
+---++----------------------+
| - ||         foo          |
|---||----------------------|
| 0 || 2020-01-15T12:30:00Z |
+---++----------------------+

+---++----------------------+
| - ||         foo          |
|---||----------------------|
| 0 || 2020-01-01T00:00:00Z |
+---++----------------------+
Example (ByWeek)
s := NewSeries([]time.Time{time.Date(2020, 1, 15, 12, 30, 0, 0, time.UTC)}).SetName("foo")
fmt.Println(s)

byWeek := Resampler{ByWeek: true, StartOfWeek: time.Sunday}
fmt.Println(s.Resample(byWeek))
Output:
+---++----------------------+
| - ||         foo          |
|---||----------------------|
| 0 || 2020-01-15T12:30:00Z |
+---++----------------------+

+---++----------------------+
| - ||         foo          |
|---||----------------------|
| 0 || 2020-01-12T00:00:00Z |
+---++----------------------+

func (*Series) RollingDuration

func (s *Series) RollingDuration(d time.Duration) *GroupedSeries

RollingDuration iterates over each row in Series, coerces the values to time.Time, and groups each set of subsequent rows that are within `d` of the current row.

func (*Series) RollingN

func (s *Series) RollingN(n int) *GroupedSeries

RollingN iterates over each row in Series and groups each set of `n` subsequent rows after the current row.

func (*Series) SelectLabels

func (s *Series) SelectLabels(name string) *Series

SelectLabels finds the first level with matching `name` and returns as a Series with all existing label levels (including itself). If label level name is default (prefixed with *), removes the prefix. Returns a new Series with shared labels.

func (*Series) SetLabelNames

func (s *Series) SetLabelNames(levelNames []string) *Series

SetLabelNames sets the names of all the label levels in the Series and returns the entire Series.

func (*Series) SetName

func (s *Series) SetName(name string) *Series

SetName modifies the name of a Series in place and returns the original Series.

func (*Series) Shift

func (s *Series) Shift(n int) *Series

Shift replaces the value in row i with the value in row i - `n`, or null if that index is out of range. Returns a new Series.

func (*Series) SliceNulls

func (s *Series) SliceNulls() []bool

SliceNulls returns whether each value is null or not.

func (*Series) Sort

func (s *Series) Sort(by ...Sorter) *Series

Sort sorts the values `by` zero or more Sorter specifications. If no Sorter is supplied, sorts by Series values (as float64) in ascending order. If a Sorter is supplied without a `Name` or with a name matching the Series name, sorts by Series values. If no DType is supplied in a Sorter, sorts as float64. DType is only used for the process of sorting. Once it has been sorted, data retains its original type. Returns a new Series.

func (*Series) Std

func (s *Series) Std() float64

Std coerces the Series values to float64 and calculates the standard deviation.

func (*Series) String

func (s *Series) String() string

func (*Series) Subset

func (s *Series) Subset(index []int) *Series

Subset returns only the rows specified at the index positions, in the order specified. Returns a new Series. Returns a new Series.

func (*Series) SubsetLabels

func (s *Series) SubsetLabels(index []int) *Series

SubsetLabels includes only the columns of labels specified at the index positions, in the order specified. Returns a new Series.

func (*Series) Subtract

func (s *Series) Subtract(other *Series, ignoreNulls bool) *Series

Subtract coerces `other` and `s` to float64 values, aligns `other` with `s`, and subtracts the aligned values of `other` from `s`, using the labels in `s` as an anchor. If `ignoreNulls` is true, then missing or null values are treated as 0. Otherwise, if a row in `s` does not align with any row in `other`, or if row does align but either value is null, then the resulting value is null.

func (*Series) Sum

func (s *Series) Sum() float64

Sum coerces the Series values float64 and sums them.

func (*Series) SwapLabels

func (s *Series) SwapLabels(i, j string) *Series

SwapLabels swaps the label levels with names `i` and `j`. Returns a new Series.

func (*Series) Tail

func (s *Series) Tail(n int) *Series

Tail returns the last `n` rows of the Series. If `n` is greater than the length of the Series, returns the entire Series. In either case, returns a new Series.

func (*Series) ToCSV

func (s *Series) ToCSV(includeLabels bool) ([][]string, error)

ToCSV converts a Series to a DataFrame and returns as [][]string. If `includeLabels` is true, then the Series' labels are written.

func (*Series) ToDataFrame

func (s *Series) ToDataFrame() *DataFrame

ToDataFrame converts a Series to a 1-column DataFrame.

func (*Series) Unique

func (s *Series) Unique(valuesOnly bool) *Series

Unique returns the first appearance of all non-null values in the Series. Returns a new Series.

func (*Series) ValueCounts

func (s *Series) ValueCounts() map[string]int

ValueCounts counts the number of appearances of each stringified value in the Series.

func (*Series) Where

func (s *Series) Where(filters map[string]FilterFn, ifTrue, ifFalse interface{}) (*Series, error)

Where iterates over the rows in `s` and evaluates whether each one satisifes `filters`, which is a map of container names (either the Series name or label name) and tada.FilterFn structs. If yes, returns `ifTrue` at that row position. If not, returns `ifFalse` at that row position. Values are coerced from their original type to the selected field type for filtering, but after filtering retains their original type.

Returns an unnamed Series a copy of the labels from the original Series and null status based on the supplied values. If an unsupported value type is supplied as either ifTrue or ifFalse, returns an error.

func (*Series) WithLabels

func (s *Series) WithLabels(name string, input interface{}) *Series

WithLabels resolves as follows:

If a scalar string is supplied as `input` and a label level exists that matches `name`: rename the level to match `input`. In this case, `name` must already exist.

If a slice is supplied as `input` and a label level exists that matches `name`: replace the values at this level to match `input`. If a slice is supplied as `input` and a label level does not exist that matches `name`: append a new level named `name` and values matching `input`. If `input` is a slice, it must be the same length as the underlying Series.

In all cases, returns a new Series.

func (*Series) WithValues

func (s *Series) WithValues(input interface{}) *Series

WithValues replaces the Series values with `input`. `input` must be a supported slice type of the same length as the original Series. Returns a new Series.

type SeriesIterator added in v0.2.0

type SeriesIterator struct {
	// contains filtered or unexported fields
}

A SeriesIterator iterates over the rows in a Series.

func (*SeriesIterator) Next added in v0.2.0

func (iter *SeriesIterator) Next() bool

Next advances to next row. Returns false at end of iteration.

func (*SeriesIterator) Row added in v0.2.0

func (iter *SeriesIterator) Row() map[string]Element

Row returns the current row in the Series as map[string]Element. The map keys are the names of containers (including label levels). The name of the Series values column is the same as the name of the Series itself. The value in each map is an Element containing an interface value and a boolean denoting if the value is null. If multiple columns have the same header, only the Elements of the left-most column are returned.

type SeriesMutator

type SeriesMutator struct {
	// contains filtered or unexported fields
}

A SeriesMutator is used to change Series values in place.

func (*SeriesMutator) Append

func (s *SeriesMutator) Append(other *Series)

Append adds the `other` labels and values as new rows to the Series. If the types of any container do not match, all the values in that container are coerced to string. Returns a new Series.

func (*SeriesMutator) Apply

func (s *SeriesMutator) Apply(lambda ApplyFn)

Apply applies a user-defined function to every row in the Series based on `lambda`. The first field selected (i.e., not left blank) in the ApplyFn struct provides the apply logic. Values are converted from their original type to the selected field type. For example, {ApplyFn{Float64: lambda}} converts the Series values to float64 and applies the lambda function to each row in the container, outputting a new float64 value for each row. If a value is null either before or after the lambda function is applied, it is also null after. Modifies the underlying Series in place.

func (*SeriesMutator) ApplyFormat

func (s *SeriesMutator) ApplyFormat(lambda ApplyFormatFn)

ApplyFormat applies a user-defined formatting function to every row in the Series based on `lambda`. The first field selected (i.e., not left blank) in the ApplyFormatFn struct provides the formatting logic. Values are converted from their original type to the selected field type and then to string. For example, {ApplyFn{Float64: lambda}} converts the Series values to float64 and applies the lambda function to each row in the container, outputting a new string value for each row. If a value is null either before or after the lambda function is applied, it is also null after. Modifies the underlying Series in place.

func (*SeriesMutator) DropLabels

func (s *SeriesMutator) DropLabels(name string)

DropLabels removes the first label level matching `name`. Modifies the underlying Series in place.

func (*SeriesMutator) DropNull

func (s *SeriesMutator) DropNull()

DropNull returns all the rows with non-null values. Modifies the underlying Series.

func (*SeriesMutator) DropRow

func (s *SeriesMutator) DropRow(index int)

DropRow removes the row at the specified index. Modifies the underlying Series in place.

func (*SeriesMutator) FillNull

func (s *SeriesMutator) FillNull(how NullFiller)

FillNull fills all the null values and makes them not-null. Modifies the underlying Series.

func (*SeriesMutator) Filter

func (s *SeriesMutator) Filter(filters map[string]FilterFn)

Filter returns all rows that satisfy all of the `filters`, which is a map of container names (either the Series name or label name) and tada.FilterFn structs. Filter may be applied to the Series values by supplying either the Series name or an empty string ("") as a key. For each container name in the map, the first field selected (i.e., not left blank) in its FilterFn struct provides the filter logic for that container

Values are coerced from their original type to the selected field type for filtering, but after filtering retains their original type. For example, {"foo": FilterFn{Float64: lambda}} converts the values in the foo container to float64, applies the true/false lambda function to each row in the container, and returns the rows that return true in their original type. Rows with null values are always excluded from the filtered data. If no filter is provided, does nothing. For equality filtering on one or more containers, see also s.FilterByValue(). Modifies the underlying Series in place.

func (*SeriesMutator) FilterByValue added in v0.3.5

func (s *SeriesMutator) FilterByValue(filters map[string]interface{})

FilterByValue returns a cross section of the rows in the Series satisfying all `filters`, which is a map of of container names (either the Series name or label name) to interface{} values. A filter is satisfied for a given row value if the stringified value in that container matches the stringified interface{} value. FilterByValue may be applied to the Series values by supplying either the Series name or an empty string ("") as a key. Modifies the underlying Series in place.

func (*SeriesMutator) Relabel

func (s *SeriesMutator) Relabel()

Relabel resets the Series labels to default labels (e.g., []int from 0 to df.Len()-1, with *0 as name). Modifies the underlying Series in place.

func (*SeriesMutator) Resample

func (s *SeriesMutator) Resample(by Resampler)

Resample coerces the Series values to time.Time and truncates them `by` the logic supplied in tada.Resampler. Modifies the underlying Series in place.

func (*SeriesMutator) Shift

func (s *SeriesMutator) Shift(n int)

Shift replaces the value in row i with the value in row i - `n`, or null if that index is out of range. // Modifies the underlying Series.

func (*SeriesMutator) Sort

func (s *SeriesMutator) Sort(by ...Sorter)

Sort sorts the values `by` zero or more Sorter specifications. If no Sorter is supplied, sorts by Series values (as float64) in ascending order. If a Sorter is supplied without a `Name` or with a name matching the Series name, sorts by Series values. If no DType is supplied in a Sorter, sorts as float64. Modifies the underlying Series in place.

func (*SeriesMutator) Subset

func (s *SeriesMutator) Subset(index []int)

Subset returns only the rows specified at the index positions, in the order specified. Modifies the underlying Series in place.

func (*SeriesMutator) SubsetLabels

func (s *SeriesMutator) SubsetLabels(index []int)

SubsetLabels includes only the columns of labels specified at the index positions, in the order specified. Modifies the underlying Series in place.

func (*SeriesMutator) SwapLabels

func (s *SeriesMutator) SwapLabels(i, j string)

SwapLabels swaps the label levels with names `i` and `j`. Modifies the underlying Series in place.

func (*SeriesMutator) WithLabels

func (s *SeriesMutator) WithLabels(name string, input interface{})

WithLabels resolves as follows:

If a scalar string is supplied as `input` and a label level exists that matches `name`: rename the level to match `input`. In this case, `name` must already exist.

If a slice is supplied as `input` and a label level exists that matches `name`: replace the values at this level to match `input`. If a slice is supplied as `input` and a label level does not exist that matches `name`: append a new level named `name` and values matching `input`. If `input` is a slice, it must be the same length as the underlying Series.

In all cases, modifies the underlying Series in place.

func (*SeriesMutator) WithValues

func (s *SeriesMutator) WithValues(input interface{})

WithValues replaces the Series values with `input`. `input` must be a supported slice type of the same length as the original Series. Modifies the underlying Series.

type Sorter

type Sorter struct {
	Name       string
	Descending bool
	DType      DType
}

A Sorter supplies details to the Sort() function. `Name` specifies the container (either label or column name) to sort. If `Descending` is true, values are sorted in descending order. `DType` specifies the data type to which values will be coerced before they are sorted (default: float64). Null values are always sorted to the bottom.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL