packages feed

dataframe 1.0.0.0 → 1.0.0.1

raw patch · 14 files changed

+115/−83 lines, 14 filesdep ~streamly-bytestringdep ~streamly-corePVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependency ranges changed: streamly-bytestring, streamly-core

API changes (from Hackage documentation)

- DataFrame: toMarkdownTable :: DataFrame -> Text
- DataFrame.Internal.DataFrame: toMarkdownTable :: DataFrame -> Text
- DataFrame.Internal.Expression: instance Control.DeepSeq.NFData DataFrame.Internal.Expression.MeanAcc
- DataFrame.Internal.Row: instance Control.DeepSeq.NFData DataFrame.Internal.Row.Any
- DataFrame.Operations.Core: partiallyParsed :: Column -> Int
- DataFrame.Operators: infix 6 .-
- DataFrame.Operators: infix 7 ./
- DataFrame.Operators: infix 8 .^.
- DataFrame.Typed.Expr: infix 8 .^
+ DataFrame: FULL_OUTER :: JoinType
+ DataFrame: INNER :: JoinType
+ DataFrame: LEFT :: JoinType
+ DataFrame: ParseOptions :: [Text] -> Int -> Bool -> DateFormat -> ParseOptions
+ DataFrame: RIGHT :: JoinType
+ DataFrame: [missingValues] :: ParseOptions -> [Text]
+ DataFrame: [parseDateFormat] :: ParseOptions -> DateFormat
+ DataFrame: [parseSafe] :: ParseOptions -> Bool
+ DataFrame: [sampleSize] :: ParseOptions -> Int
+ DataFrame: apply :: (Columnable b, Columnable c) => (b -> c) -> Text -> DataFrame -> DataFrame
+ DataFrame: applyAtIndex :: Columnable a => Int -> (a -> a) -> Text -> DataFrame -> DataFrame
+ DataFrame: applyDouble :: Columnable b => (Double -> b) -> Text -> DataFrame -> DataFrame
+ DataFrame: applyInt :: Columnable b => (Int -> b) -> Text -> DataFrame -> DataFrame
+ DataFrame: applyMany :: (Columnable b, Columnable c) => (b -> c) -> [Text] -> DataFrame -> DataFrame
+ DataFrame: applyWhere :: (Columnable a, Columnable b) => (a -> Bool) -> Text -> (b -> b) -> Text -> DataFrame -> DataFrame
+ DataFrame: data JoinType
+ DataFrame: data ParseOptions
+ DataFrame: defaultParseOptions :: ParseOptions
+ DataFrame: derive :: Columnable a => Text -> Expr a -> DataFrame -> DataFrame
+ DataFrame: deriveMany :: [NamedExpr] -> DataFrame -> DataFrame
+ DataFrame: deriveWithExpr :: Columnable a => Text -> Expr a -> DataFrame -> (Expr a, DataFrame)
+ DataFrame: fullOuterJoin :: [Text] -> DataFrame -> DataFrame -> DataFrame
+ DataFrame: impute :: ImputeOp a => Expr a -> BaseType a -> DataFrame -> DataFrame
+ DataFrame: innerJoin :: [Text] -> DataFrame -> DataFrame -> DataFrame
+ DataFrame: join :: JoinType -> [Text] -> DataFrame -> DataFrame -> DataFrame
+ DataFrame: leftJoin :: [Text] -> DataFrame -> DataFrame -> DataFrame
+ DataFrame: parseDefaults :: ParseOptions -> DataFrame -> DataFrame
+ DataFrame: rightJoin :: [Text] -> DataFrame -> DataFrame -> DataFrame
+ DataFrame: safeApply :: (Columnable b, Columnable c) => (b -> c) -> Text -> DataFrame -> Either DataFrameException DataFrame
+ DataFrame: toMarkdown :: DataFrame -> Text
+ DataFrame: toMarkdown' :: DataFrame -> String
+ DataFrame.Internal.DataFrame: toMarkdown :: DataFrame -> Text
+ DataFrame.Internal.DataFrame: toMarkdown' :: DataFrame -> String
+ DataFrame.Operators: infixl 6 .-
+ DataFrame.Operators: infixl 7 ./
+ DataFrame.Operators: infixr 8 .^.
+ DataFrame.Typed.Expr: infixr 8 .^
- DataFrame.Internal.Types: type Columnable' a = (Typeable a, Show a, Ord a, Eq a, Read a, NFData a)
+ DataFrame.Internal.Types: type Columnable' a = (Typeable a, Show a, Ord a, Eq a, Read a)

