Getting Started

Installation guides for Node and Browser based environments, including a quick 10 minute walk through of danfo.js

A stable version of Danfojs (v1), has been released, and it comes with full Typescript support, new features, and many bug fixes. See release note here.

There are a couple of breaking changes, so we have prepared a short migration guide for pre-v1 users.

Installation

There are three ways to install and use Danfo.js in your application

For Nodejs applications, you can install the danfojs-node version via package managers like yarn and npm:

npm install danfojs-node

or

yarn add danfojs-node

For client-side applications built with frameworks like React, Vue, Next.js, etc, you can install the danfojs version:

npm install danfojs

or

yarn add danfojs

For use directly in HTML files, you can add the latest script tag from JsDelivr:

<script src="https://cdn.jsdelivr.net/npm/[email protected]/lib/bundle.min.js"></script>

To play with Danfo.js in a Notebook-like environment, see Dnotebooks here or the VS-Code Nodejs notebook extension.

10 minutes to danfo.js

This is a short introduction to Danfo.js, and its flow is adapted from the official 10 minutes to Pandas

We will show you how to use danfo.js in a browser, client-side libraries, and Node.js environments. Most functions except plotting which require a DOM work the same way in all environments.

const dfd = require("danfojs-node")

//or using ES6
import * as dfd from "danfojs-node"

Creating a DataFrame/Series

You can create a Series by passing a list of values, letting Danfo.js create a default integer index:

import * as dfd from "danfojs-node"

s = new dfd.Series([1, 3, 5, undefined, 6, 8])
s.print()
//output
╔═══╤══════════════════════╗
║   │ 0                    ║
╟───┼──────────────────────╢
║ 0 │ 1                    ║
╟───┼──────────────────────╢
║ 1 │ 3                    ║
╟───┼──────────────────────╢
║ 2 │ 5                    ║
╟───┼──────────────────────╢
║ 3 │ undefined            ║
╟───┼──────────────────────╢
║ 4 │ 6                    ║
╟───┼──────────────────────╢
║ 5 │ 8                    ║
╚═══╧══════════════════════╝

Creating a Series from a tensor

const dfd = require("danfojs-node")
const tf = dfd.tensorflow //Tensorflow.js is exportedfrom Danfojs


let tensor_arr = tf.tensor([12,34,56,2])
let s = new dfd.Series(tensor_arr)
s.print()
╔═══╤════╗
║ 0 │ 12 ║
╟───┼────╢
║ 1 │ 34 ║
╟───┼────╢
║ 2 │ 56 ║
╟───┼────╢
║ 3 │ 2  ║
╚═══╧════╝

Creating a DataFrame by passing a JSON object:

const dfd = require("danfojs-node")


json_data = [{ A: 0.4612, B: 4.28283, C: -1.509, D: -1.1352 },
            { A: 0.5112, B: -0.22863, C: -3.39059, D: 1.1632 },
            { A: 0.6911, B: -0.82863, C: -1.5059, D: 2.1352 },
            { A: 0.4692, B: -1.28863, C: 4.5059, D: 4.1632 }]

df = new dfd.DataFrame(json_data)
df.print()

Creating a DataFrame from a 2D tensor

const dfd = require("danfojs-node")
const tf = dfd.tensorflow //Tensorflow.js is exported from Danfojs


let tensor_arr = tf.tensor2d([[12, 34, 2.2, 2], [30, 30, 2.1, 7]])
let df = new dfd.DataFrame(tensor_arr, {columns: ["A", "B", "C", "D"]})
df.print()
df.ctypes.print()
╔═══╤═══════════════════╤═══════════════════╤═══════════════════╤═══════════════════╗
║   │ A                 │ B                 │ C                 │ D                 ║
╟───┼───────────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 0 │ 12                │ 34                │ 2.20000004768...  │ 2                 ║
╟───┼───────────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 1 │ 30                │ 30                │ 2.09999990463...  │ 7                 ║
╚═══╧═══════════════════╧═══════════════════╧═══════════════════╧═══════════════════╝

╔═══╤══════════════════════╗
║   │ 0                    ║
╟───┼──────────────────────╢
║ A │ int32                ║
╟───┼──────────────────────╢
║ B │ int32                ║
╟───┼──────────────────────╢
║ C │ float32              ║
╟───┼──────────────────────╢
║ D │ int32                ║
╚═══╧══════════════════════╝

Creating a DataFrame by passing a dictionary of objects with the same length

const dfd = require("danfojs-node")

// Danfojs v1.0.0 and above
dates = new dfd.dateRange({ start: '2017-01-01', end: "2020-01-01", period: 4, freq: "Y" })

console.log(dates);

obj_data = {'A': dates,
            'B': ["bval1", "bval2", "bval3", "bval4"],
            'C': [10, 20, 30, 40],
            'D': [1.2, 3.45, 60.1, 45],
            'E': ["test", "train", "test", "train"]
            }

df = new dfd.DataFrame(obj_data)
df.print()
//output in console
╔═══╤═══════════════════╤═══════════════════╤═══════════════════╤═══════════════════╤═══════════════════╗
║   │ A                 │ B                 │ C                 │ D                 │ E                 ║
╟───┼───────────────────┼───────────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 0 │ 1/1/2017, 1:0...  │ bval1             │ 10                │ 1.2               │ test              ║
╟───┼───────────────────┼───────────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 1 │ 1/1/2018, 1:0...  │ bval2             │ 20                │ 3.45              │ train             ║
╟───┼───────────────────┼───────────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 2 │ 1/1/2019, 1:0...  │ bval3             │ 30                │ 60.1              │ test              ║
╟───┼───────────────────┼───────────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 3 │ 1/1/2020, 1:0...  │ bval4             │ 40                │ 45                │ train             ║
╚═══╧═══════════════════╧═══════════════════╧═══════════════════╧═══════════════════╧═══════════════════╝

The columns of the resulting DataFrame have different dtypes.

df.ctypes.print()
//output
╔═══╤═════════╗
║ A │ string  ║
╟───┼─────────╢
║ B │ string  ║
╟───┼─────────╢
║ C │ int32   ║
╟───┼─────────╢
║ D │ float32 ║
╟───┼─────────╢
║ E │ string  ║
╚═══╧═════════╝

Creating a DataFrame by passing an array of arrays. Index and column labels are automatically generated for you.

const dfd = require("danfojs-node")

arr_data = [["bval1", 10, 1.2, "test"],
            ["bval2", 20, 3.45, "train"],
            ["bval3", 30, 60.1, "train"],
            ["bval4", 35, 3.2, "test"]]

df = new dfd.DataFrame(arr_data)
df.print()
//output in console

╔═══╤═══════════════════╤═══════════════════╤═══════════════════╤═══════════════════╗
║   │ 0                 │ 1                 │ 2                 │ 3                 ║
╟───┼───────────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 0 │ bval1             │ 10                │ 1.2               │ test              ║
╟───┼───────────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 1 │ bval2             │ 20                │ 3.45              │ train             ║
╟───┼───────────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 2 │ bval3             │ 30                │ 60.1              │ train             ║
╟───┼───────────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 3 │ bval4             │ 35                │ 3.2               │ test              ║
╚═══╧═══════════════════╧═══════════════════╧═══════════════════╧═══════════════════╝

Viewing data

Here is how to view the top and bottom rows of the frame above:

df.head(2).print()
df.tail(2).print()
//output from head
╔═══╤═══════════════════╤═══════════════════╤═══════════════════╤═══════════════════╗
║   │ 0                 │ 1                 │ 2                 │ 3                 ║
╟───┼───────────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 0 │ bval1             │ 10                │ 1.2               │ test              ║
╟───┼───────────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 1 │ bval2             │ 20                │ 3.45              │ train             ║
╚═══╧═══════════════════╧═══════════════════╧═══════════════════╧═══════════════════╝


