dataframe-0.1.0.0: app/Main.hs
{-# LANGUAGE ExtendedDefaultRules #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TupleSections #-}
module Main where
import qualified Data.DataFrame as D
import Data.DataFrame (dimensions, (|>))
import Data.List (delete)
import Data.Maybe (fromMaybe, isJust, isNothing)
import qualified Data.Text as T
import qualified Data.Vector as V
import qualified Data.Vector.Generic as VG
import qualified Data.Vector.Unboxed as VU
-- Numbers default to int and double, and strings to text
default (Int, T.Text, Double)
-- Example usage of DataFrame library
main :: IO ()
main = do
putStrLn "Housing"
housing
putStrLn $ replicate 100 '-'
putStrLn "Chipotle Data"
chipotle
putStrLn $ replicate 100 '-'
putStrLn "One Billion Row Challenge"
oneBillingRowChallenge
putStrLn $ replicate 100 '-'
putStrLn "Covid Data"
covid
putStrLn $ replicate 100 '-'
mean :: (Fractional a, VG.Vector v a) => v a -> a
mean xs = VG.sum xs / fromIntegral (VG.length xs)
oneBillingRowChallenge :: IO ()
oneBillingRowChallenge = do
parsed <- D.readSeparated ';' D.defaultOptions "./data/measurements.txt"
print $
parsed
|> D.groupBy ["City"]
|> D.reduceBy (\v -> (VG.minimum v, mean @Double v, VG.maximum v)) "Measurement"
|> D.sortBy D.Ascending ["City"]
housing :: IO ()
housing = do
parsed <- D.readCsv "./data/housing.csv"
print $ D.columnInfo parsed
-- Sample.
print $ D.take 5 parsed
D.plotHistograms D.PlotAll D.VerticalHistogram parsed
covid :: IO ()
covid = do
rawFrame <- D.readCsv "./data/effects-of-covid-19-on-trade-at-15-december-2021-provisional.csv"
print $ dimensions rawFrame
print $ D.take 10 rawFrame
D.plotHistograms D.PlotAll D.VerticalHistogram rawFrame
-- value of all exports from 2015
print $
rawFrame
|> D.filter "Direction" (== "Exports")
|> D.select ["Direction", "Year", "Country", "Value"]
|> D.groupBy ["Direction", "Year", "Country"]
|> D.reduceByAgg D.Sum "Value"
chipotle :: IO ()
chipotle = do
rawFrame <- D.readTsv "./data/chipotle.tsv"
print $ D.dimensions rawFrame
-- -- Sampling the dataframe
print $ D.take 5 rawFrame
-- Transform the data from a raw string into
-- respective types (throws error on failure)
let f =
rawFrame
-- Change a specfic order ID
|> D.applyWhere (== 1) "order_id" (+ 2) "quantity"
-- Index based change.
|> D.applyAtIndex 0 (\n -> n - 2) "quantity"
-- Custom parsing: drop dollar sign and parse price as double
|> D.apply (D.readValue @Double . T.drop 1) "item_price"
-- sample the dataframe.
print $ D.take 10 f
-- Create a total_price column that is quantity * item_price
let multiply (a :: Int) (b :: Double) = fromIntegral a * b
let withTotalPrice = D.deriveFrom (["quantity", "item_price"], D.func multiply) "total_price" f
-- sample a filtered subset of the dataframe
putStrLn "Sample dataframe"
print $
withTotalPrice
|> D.select ["quantity", "item_name", "item_price", "total_price"]
|> D.filter "total_price" (100.0 <)
|> D.take 10
-- Check how many chicken burritos were ordered.
-- There are two ways to checking how many chicken burritos
-- were ordered.
let searchTerm = "Chicken Burrito" :: T.Text
print $
f
|> D.select ["item_name", "quantity"]
-- It's more efficient to filter before grouping.
|> D.filter "item_name" (searchTerm ==)
|> D.groupBy ["item_name"]
-- can also be written as:
-- D.aggregate (zip (repeat "quantity") [D.Sum, D.Maximum, D.Mean])
|> D.aggregate (map ("quantity",) [D.Sum, D.Maximum, D.Mean])
-- Automatically create a variable called <Agg>_<variable>
|> D.sortBy D.Descending ["Sum_quantity"]
-- Similarly, we can aggregate quantities by all rows.
print $
f
|> D.select ["item_name", "quantity"]
|> D.groupBy ["item_name"]
-- Aggregate written more explicitly.
-- We have the full expressiveness of Haskell and we needn't fall
-- use a DSL.
|> D.aggregate [("quantity", D.Maximum), ("quantity", D.Mean), ("quantity", D.Sum)]
|> D.take 10
let firstOrder =
withTotalPrice
|> D.filterBy (maybe False (T.isInfixOf "Guacamole")) "choice_description"
|> D.filterBy (("Chicken Bowl" :: T.Text) ==) "item_name"
print $ D.take 10 firstOrder