Files

CHANGELOG.md view
@@ -1,5 +1,13 @@ # Revision history for dataframe +## 1.0.0.1+* toMarkdownTable is now toMarkdown (mostly used internally)+* Provide toMarkdown' that outputs string+* Add associativity to nullable operators+* Better null dataframe handling/error messages for core operations.+* Fix some function display names.+* Examples now build with CI+ ## 1.0.0.0 * Fix mappend to respect schema of empty columns. * Add cast operators that force column schema
dataframe.cabal view
@@ -1,6 +1,6 @@ cabal-version:      2.4 name:               dataframe-version:            1.0.0.0+version:            1.0.0.1  synopsis: A fast, safe, and intuitive DataFrame library. @@ -145,10 +145,9 @@                       stm >= 2.5 && < 3,                       filepath >= 1.4 && < 2,                       Glob >= 0.10 && < 1,-                      http-conduit    >= 2.3 && < 3,-                      streamly-core,-                      streamly-bytestring,-+                      http-conduit >= 2.3 && < 3,+                      streamly-core >= 0.2.3 && < 0.4,+                      streamly-bytestring >= 0.2.0 && < 0.4     hs-source-dirs:   src     c-sources:        cbits/process_csv.c     include-dirs:     cbits
src/DataFrame.hs view
@@ -288,7 +288,8 @@     GroupedDataFrame,     empty,     null,-    toMarkdownTable,+    toMarkdown,+    toMarkdown',  ) import DataFrame.Internal.Expression as Expression (Expr, prettyPrint) import DataFrame.Internal.Row as Row (@@ -312,10 +313,16 @@ import DataFrame.Operations.Core as Core hiding (     ColumnInfo (..),     nulls,-    partiallyParsed,     renameSafe,  )-import DataFrame.Operations.Join as Join+import DataFrame.Operations.Join as Join (+    JoinType (..),+    fullOuterJoin,+    innerJoin,+    join,+    leftJoin,+    rightJoin,+ ) import DataFrame.Operations.Merge as Merge import DataFrame.Operations.Permutation as Permutation (     SortOrder (..),@@ -368,6 +375,22 @@     take,     takeLast,  )-import DataFrame.Operations.Transformations as Transformations-import DataFrame.Operations.Typing as Typing+import DataFrame.Operations.Transformations as Transformations (+    apply,+    applyAtIndex,+    applyDouble,+    applyInt,+    applyMany,+    applyWhere,+    derive,+    deriveMany,+    deriveWithExpr,+    impute,+    safeApply,+ )+import DataFrame.Operations.Typing as Typing (+    ParseOptions (..),+    defaultParseOptions,+    parseDefaults,+ ) import DataFrame.Operators as Operators
src/DataFrame/Functions.hs view
@@ -309,13 +309,13 @@ zScore c = (c - mean c) / stddev c  pow :: (Columnable a, Num a) => Expr a -> Int -> Expr a-pow expr i = lift2Decorated (^) "max" (Just "^") True 8 expr (Lit i)+pow expr i = lift2Decorated (^) "pow" (Just "^") True 8 expr (Lit i)  relu :: (Columnable a, Num a, Ord a) => Expr a -> Expr a relu = liftDecorated (Prelude.max 0) "relu" Nothing  min :: (Columnable a, Ord a) => Expr a -> Expr a -> Expr a-min = lift2Decorated Prelude.min "max" Nothing True 1+min = lift2Decorated Prelude.min "min" Nothing True 1  max :: (Columnable a, Ord a) => Expr a -> Expr a -> Expr a max = lift2Decorated Prelude.max "max" Nothing True 1
src/DataFrame/IO/CSV.hs view
@@ -27,6 +27,7 @@ import Data.Csv.Streaming (Records (..)) import qualified Data.Csv.Streaming as CsvStream +import Control.DeepSeq import Control.Monad import Data.Char import qualified Data.Csv as Csv@@ -272,7 +273,7 @@ readSeparated opts !path = do     let stripUtf8Bom bs = fromMaybe bs (BL.stripPrefix "\xEF\xBB\xBF" bs)     csvData <- stripUtf8Bom <$> BL.readFile path-    decodeSeparated opts csvData+    fmap force (decodeSeparated opts csvData)  decodeSeparated :: ReadOptions -> BL.ByteString -> IO DataFrame decodeSeparated !opts csvData = do
src/DataFrame/Internal/Column.hs view
@@ -134,9 +134,9 @@     show (TColumn col) = show col  instance NFData Column where-    rnf (BoxedColumn (v :: VB.Vector a)) = rnf v+    rnf (BoxedColumn (v :: VB.Vector a)) = VB.foldl' (const (`seq` ())) () v     rnf (UnboxedColumn v) = v `seq` ()-    rnf (OptionalColumn (v :: VB.Vector (Maybe a))) = rnf v+    rnf (OptionalColumn (v :: VB.Vector (Maybe a))) = VB.foldl' (const (`seq` ())) () v  instance Show Column where     show :: Column -> String
src/DataFrame/Internal/DataFrame.hs view
@@ -24,6 +24,7 @@ import DataFrame.Internal.Expression import Text.Printf import Type.Reflection (typeRep)+import Prelude hiding (null)  data DataFrame = DataFrame     { columns :: V.Vector Column@@ -97,9 +98,13 @@             T.unpack (asText d' False) ++ (if r > rows then truncationInfo else "")  -- | For showing the dataframe as markdown in notebooks.-toMarkdownTable :: DataFrame -> T.Text-toMarkdownTable df = asText df True+toMarkdown :: DataFrame -> T.Text+toMarkdown df = asText df True +-- | For showing the dataframe as a string markdown in notebooks.+toMarkdown' :: DataFrame -> String+toMarkdown' = T.unpack . toMarkdown+ asText :: DataFrame -> Bool -> T.Text asText d properMarkdown =     let header = map fst (sortBy (compare `on` snd) $ M.toList (columnIndices d))@@ -148,9 +153,11 @@ Nothing -} getColumn :: T.Text -> DataFrame -> Maybe Column-getColumn name df = do-    i <- columnIndices df M.!? name-    columns df V.!? i+getColumn name df+    | null df = Nothing+    | otherwise = do+        i <- columnIndices df M.!? name+        columns df V.!? i  {- | Retrieves a column by name from the dataframe, throwing an exception if not found. 
src/DataFrame/Internal/Expression.hs view
@@ -13,7 +13,6 @@  module DataFrame.Internal.Expression where -import Control.DeepSeq (NFData (..)) import Data.String import qualified Data.Text as T import Data.Type.Equality (TestEquality (testEquality), type (:~:) (Refl))@@ -37,9 +36,6 @@  data MeanAcc = MeanAcc {-# UNPACK #-} !Double {-# UNPACK #-} !Int     deriving (Show, Eq, Ord, Read)--instance NFData MeanAcc where-    rnf (MeanAcc _ _) = ()  data AggStrategy a b where     CollectAgg ::
src/DataFrame/Internal/Row.hs view
@@ -17,7 +17,6 @@ import qualified Data.Vector.Generic as VG import qualified Data.Vector.Unboxed as VU -import Control.DeepSeq (NFData (..)) import Control.Exception (throw) import Control.Monad.ST (runST) import Data.Function (on)@@ -57,9 +56,6 @@ instance Show Any where     show :: Any -> String     show (Value a) = T.unpack (showValue a)--instance NFData Any where-    rnf (Value a) = rnf a  showValue :: forall a. (Columnable a) => a -> T.Text showValue v = case testEquality (typeRep @a) (typeRep @T.Text) of
src/DataFrame/Internal/Types.hs view
@@ -13,14 +13,13 @@  module DataFrame.Internal.Types where -import Control.DeepSeq (NFData) import Data.Int (Int16, Int32, Int64, Int8) import Data.Kind (Constraint, Type) import Data.Typeable (Typeable) import qualified Data.Vector.Unboxed as VU import Data.Word (Word16, Word32, Word64, Word8) -type Columnable' a = (Typeable a, Show a, Ord a, Eq a, Read a, NFData a)+type Columnable' a = (Typeable a, Show a, Ord a, Eq a, Read a)  {- | A type with column representations used to select the "right" representation when specializing the `toColumn` function.
src/DataFrame/Operations/Core.hs view
@@ -44,6 +44,7 @@     derivingExpressions,     empty,     getColumn,+    null,  ) import DataFrame.Internal.Expression import DataFrame.Internal.Interpreter@@ -389,13 +390,15 @@ @ -} cloneColumn :: T.Text -> T.Text -> DataFrame -> DataFrame-cloneColumn original new df = fromMaybe-    ( throw $-        ColumnNotFoundException original "cloneColumn" (M.keys $ columnIndices df)-    )-    $ do-        column <- getColumn original df-        return $ insertColumn new column df+cloneColumn original new df+    | null df = throw (EmptyDataSetException "cloneColumn")+    | otherwise = fromMaybe+        ( throw $+            ColumnNotFoundException original "cloneColumn" (M.keys $ columnIndices df)+        )+        $ do+            column <- getColumn original df+            return $ insertColumn new column df  {- | /O(n)/ Renames a single column. @@ -479,13 +482,15 @@  renameSafe ::     T.Text -> T.Text -> DataFrame -> Either DataFrameException DataFrame-renameSafe orig new df = fromMaybe-    (Left $ ColumnNotFoundException orig "rename" (M.keys $ columnIndices df))-    $ do-        columnIndex <- M.lookup orig (columnIndices df)-        let origRemoved = M.delete orig (columnIndices df)-        let newAdded = M.insert new columnIndex origRemoved-        return (Right df{columnIndices = newAdded})+renameSafe orig new df+    | null df = throw (EmptyDataSetException "rename")+    | otherwise = fromMaybe+        (Left $ ColumnNotFoundException orig "rename" (M.keys $ columnIndices df))+        $ do+            columnIndex <- M.lookup orig (columnIndices df)+            let origRemoved = M.delete orig (columnIndices df)+            let newAdded = M.insert new columnIndex origRemoved+            return (Right df{columnIndices = newAdded})  data ColumnInfo = ColumnInfo     { nameOfColumn :: !T.Text@@ -579,15 +584,6 @@             _ -> 0 nulls _ = 0 -partiallyParsed :: Column -> Int-partiallyParsed (BoxedColumn (xs :: V.Vector a)) =-    case typeRep @a of-        App (App tycon t1) t2 -> case eqTypeRep tycon (typeRep @Either) of-            Just HRefl -> VG.length $ VG.filter isLeft xs-            Nothing -> 0-        _ -> 0-partiallyParsed _ = 0- {- | Creates a dataframe from a list of tuples with name and column.  ==== __Example__@@ -684,13 +680,15 @@ -} valueCounts ::     forall a. (Ord a, Columnable a) => Expr a -> DataFrame -> [(a, Int)]-valueCounts expr df = case columnAsVector expr df of-    Left e -> throw e-    Right column' ->-        let-            column = V.foldl' (\m v -> MS.insertWith (+) v (1 :: Int) m) M.empty column'-         in-            M.toAscList column+valueCounts expr df+    | null df = throw (EmptyDataSetException "valueCounts")+    | otherwise = case columnAsVector expr df of+        Left e -> throw e+        Right column' ->+            let+                column = V.foldl' (\m v -> MS.insertWith (+) v (1 :: Int) m) M.empty column'+             in+                M.toAscList column  {- | O (k * n) Shows the proportions of each value in a given column. @@ -706,16 +704,18 @@ -} valueProportions ::     forall a. (Ord a, Columnable a) => Expr a -> DataFrame -> [(a, Double)]-valueProportions expr df = case columnAsVector expr df of-    Left e -> throw e-    Right column' ->-        let-            counts =-                M.toAscList-                    (V.foldl' (\m v -> MS.insertWith (+) v (1 :: Int) m) M.empty column')-            total = fromIntegral (sum (map snd counts))-         in-            map (fmap ((/ total) . fromIntegral)) counts+valueProportions expr df+    | null df = throw (EmptyDataSetException "valueCounts")+    | otherwise = case columnAsVector expr df of+        Left e -> throw e+        Right column' ->+            let+                counts =+                    M.toAscList+                        (V.foldl' (\m v -> MS.insertWith (+) v (1 :: Int) m) M.empty column')+                total = fromIntegral (sum (map snd counts))+             in+                map (fmap ((/ total) . fromIntegral)) counts  {- | A left fold for dataframes that takes the dataframe as the last object. This makes it easier to chain operations.@@ -853,13 +853,16 @@ columnAsVector ::     forall a.     (Columnable a) => Expr a -> DataFrame -> Either DataFrameException (V.Vector a)-columnAsVector (Col name) df = case getColumn name df of-    Just col -> toVector col-    Nothing ->-        Left $ ColumnNotFoundException name "columnAsVector" (M.keys $ columnIndices df)-columnAsVector expr df = case interpret df expr of-    Left e -> throw e-    Right (TColumn col) -> toVector col+columnAsVector expr df+    | null df = throw (EmptyDataSetException "columnAsVector")+    | otherwise = case expr of+        (Col name) -> case getColumn name df of+            Just col -> toVector col+            Nothing ->+                Left $ ColumnNotFoundException name "columnAsVector" (M.keys $ columnIndices df)+        _ -> case interpret df expr of+            Left e -> throw e+            Right (TColumn col) -> toVector col  {- | Retrieves a column as an unboxed vector of 'Int' values. @@ -952,6 +955,8 @@ @(name, expression)@ pairs. Derived columns show their expression; raw columns show an identity @col \@type name@ expression. -}++-- TODO: mchavinda - Expand out these expressions if possible. showDerivedExpressions :: DataFrame -> [NamedExpr] showDerivedExpressions df =     let exprs = derivingExpressions df
src/DataFrame/Operators.hs view
@@ -36,9 +36,9 @@  ) import DataFrame.Internal.Types (Promote, PromoteDiv) -infix 8 .^^, .^^., .^, .^.-infix 6 .+, .--infix 7 .*, ./+infixr 8 .^^, .^^., .^, .^.+infixl 7 .*, ./, .*., ./.+infixl 6 .+, .-, .+., .-. infix 4 .==, .==., .<, .<., .<=, .<=., .>=, .>=., .>, .>., ./=, ./=. infixr 3 .&&, .&&. infixr 2 .||, .||.
src/DataFrame/Typed/Expr.hs view
@@ -274,7 +274,7 @@ infixr 2 .||., .|| infixl 6 .+., .-. infixl 7 .*., ./.-infix 8 .^^., .^^, .^., .^+infixr 8 .^^., .^^, .^., .^  (.==.) ::     (Columnable a, Eq a) => TExpr cols a -> TExpr cols a -> TExpr cols Bool
tests/Operations/Provenance.hs view
@@ -3,9 +3,7 @@  module Operations.Provenance where -import qualified Data.List as L import qualified Data.Map as M-import qualified Data.Text as T import qualified DataFrame as D import qualified DataFrame.Functions as F import qualified DataFrame.Internal.Column as DI