//output from tail

╔═══╤═══════════════════╤═══════════════════╤═══════════════════╤═══════════════════╗
║   │ 0                 │ 1                 │ 2                 │ 3                 ║
╟───┼───────────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 2 │ bval3             │ 30                │ 60.1              │ train             ║
╟───┼───────────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 3 │ bval4             │ 35                │ 3.2               │ test              ║
╚═══╧═══════════════════╧═══════════════════╧═══════════════════╧═══════════════════╝

Display the index, columns:

const dfd = require('danfojs-node')

let dates = new dfd.dateRange({
    start: "2017-01-01",
    end: "2020-01-01",
    period: 4,
    freq: "Y",
  });

  let obj_data = {
    A: dates,
    B: ["bval1", "bval2", "bval3", "bval4"],
    C: [10, 20, 30, 40],
    D: [1.2, 3.45, 60.1, 45],
    E: ["test", "train", "test", "train"],
  };

  let df = new dfd.DataFrame(obj_data);
  df.print();
  console.log(df.index);
  console.log(df.columns);
//output

╔════════════╤═══════════════════╤═══════════════════╤═══════════════════╤═══════════════════╤═══════════════════╗
║            │ A                 │ B                 │ C                 │ D                 │ E                 ║
╟────────────┼───────────────────┼───────────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 0          │ 1/1/2017, 1:00:…  │ bval1             │ 10                │ 1.2               │ test              ║
╟────────────┼───────────────────┼───────────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 1          │ 1/1/2018, 1:00:…  │ bval2             │ 20                │ 3.45              │ train             ║
╟────────────┼───────────────────┼───────────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 2          │ 1/1/2019, 1:00:…  │ bval3             │ 30                │ 60.1              │ test              ║
╟────────────┼───────────────────┼───────────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 3          │ 1/1/2020, 1:00:…  │ bval4             │ 40                │ 45                │ train             ║
╚════════════╧═══════════════════╧═══════════════════╧═══════════════════╧═══════════════════╧═══════════════════╝

[ 0, 1, 2, 3 ]
[ 'A', 'B', 'C', 'D', 'E' ]

DataFrame.tensor returns a Tensorflow tensor representation of the underlying data. Note that Tensorflow tensors have one dtype for the entire array, while danfo DataFrames have one dtype per column.

For df, our DataFrame of all floating-point values, DataFrame.tensoris fast and doesn’t require copying data.

const dfd = require("danfojs-node")


j son_data = [{ A: 0.4612, B: 4.28283, C: -1.509, D: -1.1352 },
{ A: 0.5112, B: -0.22863, C: -3.39059, D: 1.1632 },
{ A: 0.6911, B: -0.82863, C: -1.5059, D: 2.1352 },
{ A: 0.4692, B: -1.28863, C: 4.5059, D: 4.1632 }]

let  df = new dfd.DataFrame(json_data)

console.log(df.tensor);
//or
df.tensor.print()
//output

Tensor {
  kept: false,
  isDisposedInternal: false,
  shape: [ 4, 4 ],
  dtype: 'float32',
  size: 16,
  strides: [ 4 ],
  dataId: {},
  id: 0,
  rankType: '2'
}

Tensor
    [[0.4612, 4.2828302, -1.5089999, -1.1352  ],
     [0.5112, -0.22863 , -3.39059  , 1.1632   ],
     [0.6911, -0.82863 , -1.5059   , 2.1352   ],
     [0.4692, -1.28863 , 4.5058999 , 4.1631999]]

Note

DataFrame.tensor does not include the index or column labels in the output.

describe() shows a quick statistic summary of your data:

const dfd = require("danfojs-node")


let json_data = [{ A: 0.4612, B: 4.28283, C: -1.509, D: -1.1352 },
{ A: 0.5112, B: -0.22863, C: -3.39059, D: 1.1632 },
{ A: 0.6911, B: -0.82863, C: -1.5059, D: 2.1352 },
{ A: 0.4692, B: -1.28863, C: 4.5059, D: 4.1632 }]

let df = new dfd.DataFrame(json_data)

df.describe().print()
//output in console

╔════════════╤═══════════════════╤═══════════════════╤═══════════════════╤═══════════════════╗
║            │ A                 │ B                 │ C                 │ D                 ║
╟────────────┼───────────────────┼───────────────────┼───────────────────┼───────────────────╢
║ count      │ 4                 │ 4                 │ 4                 │ 4                 ║
╟────────────┼───────────────────┼───────────────────┼───────────────────┼───────────────────╢
║ mean       │ 0.533175          │ 0.4842349999999…  │ -0.474897500000…  │ 1.5816            ║
╟────────────┼───────────────────┼───────────────────┼───────────────────┼───────────────────╢
║ std        │ 0.1075428712963…  │ 2.5693167249095…  │ 3.4371471031498…  │ 2.2005448052698…  ║
╟────────────┼───────────────────┼───────────────────┼───────────────────┼───────────────────╢
║ min        │ 0.4612            │ -1.28863          │ -3.39059          │ -1.1352           ║
╟────────────┼───────────────────┼───────────────────┼───────────────────┼───────────────────╢
║ median     │ 0.4901999999999…  │ -0.528629999999…  │ -1.50745          │ 1.6492            ║
╟────────────┼───────────────────┼───────────────────┼───────────────────┼───────────────────╢
║ max        │ 0.6911            │ 4.28283           │ 4.5059            │ 4.1632            ║
╟────────────┼───────────────────┼───────────────────┼───────────────────┼───────────────────╢
║ variance   │ 0.0115654691666…  │ 6.6013884328999…  │ 11.813980208691…  │ 4.84239744        ║
╚════════════╧═══════════════════╧═══════════════════╧═══════════════════╧═══════════════════╝

Sorting by values (Defaults to ascending):

const dfd = require("danfojs")

let data = {"A": [-20, 30, 47.3, NaN],
             "B": [34, -4, 5, 6] ,
             "C": [20, 2, 3, 30] }


let df = new dfd.DataFrame(data)
df.sortValues("C", {inplace: true})
df.print()
╔════════════╤═══════════════════╤═══════════════════╤═══════════════════╗
║            │ A                 │ B                 │ C                 ║
╟────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 1          │ 30                │ -4                │ 2                 ║
╟────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 2          │ 47.3              │ 5                 │ 3                 ║
╟────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 0          │ -20               │ 34                │ 20                ║
╟────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 3          │ NaN               │ 6                 │ 30                ║
╚════════════╧═══════════════════╧═══════════════════╧═══════════════════╝

Selection

Getting

Selecting a single column, which yields a Series, equivalent to df.A:

const dfd = require("danfojs-node")


json_data = [{ A: 0.4612, B: 4.28283, C: -1.509, D: -1.1352 },
{ A: 0.5112, B: -0.22863, C: -3.39059, D: 1.1632 },
{ A: 0.6911, B: -0.82863, C: -1.5059, D: 2.1352 },
{ A: 0.4692, B: -1.28863, C: 4.5059, D: 4.1632 }]

df = new dfd.DataFrame(json_data)

df['A'].print()
//output
╔═══╤══════════════════════╗
║   │ A                    ║
╟───┼──────────────────────╢
║ 0 │ 0.4612               ║
╟───┼──────────────────────╢
║ 1 │ 0.5112               ║
╟───┼──────────────────────╢
║ 2 │ 0.6911               ║
╟───┼──────────────────────╢
║ 3 │ 0.4692               ║
╚═══╧══════════════════════╝

