Package: pynto
pynto: Time series analysis in Python using the concatenative paradigmpynto is a Python package that lets you manipulate tabular data with the expressiveness and code reusability ofconcatenativeprogramming.  With pynto you define anexpressionthat formally specifies how to calculate the data in your table.  Expressions are made by chaining together functions calledwords.  It works like a pipeline: the output from one word becomes the input for the following word.  The table of data is treated like a stack of independent columns.  The rightmost column in the table is the top of the stack.  Words can add, remove or modify columns, but they are row-agnostic--expressions can be evaluated over any range of rows.What does it look like?>>> import pynto as pt 
>>> ma_dev = pt.saved('stock_prices') \         # define an expression that appends columns from the build-in database
>>>     .quote(pt.dup.rolling(20).mean.sub) \   # append a quoted expression to the stack
>>>     .each                                   # use the each combinator to apply the quotation to the previous columns
>>> df = ma_dev['2021-06-01':]                  # evaluate your expression over a date range to get a DataFrame
>>> pt.db['stocks_ma_dev'] = df                 # save the results back to the databaseWhy pynto?Expressive: Pythonic syntax; Combinatory logic for modular, reusable codePerformant: Column-wise multiprocessing; caching of duplicate operationsBatteries included:  Built-in Redis-based time series databaseInteroperable: Seemlessly integration with PandasGet pyntopip install pyntoReferenceThe BasicsCreate expressions by chaining built-in words together using a fluent interface, or using the+operator for words in the local namespace.  When evaluated, words will operate in left-to-right order, with operators following their operands inpostfixstyle.>>> square = pt.dup.mul         # duplicates the top column, then multiplies top two columns togetherThe wordcthat adds a constant-value column to the stack.  Like many pynto words,ctakes aparameterin parentheses to specify the constant valuec(10.0). pynto can handle any NumPy data type, but all rows in a column have to have the same type.>>> expr = pt.c(10.0) + square    # compose square expression with a columns of 10sTo evaluate your expression, specify a date range using the[start:stop (exclusive):periodicity]syntax.  (Instances ofpt.Rangein the local namespace also work.)>>> expr['2021-06-01':'2021-06-03','B']                   # evaluate over a two business day date range                                                   
             constant
2021-06-01     100.0
2021-06-02     100.0Each column has a string header that can be modified.hsetsets the header to a new value.  Headers can be usefully for filtering or arranging columns.>>> expr += pt.hset('ten squared')
>>> expr['2021-06-01':'2021-06-03','B']  
               ten squared
2021-06-01        100.0
2021-06-02        100.0Combinatorsare higher-order functions that allow pynto to do more complicated things like branching and looping.  Combinators operate onquotations, expressions that are pushed to the stack instead of operating on the stack.  To create a quotation put an expression within the parentheses ofpt.quote().>>> expr = pt.c(9.).c(10.).quote(square).each
>>> expr['2021-06-01':'2021-06-02']
              constant  constant
2021-06-01      81.0     100.0The Databasepynto has built-in time series database functionality that lets you save pandas DataFrames and Series to a Redis database.  The database uses only String key/values, saving the underlying numpy data in native byte format for zero-copy retrieval.   Each DataFrame column is saved as an independent key and can be retrieved on its own.  The database also supports three-dimensional frames that have a two-level MultiIndex.  Saved data can be accessed through pynto expressions or standard methods>>> pt.db['my_df'] = expr['2021-06-01':'2021-06-03']
>>> pt.saved('my_df')['2021-06-01':'2021-06-02']
              constant  constant
2021-06-01      81.0     100.0
>>> pt.db.read('my_df')
              constant  constant
2021-06-01      81.0     100.0
2021-06-02      81.0     100.0pynto built-in vocabularyWords for adding columnsNameParametersStack effectbefore--afterDescriptioncvalue-- cAdds a constant-valuecolumn.csvcsv_file, index_col=0, header='infer'-- c (c)Adds columns fromcsv_file.pandasframe_or_series-- c (c)Adds columns from a pandas data structure.c_rangevalue-- c (c)Add constant int columns from 0 tovalue.CombinatorsNameParametersStack effectbefore--afterDescriptioncalldepth=None, copy=Falsea q -- cApply quotation to stack, up todepthif specified.  Optionally leaves stack in place withcopy.eachstart=0, stop=None, every=1, copy=Falsea b q -- c dApply quotation stack elements fromstarttoendin groups ofevery.  Optionally leaves stack in place withcopy.repeattimesa b q -- c dApply quotation to the stacktimestimes.cleavenum_quotations, depth=None, copy=Falsea q q -- c dApplynum_quotationsquotations to copies of stack elements up todepth.  Optionally leaves stack in place withcopy.Words to manipulate columnsNameParametersStack effectbefore--afterDescriptiondupa -- a aDuplicate top column.rolla b c -- c a bPermute columns.swapa b -- b aSwap top two columns.dropa b c -- a bDrop top column.cleara b c --Clear columns.interleavecount=None, split_into=2a b c d -- a c b dDivide columns intosplit intogroups and interleave group elements.pullstart,end=None,clear=Falsea b c -- b c aBring columnsstart(toend) to the top.hpull*headers, clear=Falsea b c -- b c aBring columns with headers matching regexheadersto the top.  Optionally clear remainder of stackhfilter*headers, clear=Falsea b c -- aShortcut for hpull withclear=TrueWords to manipulate headersNameParametersStack effectbefore--afterDescriptionhset*headersa b -- a bSet top columns' headers toheaders.hformatformat_stringa -- aApplyformat_stringto existing headers.happlyheader_functiona -- aApplyheader_functionto existing header.Words for arithmetic or logical operatorsNameParametersStack effectbefore--afterDescriptionadda b -- ca + bsuba b -- ca - bmula b -- ca * bdiva b -- ca / bmoda b -- ca % bpowa b -- ca ** beqa b -- ca == bnea b -- ca != bgea b -- ca >= bgta b -- ca > blea b -- ca <= blta b -- ca < bnega -- ca * -1absa -- cabs(a)sqrta -- ca ** 0.5zeroToNaa -- cReplaces zeros with np.nanWords for creating window columnsNameParametersStack effectbefore--afterDescriptionrollingwindow=2, exclude_nans=True, lookback_multiplier=2a -- wCreate window column with values from most recentwindowrows.  Exclude nan-valued rows from count unlessexclude_nans.  Extend history up tolookback_multiplierto look for non-nan rows.crossinga b c -- wCreate window column with cross-sectional values from the same rows of all columns.Words for calculating statistics on window columnsNameParametersStack effectbefore--afterDescriptionsumw -- cSums of windows.meanw -- cMeans of windows.varw -- cVariances of windows.stdw -- cStandard deviations of windows.changew -- cChanges between first and last rows of windows.pct_changew -- cPercent changes between first and last rows of windows.log_changew -- cDifferences of logs of first and last rows of windows.firstw -- cFirst rows of windows.lastw -- cLast rows of windows.zscorew -- cZ-score of most recent rows within windows.Words for cleaning up dataNameParametersStack effectbefore--afterDescriptionfillvaluea -- aFill nans withvalue.ffilla -- aLast observation carry-forward.joindatea b -- cJoin top two columns, switching from second to first ondateindex.Other wordsNameParametersStack effectbefore--afterDescriptionewmawindow, fill_nans=Truea -- cCalculates exponentially-weighted moving average with half-lifewindow.wlagnumberw -- cLagnumberrows.