Selection by label

For getting a cross-section using a label:

const dfd = require("danfojs")

let data = { "Name": ["Apples", "Mango", "Banana", "Pear"] ,
            "Count": [21, 5, 30, 10] ,
           "Price": [200, 300, 40, 250] }

let df = new dfd.DataFrame(data, {index: ["a", "b", "c", "d"]})
df.print()

let sub_df = df.loc({rows: ["a", "c"]})
sub_df.print()
╔═══╤═══════════════════╤═══════════════════╤═══════════════════╗
║   │ Name              │ Count             │ Price             ║
╟───┼───────────────────┼───────────────────┼───────────────────╢
║ a │ Apples            │ 21                │ 200               ║
╟───┼───────────────────┼───────────────────┼───────────────────╢
║ b │ Mango             │ 5                 │ 300               ║
╟───┼───────────────────┼───────────────────┼───────────────────╢
║ c │ Banana            │ 30                │ 40                ║
╟───┼───────────────────┼───────────────────┼───────────────────╢
║ d │ Pear              │ 10                │ 250               ║
╚═══╧═══════════════════╧═══════════════════╧═══════════════════╝


 Shape: (2,3) 

╔═══╤═══════════════════╤═══════════════════╤═══════════════════╗
║   │ Name              │ Count             │ Price             ║
╟───┼───────────────────┼───────────────────┼───────────────────╢
║ a │ Apples            │ 21                │ 200               ║
╟───┼───────────────────┼───────────────────┼───────────────────╢
║ c │ Banana            │ 30                │ 40                ║
╚═══╧═══════════════════╧═══════════════════╧═══════════════════╝

Selecting on a multi-axis by label:

const dfd = require("danfojs-node")

let data = { "Name": ["Apples", "Mango", "Banana", "Pear"] ,
            "Count": [21, 5, 30, 10],
             "Price": [200, 300, 40, 250] }

let df = new dfd.DataFrame(data)
df.print()

let sub_df = df.loc({ rows: [0,1], columns: ["Name", "Price"] })
sub_df.print()
╔═══╤═══════════════════╤═══════════════════╤═══════════════════╗
║   │ Name              │ Count             │ Price             ║
╟───┼───────────────────┼───────────────────┼───────────────────╢
║ 0 │ Apples            │ 21                │ 200               ║
╟───┼───────────────────┼───────────────────┼───────────────────╢
║ 1 │ Mango             │ 5                 │ 300               ║
╟───┼───────────────────┼───────────────────┼───────────────────╢
║ 2 │ Banana            │ 30                │ 40                ║
╟───┼───────────────────┼───────────────────┼───────────────────╢
║ 3 │ Pear              │ 10                │ 250               ║
╚═══╧═══════════════════╧═══════════════════╧═══════════════════╝


 Shape: (2,2) 

╔═══╤═══════════════════╤═══════════════════╗
║   │ Name              │ Price             ║
╟───┼───────────────────┼───────────────────╢
║ 0 │ Apples            │ 200               ║
╟───┼───────────────────┼───────────────────╢
║ 1 │ Mango             │ 300               ║
╚═══╧═══════════════════╧═══════════════════╝

Showing label slicing:

const dfd = require("danfojs-node")

let data = { "Name": ["Apples", "Mango", "Banana", "Pear"] ,
            "Count": [21, 5, 30, 10],
             "Price": [200, 300, 40, 250] }

let df = new dfd.DataFrame(data)
df.print()

let sub_df = df.loc({ rows: ["0:2"], columns: ["Name", "Price"] })
sub_df.print()
//before slicing
╔═══╤═══════════════════╤═══════════════════╤═══════════════════╗
║   │ Name              │ Count             │ Price             ║
╟───┼───────────────────┼───────────────────┼───────────────────╢
║ 0 │ Apples            │ 21                │ 200               ║
╟───┼───────────────────┼───────────────────┼───────────────────╢
║ 1 │ Mango             │ 5                 │ 300               ║
╟───┼───────────────────┼───────────────────┼───────────────────╢
║ 2 │ Banana            │ 30                │ 40                ║
╟───┼───────────────────┼───────────────────┼───────────────────╢
║ 3 │ Pear              │ 10                │ 250               ║
╚═══╧═══════════════════╧═══════════════════╧═══════════════════╝

//after slicing
 

╔════════════╤═══════════════════╤═══════════════════╗
║            │ Name              │ Price             ║
╟────────────┼───────────────────┼───────────────────╢
║ 0          │ Apples            │ 200               ║
╟────────────┼───────────────────┼───────────────────╢
║ 1          │ Mango             │ 300               ║
╚════════════╧═══════════════════╧═══════════════════╝

Selection by position

Select via the position of the passed integers:

const dfd = require("danfojs-node")

let data = { "Name": ["Apples", "Mango", "Banana", "Pear"] ,
           "Count": [21, 5, 30, 10] ,
           "Price": [200, 300, 40, 250] }

let df = new dfd.DataFrame(data)

let sub_df = df.iloc({rows: [1,3]})
sub_df.print()
╔═══╤═══════════════════╤═══════════════════╤═══════════════════╗
║   │ Name              │ Count             │ Price             ║
╟───┼───────────────────┼───────────────────┼───────────────────╢
║ 1 │ Mango             │ 5                 │ 300               ║
╟───┼───────────────────┼───────────────────┼───────────────────╢
║ 3 │ Pear              │ 10                │ 250               ║
╚═══╧═══════════════════╧═══════════════════╧═══════════════════╝

By integer slices:

const dfd = require("danfojs-node")

let data = { "Name": ["Apples", "Mango", "Banana", "Pear"] ,
           "Count": [21, 5, 30, 10] ,
           "Price": [200, 300, 40, 250] }

let df = new dfd.DataFrame(data)

let sub_df = df.iloc({rows: ["1:3"]})
sub_df.print()
╔════════════╤═══════════════════╤═══════════════════╤═══════════════════╗
║            │ Name              │ Count             │ Price             ║
╟────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 1          │ Mango             │ 5                 │ 300               ║
╟────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 2          │ Banana            │ 30                │ 40                ║
╚════════════╧═══════════════════╧═══════════════════╧═══════════════════╝

By lists of integer position locations:

const dfd = require("danfojs-node")

let data = { "Name": ["Apples", "Mango", "Banana", "Pear"] ,
           "Count": [21, 5, 30, 10] ,
           "Price": [200, 300, 40, 250] }

let df = new dfd.DataFrame(data)

let sub_df = df.iloc({rows: [1,3], columns: [0,2]})
sub_df.print()
╔═══╤═══════════════════╤═══════════════════╗
║   │ Name              │ Price             ║
╟───┼───────────────────┼───────────────────╢
║ 1 │ Mango             │ 300               ║
╟───┼───────────────────┼───────────────────╢
║ 3 │ Pear              │ 250               ║
╚═══╧═══════════════════╧═══════════════════╝

For slicing rows explicitly:

const dfd = require("danfojs-node")

let data = { "Name": ["Apples", "Mango", "Banana", "Pear"] ,
           "Count": [21, 5, 30, 10] ,
           "Price": [200, 300, 40, 250] }

let df = new dfd.DataFrame(data)

let sub_df = df.iloc({rows: ["2:3"], columns: [":"]})
sub_df.print()
╔════════════╤═══════════════════╤═══════════════════╤═══════════════════╗
║            │ Name              │ Count             │ Price             ║
╟────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 2          │ Banana            │ 30                │ 40                ║
╚════════════╧═══════════════════╧═══════════════════╧═══════════════════╝

For slicing columns explicitly:

const dfd = require("danfojs-node")

let data = { "Name": ["Apples", "Mango", "Banana", "Pear"] ,
           "Count": [21, 5, 30, 10] ,
           "Price": [200, 300, 40, 250] }

let df = new dfd.DataFrame(data)

let sub_df = df.iloc({rows: [":"], columns: ["1:2"]})
sub_df.print()
╔════════════╤═══════════════════╗
║            │ Count             ║
╟────────────┼───────────────────╢
║ 0          │ 21                ║
╟────────────┼───────────────────╢
║ 1          │ 5                 ║
╟────────────┼───────────────────╢
║ 2          │ 30                ║
╟────────────┼───────────────────╢
║ 3          │ 10                ║
╚════════════╧═══════════════════╝

Selection with Boolean Mask

You can select subsections from a DataFrame by a booelan condition mask. E.g. In the following code, we select and return only rows where the column Count is greater than 10.

let data = {
    "Name": ["Apples", "Mango", "Banana", "Pear"],
    "Count": [21, 5, 30, 10],
    "Price": [200, 300, 40, 250]
}

let df = new dfd.DataFrame(data)

let sub_df = df.iloc({ rows: df["Count"].gt(10) })
sub_df.print()
//output
╔════════════╤═══════════════════╤═══════════════════╤═══════════════════╗
║            │ Name              │ Count             │ Price             ║
╟────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 0          │ Apples            │ 21                │ 200               ║
╟────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 2          │ Banana            │ 30                │ 40                ║
╚════════════╧═══════════════════╧═══════════════════╧═══════════════════╝

A Boolean mask for filtering also works for multiple conditions using and & or functions. E.g, In the following code, we select and return only rows where the column Count is greater than 10 and column Name is equal to Apples.

let sub_df = df.iloc({
    rows: df["Count"].gt(10).and(df["Name"].eq("Apples")),
    columns: [0]
})
sub_df.print()

//output
╔════════════╤═══════════════════╗
║            │ Name              ║
╟────────────┼───────────────────╢
║ 0          │ Apples            ║
╚════════════╧═══════════════════╝

Boolean Querying/Filtering

The best way to query data is to use a boolean mask just as we demonstrated above with iloc and loc. For example, in the following code, we use a condition parameter to query the DataFrame:

let data = {
    "A": ["Ng", "Yu", "Mo", "Ng"],
    "B": [34, 4, 5, 6],
    "C": [20, 20, 30, 40]
}
let df = new dfd.DataFrame(data)

let query_df = df.query(df["B"].gt(5))
query_df.print()
╔════════════╤═══════════════════╤═══════════════════╤═══════════════════╗
║            │ A                 │ B                 │ C                 ║
╟────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 0          │ Ng                │ 34                │ 20                ║
╟────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 3          │ Ng                │ 6                 │ 40                ║
╚════════════╧═══════════════════╧═══════════════════╧═══════════════════╝

Querying by a boolean condition is supported from v0.3.0 and above. It also supports condition chaining as long as the final boolean mask is the same lenght as the DataFrame rows. For example in the following code, we use multiple chaining conditions:

let data = {
    "A": ["Ng", "Yu", "Mo", "Ng"],
    "B": [34, 4, 5, 6],
    "C": [20, 20, 30, 40]
}
let query_df = df.query( df["B"].gt(5).and(df["C"].lt(0)))
query_df.print() //after query

//output
╔════════════╤═══════════════════╤═══════════════════╤═══════════════════╗
║            │ A                 │ B                 │ C                 ║
╟────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 0          │ Ng                │ 34                │ 20                ║
╚════════════╧═══════════════════╧═══════════════════╧═══════════════════╝

Adding a new column

Setting a new column automatically aligns the data by the indexes.

const dfd = require("danfojs-node")

let data = { "A": [30, 1, 2, 3] ,
             "B": [34, 4, 5, 6] ,
             "C": [20, 20, 30, 40] }

let df = new dfd.DataFrame(data)
df.print()

let new_col = [1, 2, 3, 4]
df.addColumn("D", new_col, { inplace: true }); //happens inplace

df.print()
//before adding column
╔═══╤═══════════════════╤═══════════════════╤═══════════════════╗
║   │ A                 │ B                 │ C                 ║
╟───┼───────────────────┼───────────────────┼───────────────────╢
║ 0 │ 30                │ 34                │ 20                ║
╟───┼───────────────────┼───────────────────┼───────────────────╢
║ 1 │ 1                 │ 4                 │ 20                ║
╟───┼───────────────────┼───────────────────┼───────────────────╢
║ 2 │ 2                 │ 5                 │ 30                ║
╟───┼───────────────────┼───────────────────┼───────────────────╢
║ 3 │ 3                 │ 6                 │ 40                ║
╚═══╧═══════════════════╧═══════════════════╧═══════════════════╝

//after adding column
 Shape: (4,3) 

╔════════════╤═══════════════════╤═══════════════════╤═══════════════════╤═══════════════════╗
║            │ A                 │ B                 │ C                 │ D                 ║
╟────────────┼───────────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 0          │ 1                 │ 2                 │ 3                 │ 25                ║
╟────────────┼───────────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 1          │ 4                 │ 5                 │ 6                 │ 35                ║
╟────────────┼───────────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 2          │ 20                │ 30                │ 40                │ 45                ║
╟────────────┼───────────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 3          │ 39                │ 89                │ 78                │ 55                ║
╚════════════╧═══════════════════╧═══════════════════╧═══════════════════╧═══════════════════╝

Missing data

NaN, null, and undefined represent missing data in Danfo.js. These values can be dropped or filled using some functions available in Danfo.js.

To drop any columns that have missing data:

const dfd = require("danfojs-node")

let data = [[1, 2, 3], [NaN, 5, 6], [NaN, 30, 40], [39, 20, 78]]
let cols = ["A", "B", "C"]
let df = new dfd.DataFrame(data, { columns: cols })

df.print()

let df_drop = df.dropNa({ axis: 0 })
df_drop.print()
//Before dropping
╔════════════╤═══════════════════╤═══════════════════╤═══════════════════╗
║            │ A                 │ B                 │ C                 ║
╟────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 0          │ 1                 │ 2                 │ 3                 ║
╟────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 1          │ NaN               │ 5                 │ 6                 ║
╟────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 2          │ NaN               │ 30                │ 40                ║
╟────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 3          │ 39                │ 20                │ 78                ║
╚════════════╧═══════════════════╧═══════════════════╧═══════════════════╝


//after dropping
╔════════════╤═══════════════════╤═══════════════════╗
║            │ B                 │ C                 ║
╟────────────┼───────────────────┼───────────────────╢
║ 0          │ 2                 │ 3                 ║
╟────────────┼───────────────────┼───────────────────╢
║ 1          │ 5                 │ 6                 ║
╟────────────┼───────────────────┼───────────────────╢
║ 2          │ 30                │ 40                ║
╟────────────┼───────────────────┼───────────────────╢
║ 3          │ 20                │ 78                ║
╚════════════╧═══════════════════╧═══════════════════╝

To drop row(s) with have missing data, set the axis to 1:

const dfd = require("danfojs-node")

let data = [[1, 2, 3], [NaN, 5, 6], [20, 30, 40], [39, 34, 78]]
let cols = ["A", "B", "C"]
let df = new dfd.DataFrame(data, { columns: cols })

df.print()

let df_drop = df.dropNa({ axis: 1 })
df_drop.print()
//Before dropping
╔════════════╤═══════════════════╤═══════════════════╤═══════════════════╗
║            │ A                 │ B                 │ C                 ║
╟────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 0          │ 1                 │ 2                 │ 3                 ║
╟────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 1          │ NaN               │ 5                 │ 6                 ║
╟────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 2          │ 20                │ 30               │ 40                ║
╟────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 3          │ 39                │ 34                │ 78                ║
╚════════════╧═══════════════════╧═══════════════════╧═══════════════════╝


//after dropping

╔════════════╤═══════════════════╤═══════════════════╤═══════════════════╗
║            │ A                 │ B                 │ C                 ║
╟────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 0          │ 1                 │ 2                 │ 3                 ║
╟────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 3          │ 39                │ 20                │ 78                ║
╚════════════╧═══════════════════╧═══════════════════╧═══════════════════╝

Filling missing data:

const dfd = require("danfojs-node")


let data = {
    "Name": ["Apples", "Mango", "Banana", NaN],
    "Count": [NaN, 5, NaN, 10],
    "Price": [200, 300, 40, 250]
  }

let df = new dfd.DataFrame(data)
let df_filled = df.fillNa("Apples")

df_filled.print()
╔═══╤═══════════════════╤═══════════════════╤═══════════════════╗
║   │ Name              │ Count             │ Price             ║
╟───┼───────────────────┼───────────────────┼───────────────────╢
║ 0 │ Apples            │ Apples            │ 200               ║
╟───┼───────────────────┼───────────────────┼───────────────────╢
║ 1 │ Mango             │ 5                 │ 300               ║
╟───┼───────────────────┼───────────────────┼───────────────────╢
║ 2 │ Banana            │ Apples            │ 40                ║
╟───┼───────────────────┼───────────────────┼───────────────────╢
║ 3 │ Apples            │ 10                │ 250               ║
╚═══╧═══════════════════╧═══════════════════╧═══════════════════╝

Filling missing values in specific columns with specific values:

const dfd = require("danfojs-node")

let data = {
    "Name": ["Apples", "Mango", "Banana", NaN],
    "Count": [NaN, 5, NaN, 10],
    "Price": [200, 300, 40, 250]
}

let df = new dfd.DataFrame(data)
df.print()

let df_filled = df.fillNa(["Apples", df["Count"].mean()], { columns: ["Name", "Count"] })
df_filled.print()
╔═══╤═══════════════════╤═══════════════════╤═══════════════════╗
║   │ Name              │ Count             │ Price             ║
╟───┼───────────────────┼───────────────────┼───────────────────╢
║ 0 │ Apples            │ 7.5               │ 200               ║
╟───┼───────────────────┼───────────────────┼───────────────────╢
║ 1 │ Mango             │ 5                 │ 300               ║
╟───┼───────────────────┼───────────────────┼───────────────────╢
║ 2 │ Banana            │ 7.5               │ 40                ║
╟───┼───────────────────┼───────────────────┼───────────────────╢
║ 3 │ Apples            │ 10                │ 250               ║
╚═══╧═══════════════════╧═══════════════════╧═══════════════════╝

To get the boolean mask where values are nan.

const dfd = require("danfojs-node")

let data = {"Name":["Apples", "Mango", "Banana", undefined],
            "Count": [NaN, 5, NaN, 10], 
            "Price": [200, 300, 40, 250]}

let df = new dfd.DataFrame(data)
df.isNa().print()
╔═══╤═══════════════════╤═══════════════════╤═══════════════════╗
║   │ Name              │ Count             │ Price             ║
╟───┼───────────────────┼───────────────────┼───────────────────╢
║ 0 │ false             │ true              │ false             ║
╟───┼───────────────────┼───────────────────┼───────────────────╢
║ 1 │ false             │ false             │ false             ║
╟───┼───────────────────┼───────────────────┼───────────────────╢
║ 2 │ false             │ true              │ false             ║
╟───┼───────────────────┼───────────────────┼───────────────────╢
║ 3 │ true              │ false             │ false             ║
╚═══╧═══════════════════╧═══════════════════╧═══════════════════╝

Operations

Stats

Operations, in general, exclude missing data.

Performing a descriptive statistic:

const dfd = require("danfojs-node")

data = [[11, 20, 3], [1, 15, 6], [2, 30, 40], [2, 89, 78]]
cols = ["A", "B", "C"]


let df = new dfd.DataFrame(data, { columns: cols })
df.print()
df.mean().print() //defaults to column (1) axis
╔═══╤═══════════════════╤═══════════════════╤═══════════════════╗
║   │ 0                 │ 1                 │ 2                 ║
╟───┼───────────────────┼───────────────────┼───────────────────╢
║ 0 │ 11                │ 20                │ 3                 ║
╟───┼───────────────────┼───────────────────┼───────────────────╢
║ 1 │ 1                 │ 15                │ 6                 ║
╟───┼───────────────────┼───────────────────┼───────────────────╢
║ 2 │ 2                 │ 30                │ 40                ║
╟───┼───────────────────┼───────────────────┼───────────────────╢
║ 3 │ 2                 │ 89                │ 78                ║
╚═══╧═══════════════════╧═══════════════════╧═══════════════════╝

╔═══╤════════════════════╗
║ 0 │ 11.333333333333334 ║
╟───┼────────────────────╢
║ 1 │ 7.333333333333333  ║
╟───┼────────────────────╢
║ 2 │ 24                 ║
╟───┼────────────────────╢
║ 3 │ 56.333333333333336 ║
╚═══╧════════════════════╝

Same operation on the row axis:

const dfd = require("danfojs-node")

data = [[11, 20, 3], [1, 15, 6], [2, 30, 40], [2, 89, 78]]
cols = ["A", "B", "C"]


let df = new dfd.DataFrame(data)
df.print()
df.mean({ axis: 0 }).print() //row axis=0, column=1
╔═══╤═══════════════════╤═══════════════════╤═══════════════════╗
║   │ 0                 │ 1                 │ 2                 ║
╟───┼───────────────────┼───────────────────┼───────────────────╢
║ 0 │ 11                │ 20                │ 3                 ║
╟───┼───────────────────┼───────────────────┼───────────────────╢
║ 1 │ 1                 │ 15                │ 6                 ║
╟───┼───────────────────┼───────────────────┼───────────────────╢
║ 2 │ 2                 │ 30                │ 40                ║
╟───┼───────────────────┼───────────────────┼───────────────────╢
║ 3 │ 2                 │ 89                │ 78                ║
╚═══╧═══════════════════╧═══════════════════╧═══════════════════╝

╔═══╤═══════╗
║ A │ 4     ║
╟───┼───────╢
║ B │ 38.5  ║
╟───┼───────╢
║ C │ 31.75 ║
╚═══╧═══════╝

Operations on objects with different dimensionality and need alignment. Danfo automatically broadcasts along the specified dimension.

const dfd = require("danfojs-node")


let data = { "Col1": [1, 4, 5, 1], "Col2": [3, 2, 0, 4] }
let df = new dfd.DataFrame(data)
let sf = new dfd.Series([4, 5])

let df_new = df.sub(sf, { axis: 1 })

df_new.print()
╔═══╤═══════════════════╤═══════════════════╗
║   │ Col1              │ Col2              ║
╟───┼───────────────────┼───────────────────╢
║ 0 │ -3                │ -2                ║
╟───┼───────────────────┼───────────────────╢
║ 1 │ 0                 │ -3                ║
╟───┼───────────────────┼───────────────────╢
║ 2 │ 1                 │ -5                ║
╟───┼───────────────────┼───────────────────╢
║ 3 │ -3                │ -1                ║
╚═══╧═══════════════════╧═══════════════════╝

Apply

Applying functions to the data along a specified axis. If axis = 1 (default), then the specified function (callable) will be called with each row data, and vice versa:

const dfd = require("danfojs")

let data = [[1, 2, 3], [4, 5, 6], [20, 30, 40], [39, 89, 78]]
let cols = ["A", "B", "C"]
let df = new dfd.DataFrame(data, { columns: cols })

function sum_vals(col) {
    return col.reduce((a, b) => a + b, 0);
}

let df_new = df.apply(sum_vals, { axis: 1 })
df_new.print()
//before applying
╔═══╤═══════════════════╤═══════════════════╤═══════════════════╗
║   │ A                 │ B                 │ C                 ║
╟───┼───────────────────┼───────────────────┼───────────────────╢
║ 0 │ 1                 │ 2                 │ 3                 ║
╟───┼───────────────────┼───────────────────┼───────────────────╢
║ 1 │ 4                 │ 5                 │ 6                 ║
╟───┼───────────────────┼───────────────────┼───────────────────╢
║ 2 │ 20                │ 30                │ 40                ║
╟───┼───────────────────┼───────────────────┼───────────────────╢
║ 3 │ 39                │ 89                │ 78                ║
╚═══╧═══════════════════╧═══════════════════╧═══════════════════╝


//after applying

╔═══╤═════╗
║ 0 │ 6   ║
╟───┼─────╢
║ 1 │ 15  ║
╟───┼─────╢
║ 2 │ 90  ║
╟───┼─────╢
║ 3 │ 206 ║
╚═══╧═════╝

Applying Element wise operations to the data:

You can use the applyMap function if you need to apply a function to each element in the DataFrame. applyMap works element-wise.

const dfd = require("danfojs-node")

let data = [[1, 2, 3], [4, 5, 6], [20, 30, 40], [39, 89, 78]]
let cols = ["A", "B", "C"]
let df = new dfd.DataFrame(data, { columns: cols })

function sum_vals(x) {
    return x + 10
}

let df_new = df.applyMap(sum_vals)
df_new.print()
//before applying
╔═══╤═══════════════════╤═══════════════════╤═══════════════════╗
║   │ A                 │ B                 │ C                 ║
╟───┼───────────────────┼───────────────────┼───────────────────╢
║ 0 │ 1                 │ 2                 │ 3                 ║
╟───┼───────────────────┼───────────────────┼───────────────────╢
║ 1 │ 4                 │ 5                 │ 6                 ║
╟───┼───────────────────┼───────────────────┼───────────────────╢
║ 2 │ 20                │ 30                │ 40                ║
╟───┼───────────────────┼───────────────────┼───────────────────╢
║ 3 │ 39                │ 89                │ 78                ║
╚═══╧═══════════════════╧═══════════════════╧═══════════════════╝


 //after applyMap

╔════════════╤═══════════════════╤═══════════════════╤═══════════════════╗
║            │ A                 │ B                 │ C                 ║
╟────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 0          │ 11                │ 12                │ 13                ║
╟────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 1          │ 14                │ 15                │ 16                ║
╟────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 2          │ 30                │ 40                │ 50                ║
╟────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 3          │ 49                │ 99                │ 88                ║
╚════════════╧═══════════════════╧═══════════════════╧═══════════════════╝

String Methods

Series is equipped with a set of string processing methods in the str attribute that make it easy to operate on each element of the array, as in the code snippet below. Note that pattern-matching in str generally uses JavaScript regular expressions by default (and in some cases always uses them).

const dfd = require("danfojs-node")

let s = new dfd.Series(['A', 'B', 'C', 'Aaba', 'Baca', 'CABA', 'dog', 'cat'])
let lower_s = s.str.toLowerCase()
lower_s.print()
╔═══╤══════════════════════╗
║   │ 0                    ║
╟───┼──────────────────────╢
║ 0 │ a                    ║
╟───┼──────────────────────╢
║ 1 │ b                    ║
╟───┼──────────────────────╢
║ 2 │ c                    ║
╟───┼──────────────────────╢
║ 3 │ aaba                 ║
╟───┼──────────────────────╢
║ 4 │ baca                 ║
╟───┼──────────────────────╢
║ 5 │ caba                 ║
╟───┼──────────────────────╢
║ 6 │ dog                  ║
╟───┼──────────────────────╢
║ 7 │ cat                  ║
╚═══╧══════════════════════╝

See more string accessors here

Merge

Concat

danfo provides various methods for easily combining together Series and DataFrame objects with various kinds of set logic for the indexes and relational algebra functionality in the case of join / merge-type operations.

Concatenating DataFrame together with concat():

const dfd = require("danfojs-node")


let data = [['K0', 'k0', 'A0', 'B0'], ['k0', 'K1', 'A1', 'B1'],
['K1', 'K0', 'A2', 'B2'], ['K2', 'K2', 'A3', 'B3']]

let data2 = [['K0', 'k0', 'C0', 'D0'], ['K1', 'K0', 'C1', 'D1'],
['K1', 'K0', 'C2', 'D2'], ['K2', 'K0', 'C3', 'D3']]

let colum1 = ['Key1', 'Key2', 'A', 'B']
let colum2 = ['Key1', 'Key2', 'A', 'D']

let df1 = new dfd.DataFrame(data, { columns: colum1 })
let df2 = new dfd.DataFrame(data2, { columns: colum2 })


let com_df = dfd.concat({ dfList: [df1, df2], axis: 1 }) //along column axis
com_df.print()
╔════════════╤═══════════════════╤═══════════════════╤═══════════════════╤═══════════════════╤═══════════════════╤═══════════════════╤═══════════════════╤═══════════════════╗
║            │ Key1              │ Key2              │ A                 │ B                 │ Key11             │ Key21             │ A1                │ D                 ║
╟────────────┼───────────────────┼───────────────────┼───────────────────┼───────────────────┼───────────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 0          │ K0                │ k0                │ A0                │ B0                │ K0                │ k0                │ C0                │ D0                ║
╟────────────┼───────────────────┼───────────────────┼───────────────────┼───────────────────┼───────────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 1          │ k0                │ K1                │ A1                │ B1                │ K1                │ K0                │ C1                │ D1                ║
╟────────────┼───────────────────┼───────────────────┼───────────────────┼───────────────────┼───────────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 2          │ K1                │ K0                │ A2                │ B2                │ K1                │ K0                │ C2                │ D2                ║
╟────────────┼───────────────────┼───────────────────┼───────────────────┼───────────────────┼───────────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 3          │ K2                │ K2                │ A3                │ B3                │ K2                │ K0                │ C3                │ D3                ║
╚════════════╧═══════════════════╧═══════════════════╧═══════════════════╧═══════════════════╧═══════════════════╧═══════════════════╧═══════════════════╧═══════════════════╝

Concatenate along row axis (0).

const dfd = require("danfojs-node")


let data = [['K0', 'k0', 'A0', 'B0'], ['k0', 'K1', 'A1', 'B1'],
['K1', 'K0', 'A2', 'B2'], ['K2', 'K2', 'A3', 'B3']]

let data2 = [['K0', 'k0', 'C0', 'D0'], ['K1', 'K0', 'C1', 'D1'],
['K1', 'K0', 'C2', 'D2'], ['K2', 'K0', 'C3', 'D3']]

let colum1 = ['Key1', 'Key2', 'A', 'B']
let colum2 = ['Key1', 'Key2', 'A', 'D']

let df1 = new dfd.DataFrame(data, { columns: colum1 })
let df2 = new dfd.DataFrame(data2, { columns: colum2 })


let com_df = dfd.concat({ dfList: [df1, df2], axis: 0 }) //along row axis
com_df.print()
╔═══╤═══════════════════╤═══════════════════╤═══════════════════╤═══════════════════╤═══════════════════╗
║   │ Key1              │ Key2              │ A                 │ B                 │ D                 ║
╟───┼───────────────────┼───────────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 0 │ K0                │ k0                │ A0                │ B0                │ NaN               ║
╟───┼───────────────────┼───────────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 1 │ k0                │ K1                │ A1                │ B1                │ NaN               ║
╟───┼───────────────────┼───────────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 2 │ K1                │ K0                │ A2                │ B2                │ NaN               ║
╟───┼───────────────────┼───────────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 3 │ K2                │ K2                │ A3                │ B3                │ NaN               ║
╟───┼───────────────────┼───────────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 4 │ K0                │ k0                │ C0                │ NaN               │ D0                ║
╟───┼───────────────────┼───────────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 5 │ K1                │ K0                │ C1                │ NaN               │ D1                ║
╟───┼───────────────────┼───────────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 6 │ K1                │ K0                │ C2                │ NaN               │ D2                ║
╟───┼───────────────────┼───────────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 7 │ K2                │ K0                │ C3                │ NaN               │ D3                ║
╚═══╧═══════════════════╧═══════════════════╧═══════════════════╧═══════════════════╧═══════════════════╝

Join

SQL style merges. See the Pandas Database style joining section for more info.

const dfd = require("danfojs-node")

let data = [['K0', 'k0', 'A0', 'B0'], ['k0', 'K1', 'A1', 'B1'],
            ['K1', 'K0', 'A2', 'B2'], ['K2', 'K2', 'A3', 'B3']]

let data2 = [['K0', 'k0', 'C0', 'D0'], ['K1', 'K0', 'C1', 'D1'],
            ['K1', 'K0', 'C2', 'D2'], ['K2', 'K0', 'C3', 'D3']]

let colum1 = ['Key1', 'Key2', 'A', 'B']
let colum2 = ['Key1', 'Key2', 'A', 'D']

let df1 = new dfd.DataFrame(data, { columns: colum1 })
let df2 = new dfd.DataFrame(data2, { columns: colum2 })
df1.print()
df2.print()

let merge_df = dfd.merge({ "left": df1, "right": df2, "on": ["Key1"], how: "inner" })
merge_df.print()
 //first DataFrame
╔═══╤═══════════════════╤═══════════════════╤═══════════════════╤═══════════════════╗
║   │ Key1              │ Key2              │ A                 │ B                 ║
╟───┼───────────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 0 │ K0                │ k0                │ A0                │ B0                ║
╟───┼───────────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 1 │ k0                │ K1                │ A1                │ B1                ║
╟───┼───────────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 2 │ K1                │ K0                │ A2                │ B2                ║
╟───┼───────────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 3 │ K2                │ K2                │ A3                │ B3                ║
╚═══╧═══════════════════╧═══════════════════╧═══════════════════╧═══════════════════╝


 //Second DataFrame

╔═══╤═══════════════════╤═══════════════════╤═══════════════════╤═══════════════════╗
║   │ Key1              │ Key2              │ A                 │ D                 ║
╟───┼───────────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 0 │ K0                │ k0                │ C0                │ D0                ║
╟───┼───────────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 1 │ K1                │ K0                │ C1                │ D1                ║
╟───┼───────────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 2 │ K1                │ K0                │ C2                │ D2                ║
╟───┼───────────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 3 │ K2                │ K0                │ C3                │ D3                ║
╚═══╧═══════════════════╧═══════════════════╧═══════════════════╧═══════════════════╝


 //After inner join on column 'Key1'

╔═══╤═══════════════════╤═══════════════════╤═══════════════════╤═══════════════════╤═══════════════════╤═══════════════════╤═══════════════════╗
║   │ Key1              │ Key2              │ A                 │ B                 │ Key2_1            │ A_1               │ D                 ║
╟───┼───────────────────┼───────────────────┼───────────────────┼───────────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 0 │ K0                │ k0                │ A0                │ B0                │ k0                │ C0                │ D0                ║
╟───┼───────────────────┼───────────────────┼───────────────────┼───────────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 1 │ K1                │ K0                │ A2                │ B2                │ K0                │ C1                │ D1                ║
╟───┼───────────────────┼───────────────────┼───────────────────┼───────────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 2 │ K1                │ K0                │ A2                │ B2                │ K0                │ C2                │ D2                ║
╟───┼───────────────────┼───────────────────┼───────────────────┼───────────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 3 │ K2                │ K2                │ A3                │ B3                │ K0                │ C3                │ D3                ║
╚═══╧═══════════════════╧═══════════════════╧═══════════════════╧═══════════════════╧═══════════════════╧═══════════════════╧═══════════════════╝

See the merge section for more examples

Grouping

By “group by” we are referring to a process involving one or more of the following steps:

  • Splitting the data into groups based on some criteria

  • Applying a function to each group independently

  • Combining the results into a data structure

See the Grouping section.

const dfd = require("danfojs-node")

let data ={'A': ['foo', 'bar', 'foo', 'bar',
                'foo', 'bar', 'foo', 'foo'],
           'B': ['one', 'one', 'two', 'three',
                'two', 'two', 'one', 'three'],
           'C': [1,3,2,4,5,2,6,7],
           'D': [3,2,4,1,5,6,7,8]
        }

let df = new dfd.DataFrame(data)


let grp = df.groupby(["A"])

grp.get_groups(["foo"]).print()

grp.get_groups(["bar"]).print()
╔═══╤═══════════════════╤═══════════════════╤═══════════════════╤═══════════════════╗
║   │ A                 │ B                 │ C                 │ D                 ║
╟───┼───────────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 0 │ foo               │ one               │ 1                 │ 3                 ║
╟───┼───────────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 1 │ foo               │ two               │ 2                 │ 4                 ║
╟───┼───────────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 2 │ foo               │ two               │ 5                 │ 5                 ║
╟───┼───────────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 3 │ foo               │ one               │ 6                 │ 7                 ║
╟───┼───────────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 4 │ foo               │ three             │ 7                 │ 8                 ║
╚═══╧═══════════════════╧═══════════════════╧═══════════════════╧═══════════════════╝


 Shape: (3,4) 

╔═══╤═══════════════════╤═══════════════════╤═══════════════════╤═══════════════════╗
║   │ A                 │ B                 │ C                 │ D                 ║
╟───┼───────────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 0 │ bar               │ one               │ 3                 │ 2                 ║
╟───┼───────────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 1 │ bar               │ three             │ 4                 │ 1                 ║
╟───┼───────────────────┼───────────────────┼───────────────────┼───────────────────╢
║ 2 │ bar               │ two               │ 2                 │ 6                 ║
╚═══╧═══════════════════╧═══════════════════╧═══════════════════╧═══════════════════╝

Grouping and then applying thesum() function to the resulting groups.

const dfd = require("danfojs-node")

let data = {
  A: ["foo", "bar", "foo", "bar", "foo", "bar", "foo", "foo"],
  B: ["one", "one", "two", "three", "two", "two", "one", "three"],
  C: [1, 3, 2, 4, 5, 2, 6, 7],
  D: [3, 2, 4, 1, 5, 6, 7, 8],
};

let df = new dfd.DataFrame(data);

let grp = df.groupby(["A"]);
grp.col(["C"]).sum().print();
╔═══╤═══════════════════╤═══════════════════╗
║   │ A                 │ C_sum             ║
╟───┼───────────────────┼───────────────────╢
║ 0 │ foo               │ 21                ║
╟───┼───────────────────┼───────────────────╢
║ 1 │ bar               │ 9                 ║
╚═══╧═══════════════════╧═══════════════════╝

Grouping by multiple columns forms a hierarchical index, and again we can apply thesum() function.

const dfd = require("danfojs-node")

let data ={'A': ['foo', 'bar', 'foo', 'bar',
                'foo', 'bar', 'foo', 'foo'],
           'B': ['one', 'one', 'two', 'three',
                'two', 'two', 'one', 'three'],
           'C': [1,3,2,4,5,2,6,7],
           'D': [3,2,4,1,5,6,7,8]
        }

let df = new dfd.DataFrame(data)


let grp = df.groupby(["A","B"])
grp.col(["C"]).sum().print()
╔═══╤═══════════════════╤═══════════════════╤═══════════════════╗
║   │ A                 │ B                 │ C_sum             ║
╟───┼───────────────────┼───────────────────┼───────────────────╢
║ 0 │ foo               │ one               │ 7                 ║
╟───┼───────────────────┼───────────────────┼───────────────────╢
║ 1 │ foo               │ two               │ 7                 ║
╟───┼───────────────────┼───────────────────┼───────────────────╢
║ 2 │ foo               │ three             │ 7                 ║
╟───┼───────────────────┼───────────────────┼───────────────────╢
║ 3 │ bar               │ one               │ 3                 ║
╟───┼───────────────────┼───────────────────┼───────────────────╢
║ 4 │ bar               │ two               │ 2                 ║
╟───┼───────────────────┼───────────────────┼───────────────────╢
║ 5 │ bar               │ three             │ 4                 ║
╚═══╧═══════════════════╧═══════════════════╧═══════════════════╝

Time series

danfo provides a simple but powerful, and efficient functionality for working with DateTime data. See the dt Accessors section.

const dfd = require("danfojs-node")

let data = new dfd.dateRange({"start":'2018-01', freq:'M', period:3})
let sf = new dfd.Series(data)
//print series
sf.print()
//print month names
sf.dt.monthName().print()
╔═══╤══════════════════════╗
║   │ 0                    ║
╟───┼──────────────────────╢
║ 0 │ 1/1/2018, 1:00:00 AM ║
╟───┼──────────────────────╢
║ 1 │ 2/1/2018, 1:00:00 AM ║
╟───┼──────────────────────╢
║ 2 │ 3/1/2018, 1:00:00 AM ║
╚═══╧══════════════════════╝

╔═══╤══════════╗
║ 0 │ January  ║
╟───┼──────────╢
║ 1 │ February ║
╟───┼──────────╢
║ 2 │ March    ║
╚═══╧══════════╝

More Examples:

const dfd = require("danfojs-node")

let data = new dfd.dateRange({"start":'2018-01', freq:'M', period:3})
let sf = new dfd.Series(data)
//print series
sf.print()
//print week day names
sf.dt.dayOfWeekName().print()
╔═══╤══════════════════════╗
║   │ 0                    ║
╟───┼──────────────────────╢
║ 0 │ 1/1/2018, 1:00:00 AM ║
╟───┼──────────────────────╢
║ 1 │ 2/1/2018, 1:00:00 AM ║
╟───┼──────────────────────╢
║ 2 │ 3/1/2018, 1:00:00 AM ║
╚═══╧══════════════════════╝

╔═══╤══════════╗
║ 0 │ Monday   ║
╟───┼──────────╢
║ 1 │ Thursday ║
╟───┼──────────╢
║ 2 │ Thursday ║
╚═══╧══════════╝

Plotting

See the Plotting docs.

We currently support Plotly.js for plotting. In the future, we plan other JS plotting libraries like Vega, D3.

Using the plot API, you can make interactive plots from DataFrame and Series. Plotting only works in the browser/client-side version of Danfo.js, and requires an HTML div to display plots.

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
     <script src="https://cdn.jsdelivr.net/npm/[email protected]/lib/bundle.min.js"></script>
     <title>Document</title>
</head>

<body>

    <div id="plot_div"></div>
    <script>

          dfd.readCSV(
          "https://raw.githubusercontent.com/plotly/datasets/master/finance-charts-apple.csv"
        )
        .then((df) => {
          let layout = {
            title: "A financial charts",
            xaxis: {
              title: "Date",
            },
            yaxis: {
              title: "Count",
            },
          };

          let config = {
            columns: ["AAPL.Open", "AAPL.High"],
          };

          let new_df = df.setIndex({ column: "Date" });
          new_df.plot("plot_div").line({ config, layout });
        })
        .catch((err) => {
          console.log(err);
        });

    </script>
</body>

</html>

On a DataFrame, the plot()method exposes various plot types. And by default, all columns are plotted unless specified otherwise.

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <script src="https://cdn.plot.ly/plotly-1.2.0.min.js"></script> 
     <script src="https://cdn.jsdelivr.net/npm/[email protected]/lib/bundle.min.js"></script>
    <title>Document</title>
</head>

<body>

    <div id="plot_div"></div>
    <script>

        df = new dfd.DataFrame({'pig': [20, 18, 489, 675, 1776],
                               'horse': [4, 25, 281, 600, 1900]}, {index: [1990, 1997, 2003, 2009, 2014]})
        df.plot("plot_div").line()

    </script>
</body>

</html>

Getting data in/out

CSV

Writing to a CSV file.

Convert any DataFrame to csv format.

In NodeJs, if a file path is specified, then the CSV is saved to the path, else it is returned as a string.

In the browser, you can automatically download the file as CSV by setting the download paramater to true.

const dfd = require("danfojs-node")
let data = {
    "Abs": [20.2, 30, 47.3],
    "Count": [34, 4, 5],
    "country code": ["NG", "FR", "GH"]
}


let df = new dfd.DataFrame(data)

const csv = dfd.toCSV(df)
console.log(csv);
//output
Abs,Count,country code
20.2,34,NG
30,4,FR
47.3,5,GH


dfd.toCSV(df, {filePath: "testOut.csv" }) //writes to file system in Nodejs


dfd.toCSV(df, {fileName: "testOut", download: true }) //downloads the file in browser version
Abs,Count,country code
20.2,34,NG
30,4,FR
47.3,5,GH

Reading from a CSV file.

The readCSV method can read CSV files from local disk, or over the internet. Both full and relative paths are supported. For example, to read a CSV file at the path /home/Desktop/titanic.csv, you can do the following:

const dfd = require("danfojs")

dfd.readCSV("/home/Desktop/titanic.csv")
  .then(df => {

   //do something with the CSV file
   df.head().print()

  }).catch(err=>{
     console.log(err);
  })

JSON

Writing to JSON format

const dfd = require("danfojs-node")

let data = {
          "Abs": [20.2, 30, 47.3],
          "Count": [34, 4, 5],
          "country code": ["NG", "FR", "GH"]
        }


let df = new dfd.DataFrame(data)

const json = dfd.toJSON(df)
console.log(json);
//output
[
  { Abs: 20.2, Count: 34, 'country code': 'NG' },
  { Abs: 30, Count: 4, 'country code': 'FR' },
  { Abs: 47.3, Count: 5, 'country code': 'GH' }
]


const json = dfd.toJSON(df, {format: "row"})
console.log(json);
//output
{
  Abs: [ 20.2, 30, 47.3 ],
  Count: [ 34, 4, 5 ],
  'country code': [ 'NG', 'FR', 'GH' ]
}

Last updated