{ "info": { "author": "Don Smiley", "author_email": "ds@sidorof.com", "bugtrack_url": null, "classifiers": [ "Development Status :: 3 - Alpha", "Environment :: Console", "Intended Audience :: Developers", "Intended Audience :: Science/Research", "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Topic :: Adaptive Technologies", "Topic :: Scientific/Engineering", "Topic :: Software Development :: Libraries :: Python Modules" ], "description": "Thymus-timeseries\n=================\n\nAn intuitive library tracking dates and timeseries in common using numpy\narrays.\n\nWhen working with arrays of timeseries, the manipulation process can\neasily cause mismatching sets of arrays in time, arrays in the wrong\norder, slow down the analysis, and lead to generally spending more time\nto ensure consistency.\n\nThis library attempts to address the problem in a way that enables ready\naccess to the current date range, but stays out of your way most of the\ntime. Essentially, this library is a wrapper around numpy arrays.\n\nThis library grew out of the use of market and trading data. The\ntimeseries is typically composed of regular intervals but with gaps such\nas weekends and holidays. In the case of intra-day data, there are\ninteruptions due to periods when the market is closed or gaps in\ntrading.\n\nWhile the library grew from addressing issues associated with market\ndata, the implementation does not preclude use in other venues. Direct\naccess to the numpy arrays is expected and the point of being able to\nuse the library.\n\nDependencies\n------------\n\nOther than NumPy being installed, there are no other requirements.\n\nInstallation\n------------\n\npip install thymus-timeseries\n\nA Brief Look at Capabilities.\n-----------------------------\n\nCreating a Small Sample Timeseries Object\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nAs a first look, we will create a small timeseries object and show a few\nways that it can used. For this example, we will use daily data.\n\n::\n\n from datetime import datetime\n import numpy as np\n\n from thymus.timeseries import Timeseries\n\n ts = Timeseries()\n\n # elements of Timeseries()\n key: (an optional identifier for the timeseries)\n columns: [] (an optional list of column names for the data)\n frequency: d (the d in this case refers to the default daily data.\n current frequencies supported are sec, min, h, d, w,\n m, q, y)\n\n dseries: (this is a numpy array of dates in numeric format)\n\n tseries: (this is a numpy array of data. most of the work takes\n place here.)\n\n end-of-period: True (this is a default indicating that the data is as of\n the end of the data. This only comes into play when\n converting from one frequency to another and will\n be ignored for the moment.)\n\nWhile normal usage of the timeseries object would involve pulling data\nfrom a database and inserting data into the timeseries object, we will\nuse a quick-and-dirty method of inputting some data. Dates are stored as\neither ordinals or timestamps, avoiding clogging up memory with large\nsets of datetime objects. Because it is daily data, ordinals will be\nused for this example.\n\n::\n\n ts = Timeseries()\n\n start_date = datetime(2015, 12, 31).toordinal()\n\n ts.dseries = start_date + np.arange(10)\n ts.tseries = np.arange(10)\n\n ts.make_arrays()\n\nWe created an initial timeseries object. It starts at the end of 2015\nand continues for 10 days. Setting the values in **dseries** and\n**tseries** can be somewhat sloppy. For example, a list could be\nassigned initially to either **dseries** (the dates) and a numpy array\nto **tseries** (the values).\n\nThe use of the **make\\_arrays()** function converts the date series to\nan int32 array (because they are ordinal values) and **tseries** to a\nfloat64 array. The idea is that the data might often enter the\ntimeseries object as lists, but then be converted to arrays of\nappropriate format for use.\n\nThe completed timeseries object is:\n\n::\n\n print(ts)\n\n \n key:\n columns: []\n frequency: d\n daterange: ('2015-12-31', '2016-01-09')\n end-of-period: True\n shape: (10,)\n\nYou can see the date range contained in the date series. The shape\nrefers to the shape of the **tseries** array. **key** and **columns**\nare free-form, available to update as appropriate to identify the\ntimeseries and content of the columns. Again, the **end-of-period** flag\ncan be ignored right now.\n\nSelection\n---------\n\nSelection of elements is the same as numpy arrays. Currently, our sample\nhas 10 elements.\n\n::\n\n print(ts[:5])\n \n key:\n columns: []\n frequency: d\n daterange: ('2015-12-31', '2016-01-04')\n end-of-period: True\n shape: (5,)\n\nNote how the date range above reflects the selected elements.\n\n::\n\n ts1 = ts % 2 == 0\n ts1.tseries\n [ True False True False True False True False True False]\n\nWe can isolate the dates of even numbers:\n\n::\n\n # note that tseries, not the timeseries obj, is explicitly used with\n # np.argwhere. More on when to operate directly on tseries later.\n evens = np.argwhere((ts % 2 == 0).tseries)\n\n ts_even = ts[evens]\n\n # this just prints a list of date and value pairs only useful with\n # very small sets (or examples like this)\n print(ts_even.items('str'))\n ('2015-12-31', '[0.0]')\n ('2016-01-02', '[2.0]')\n ('2016-01-04', '[4.0]')\n ('2016-01-06', '[6.0]')\n ('2016-01-08', '[8.0]')\n\nDate-based Selection\n--------------------\n\nSo let us use a slightly larger timeseries. 1000 rows 2 columns of data.\nAnd, use random values to ensure uselessness.\n\n::\n\n ts = Timeseries()\n\n start_date = datetime(2015, 12, 31).toordinal()\n\n ts.dseries = start_date + np.arange(1000)\n ts.tseries = np.random.random((1000, 2))\n\n ts.make_arrays()\n\n print(ts)\n\n \n key:\n columns: []\n frequency: d\n daterange: ('2015-12-31', '2018-09-25')\n end-of-period: True\n shape: (1000, 2)\n\nYou can select on the basis of date ranges, but first we will use a row\nnumber technique that is based on slicing. This function is called\n**trunc()** for truncation.\n\n::\n\n # normal truncation -- you will end up with a timeseries with row 100\n # through 499. This provides in-place execution.\n ts.trunc(start=100, finish=500)\n\n # this version returns a new timeseries, effective for chaining.\n ts1 = ts.trunc(start=100, finish=500, new=True)\n\nBut suppose you want to select a specific date range? This leads to the\nnext function, **truncdate()**.\n\n::\n\n # select using datetime objects\n ts1 = ts.truncdate(\n start=datetime(2017, 1, 1),\n finish=datetime(2017, 12, 31),\n new=True)\n\n print(ts1)\n\n \n key:\n columns: []\n frequency: d\n daterange: ('2017-01-01', '2017-12-31')\n end-of-period: True\n shape: (365, 2)\n\nAs you might expect, the timeseries object has a date range of all the\ndays during 2017. But see how this is slightly different than slicing.\nWhen you use **truncdate()** it selects everything within the date range\ninclusive of the ending date as well. The idea is to avoid having to\nalways find one day after the date range that you want to select to\naccommodate slicing behavior. This way is more convenient.\n\nYou can also convert data from a higer frequency to a lower frequency.\nSuppose we needed monthly data for 2017 from our timeseries.\n\n::\n\n start = datetime(2017, 1, 1)\n finish = datetime(2017, 12, 31)\n ts1 = ts.truncdate(start=start, finish=finish, new=True).convert('m')\n\n print(ts1.items('str'))\n\n ('2017-01-31', '[0.1724835781570483, 0.9856812220255055]')\n ('2017-02-28', '[0.3855043513164875, 0.30697511661843124]')\n ('2017-03-31', '[0.7067982987769881, 0.7680886691626396]')\n ('2017-04-30', '[0.07770763295126926, 0.04697651222041588]')\n ('2017-05-31', '[0.4473657194650975, 0.49443624153533783]')\n ('2017-06-30', '[0.3793816656495891, 0.03646544387811124]')\n ('2017-07-31', '[0.2783335012003322, 0.5144979569785825]')\n ('2017-08-31', '[0.9261879195281345, 0.6980224313957553]')\n ('2017-09-30', '[0.09531834159018227, 0.5435208082899813]')\n ('2017-10-31', '[0.6865842769906441, 0.7951735180348887]')\n ('2017-11-30', '[0.34901775001111657, 0.7014208950555662]')\n ('2017-12-31', '[0.4731393617405252, 0.630488855197775]')\n\nOr yearly. In this case, we use a flag that governs whether to include\nthe partial period leading up to the last year. The default includes it.\nHowever, when unwanted the flag, **include\\_partial** can be set to\nFalse.\n\n::\n\n ts1 = ts.convert('y', include_partial=True)\n\n print(ts1.items('str'))\n\n ('2015-12-31', '[0.2288539210230056, 0.288320541664724]')\n ('2016-12-31', '[0.5116274142615629, 0.21680312154651182]')\n ('2017-12-31', '[0.4731393617405252, 0.630488855197775]')\n ('2018-09-25', '[0.7634145837512148, 0.32026411425902257]')\n\n ts2 = ts.convert('y', include_partial=False)\n\n print(ts2.items('str'))\n\n ('2015-12-31', '[[0.2288539210230056, 0.288320541664724]]')\n ('2016-12-31', '[[0.5116274142615629, 0.21680312154651182]]')\n ('2017-12-31', '[[0.4731393617405252, 0.630488855197775]]')\n\nCombining Timeseries\n--------------------\n\nSuppose you want to combine multiple timeseries together that are of\ndifferent lengths? In this case we assume that the two timeseries end on\nthe same date, but one has a longer tail than the other. However, the\noperation that you need requires common dates.\n\nBy **combine** we mean instead of two timeseries make one timeseries\nthat has the columns of both.\n\n::\n\n ts_short = Timeseries()\n ts_long = Timeseries()\n\n end_date = datetime(2016, 12, 31)\n\n ts_short.dseries = [\n (end_date + timedelta(days=-i)).toordinal()\n for i in range(5)]\n\n ts_long.dseries = [\n (end_date + timedelta(days=-i)).toordinal()\n for i in range(10)]\n\n ts_short.tseries = np.zeros((5))\n ts_long.tseries = np.ones((10))\n\n ts_short.make_arrays()\n ts_long.make_arrays()\n\n ts_combine = ts_short.combine(ts_long)\n\n print(ts.items('str'))\n\n ('2016-12-31', '[0.0, 1.0]')\n ('2016-12-30', '[0.0, 1.0]')\n ('2016-12-29', '[0.0, 1.0]')\n ('2016-12-28', '[0.0, 1.0]')\n ('2016-12-27', '[0.0, 1.0]')\n\nThe combine function has a couple variations. While it can be helpful to\nautomatically discard the unwanted rows, you can also enforce that\ncombining does not take place if the number of rows do not match. Also,\nyou can build out the missing information with padding to create a\ntimeseries that has the length of the longest timeseries.\n\n::\n\n # this would raise an error -- the two are different lengths\n ts_combine = ts_short.combine(ts_long discard=False)\n\n # this combines, and fills 99 as a missing value\n ts_combine = ts_short.combine(ts_long discard=False, pad=99)\n\n print(ts_combine.items('str'))\n ('2016-12-31', '[0.0, 1.0]')\n ('2016-12-30', '[0.0, 1.0]')\n ('2016-12-29', '[0.0, 1.0]')\n ('2016-12-28', '[0.0, 1.0]')\n ('2016-12-27', '[0.0, 1.0]')\n ('2016-12-26', '[99.0, 1.0]')\n ('2016-12-25', '[99.0, 1.0]')\n ('2016-12-24', '[99.0, 1.0]')\n ('2016-12-23', '[99.0, 1.0]')\n ('2016-12-22', '[99.0, 1.0]')\n\nThe combining can also receive multiple timeseries.\n\n::\n\n ts_combine = ts_short.combine([ts_long, ts_long, ts_long])\n\n print(ts_combine.items('str'))\n ('2016-12-31', '[0.0, 1.0, 1.0, 1.0]')\n ('2016-12-30', '[0.0, 1.0, 1.0, 1.0]')\n ('2016-12-29', '[0.0, 1.0, 1.0, 1.0]')\n ('2016-12-28', '[0.0, 1.0, 1.0, 1.0]')\n ('2016-12-27', '[0.0, 1.0, 1.0, 1.0]')\n\nSplitting Timeseries\n--------------------\n\nIn some ways it would make sense to mirror the **combine()** function\nwith a **split()** from an aesthetic standpoint. However, splitting is\nvery straight-forward without such a function. For example, suppose you\nwant a timeseries that only has the the first two columns from our\nprevious example. As you can see in the ts\\_split tseries, the first two\ncolumns were taken.\n\n::\n\n ts_split = ts_combine[:, :2]\n\n print(ts_split.items('str'))\n ('2016-12-31', '[0.0, 1.0]')\n ('2016-12-30', '[0.0, 1.0]')\n ('2016-12-29', '[0.0, 1.0]')\n ('2016-12-28', '[0.0, 1.0]')\n ('2016-12-27', '[0.0, 1.0]')\n\nArithmetic Operations\n---------------------\n\nWe have combined timeseries together to stack up rows in common. In\naddition, we looked at the issue of mismatched lengths. Now we will look\nat arithmetic approaches and some of the design decisions and tradeoffs\nassociated with mathematical operations.\n\nWe will start with the **add()** function. First, if we assume that all\nwe are adding together are arrays that have exactly the same dateseries,\nand therefore the same length, and we assume they have exactly the same\nnumber of columns, then the whole question becomes trivial. If we relax\nthose constraints, then some choices need to be made.\n\nWe will use the long and short timeseries from the previous example.\n\n::\n\n # this will fail due to dissimilar lengths\n ts_added = ts_short.add(ts_long, match=True)\n\n # this will work\n ts_added = ts_short.add(ts_long, match=False)\n\n [ 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.]\n\nThe **add()** function checks to see if the number of columns match. If\nthey do not an error is raised. If the **match** flag is True, then it\nalso checks that all the dates in both timeseries match prior to the\noperation.\n\nIf **match** is False, then as long as the columns are compatible, the\noperation can take place. It also supports the concept of sparse arrays\nas well. For example, suppose you have a timeseries that is primary, but\nyou would like to add in a timeseries values from only a few dates\nwithin the range. This function will find the appropriate dates adding\nin the values at just those rows.\n\nTo summarize, all dates in common to both timeseries will be included in\nthe new timeseries if **match** is False.\n\nBecause the previous function is somewhat specialized, you can assume\nthat the checking of common dates and creating the new timeseries can be\nsomewhat slower than other approaches.\n\nIf we assume some commonalities about our timeseries, then we can do our\nwork in a more intuitive fashion.\n\nAssumptions of Commonality\n~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nLet us assume that our timeseries might be varying in length, but we\nabsolutely know what either our starting date or ending date is. And,\nlet us assume that all the dates for the periods in common to the\ntimeseries match.\n\nIf we accept those assumptions, then a number of operations become quite\neasy.\n\nThe timeseries object can accept simple arithmetic as if it is an array.\nIt automatically passes the values on to the **tseries** array. If the\ntwo arrays are not the same length the longer array is truncated to the\nshorter length. So if you were add two arrays together that end at the\nsame date, you would want to sort them latest date to earliest date\nusing the function **sort\\_by\\_date()**.\n\nExamples\n~~~~~~~~\n\n::\n\n # starting tseries\n ts.tseries\n [ 0. 1. 2. 3. 4. 5. 6. 7. 8. 9.]\n\n (ts + 3).tseries\n [ 3. 4. 5. 6. 7. 8. 9. 10. 11. 12.]\n\n # Also, reverse (__radd__)\n (3 + ts).tseries\n [ 3. 4. 5. 6. 7. 8. 9. 10. 11. 12.]\n\n # of course not just addition\n 5 * ts.tseries\n [ 0. 5. 10. 15. 20. 25. 30. 35. 40. 45.]\n\nAlso, in-place operations. But first, we will make a copy.\n\n::\n\n ts1 = ts.clone()\n ts1.tseries /= 3\n print(ts1.tseries)\n [0.0\n 0.3333333333333333\n 0.6666666666666666\n 1.0\n 1.3333333333333333\n 1.6666666666666667\n 2.0\n 2.3333333333333335\n 2.6666666666666665\n 3.0]\n\n ts1 = ts ** 3\n ts1.tseries\n 0.0\n 1.0\n 8.0\n 27.0\n 64.0\n 125.0\n 216.0\n 343.0\n 512.0\n 729.0\n\n ts1 = 10 ** ts\n ts1.tseries\n [1.0\n 10.0\n 100.0\n 1000.0\n 10000.0\n 100000.0\n 1000000.0\n 10000000.0\n 100000000.0\n 1000000000.0]\n\nIn other words, the normal container functions you can use with numpy\narrays are available to the timeseries objects. The following container\nfunctions for arrays are supported.\n\n::\n\n __pow__ __add__ __rsub__ __sub__ __eq__ __ge__ __gt__ __le__\n __lt__ __mod__ __mul__ __ne__ __radd__ __rmod__ __rmul__ __rpow__\n __abs__ __pos__ __neg__ __invert__ __rdivmod__ __rfloordiv__\n __floordiv__ __truediv__\n __rtruediv__ __divmod__\n\n __and__ __or__ __ror__ __rand__ __rxor__ __xor__ __rshift__\n __rlshift__ __lshift__ __rrshift__\n\n __iadd__ __ifloordiv__ __imod__ __imul__ __ipow__ __isub__\n __itruediv__]\n\n __iand__ __ilshift__ __ior__ __irshift__ __ixor__\n\nFunctions of Arrays Not Supported\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nThe purpose the timeseries objects is to implement an intuitive usage of\ntimeseries objects in a fashion that is consistent with NumPy. However,\nit is not intended to replace functions that are better handled\nexplicitly with the **dseries** and **tseries** arrays directly. The\ndifference will be clear by comparing the list of functions for the\ntimeseries object versus a numpy array. Most of the functions of the\ntimeseries object is related to handling the commonality of date series\nwith time series. You can see that the bulk of the thymus functions\nrelate to maintenance of the coordination betwee the date series and\ntimeseries. The meat of the functions still lie with the numpy arrays.\n\n::\n\n # timeseries members and functions:\n ts.add ts.daterange ts.get_pcdiffs ts.series_direction\n ts.as_dict ts.datetime_series ts.header ts.set_ones\n ts.as_json ts.dseries ts.if_dseries_match ts.set_zeros\n ts.as_list ts.end_date ts.if_tseries_match ts.shape\n ts.clone ts.end_of_period ts.items ts.sort_by_date\n ts.closest_date ts.extend ts.key ts.start_date\n ts.columns ts.fmt_date ts.lengths ts.trunc\n ts.combine ts.frequency ts.make_arrays ts.truncdate\n ts.common_length ts.get_date_series_type ts.months ts.tseries\n ts.convert ts.get_datetime ts.replace ts.years\n ts.date_native ts.get_diffs ts.reverse\n ts.date_string_series ts.get_duped_dates ts.row_no\n\n # numpy functions in the arrays\n ts.tseries.T ts.tseries.cumsum ts.tseries.min ts.tseries.shape\n ts.tseries.all ts.tseries.data ts.tseries.nbytes ts.tseries.size\n ts.tseries.any ts.tseries.diagonal ts.tseries.ndim ts.tseries.sort\n ts.tseries.argmax ts.tseries.dot ts.tseries.newbyteorder ts.tseries.squeeze\n ts.tseries.argmin ts.tseries.dtype ts.tseries.nonzero ts.tseries.std\n ts.tseries.argpartition ts.tseries.dump ts.tseries.partition ts.tseries.strides\n ts.tseries.argsort ts.tseries.dumps ts.tseries.prod ts.tseries.sum\n ts.tseries.astype ts.tseries.fill ts.tseries.ptp ts.tseries.swapaxes\n ts.tseries.base ts.tseries.flags ts.tseries.put ts.tseries.take\n ts.tseries.byteswap ts.tseries.flat ts.tseries.ravel ts.tseries.tobytes\n ts.tseries.choose ts.tseries.flatten ts.tseries.real ts.tseries.tofile\n ts.tseries.clip ts.tseries.getfield ts.tseries.repeat ts.tseries.tolist\n ts.tseries.compress ts.tseries.imag ts.tseries.reshape ts.tseries.tostring\n ts.tseries.conj ts.tseries.item ts.tseries.resize ts.tseries.trace\n ts.tseries.conjugate ts.tseries.itemset ts.tseries.round ts.tseries.transpose\n ts.tseries.copy ts.tseries.itemsize ts.tseries.searchsorted ts.tseries.var\n ts.tseries.ctypes ts.tseries.max ts.tseries.setfield ts.tseries.view\n ts.tseries.cumprod ts.tseries.mean ts.tseries.setflags\n\nOther Date Functions\n~~~~~~~~~~~~~~~~~~~~\n\nVariations on a theme:\n\n::\n\n # truncation\n ts.truncdate(\n start=datetime(2017, 1, 1),\n finish=datetime(2017, 12, 31))\n\n # just start date etc.\n ts.truncdate(\n start=datetime(2017, 1, 1))\n\n # this was in date order but suppose it was in reverse order?\n # this result will give the same answer\n ts1 = ts.truncdate(\n start=datetime(2017, 1, 1),\n new=True)\n\n ts.reverse()\n\n ts1 = ts.truncdate(\n start=datetime(2017, 1, 1),\n new=True)\n\n # use the date format native to the dateseries (ordinal / timestamp)\n ts1 = ts.truncdate(\n start=datetime(2017, 1, 1).toordinal(),\n new=True)\n\n # suppose you start with a variable that represents a date range\n # date range can be either a list or tuple\n ts.truncdate(\n [datetime(2017, 1, 1), datetime(2017, 12, 31)])\n\nAssorted Date Functions\n-----------------------\n\n::\n\n # native format\n ts.daterange()\n (735963, 735972)\n\n # str format\n ts.daterange('str')\n ('2015-12-31', '2016-01-09')\n\n # datetime format\n ts.daterange('datetime')\n (datetime.datetime(2015, 12, 31, 0, 0), datetime.datetime(2016, 1, 9, 0, 0))\n\n # native format\n ts.start_date(); ts.end_date()\n 735963 735972\n\n # str format\n ts.start_date('str'); ts.end_date('str')\n 2015-12-31 2016-01-09\n\n # datetime format\n ts.start_date('datetime'); ts.end_date('datetime')\n 2015-12-31 00:00:00 2016-01-09 00:00:00\n\nSometimes it is helpful to find a particular row based on the date.\nAlso, that date might not be in the dateseries, and so, the closest date\nwill suffice.\n\nWe will create a sample timeseries to illustrate.\n\n::\n\n ts = Timeseries()\n ts.dseries = []\n ts.tseries = []\n\n start_date = datetime(2015, 12, 31)\n for i in range(40):\n date = start_date + timedelta(days=i)\n if date.weekday() not in [5, 6]: # skipping weekends\n\n ts.dseries.append(date.toordinal())\n ts.tseries.append(i)\n\n ts.make_arrays()\n\n # row_no, date\n (0, '2015-12-31')\n (1, '2016-01-01')\n (2, '2016-01-04')\n (3, '2016-01-05')\n (4, '2016-01-06')\n (5, '2016-01-07')\n (6, '2016-01-08')\n (7, '2016-01-11')\n (8, '2016-01-12')\n (9, '2016-01-13')\n (10, '2016-01-14')\n (11, '2016-01-15')\n (12, '2016-01-18')\n (13, '2016-01-19')\n (14, '2016-01-20')\n (15, '2016-01-21')\n (16, '2016-01-22')\n (17, '2016-01-25')\n (18, '2016-01-26')\n (19, '2016-01-27')\n (20, '2016-01-28')\n (21, '2016-01-29')\n (22, '2016-02-01')\n (23, '2016-02-02')\n (24, '2016-02-03')\n (25, '2016-02-04')\n (26, '2016-02-05')\n (27, '2016-02-08')\n\n date1 = datetime(2016, 1, 7) # existing date within date series\n date2 = datetime(2016, 1, 16) # date falling on a weekend\n date3 = datetime(2015, 6, 16) # date prior to start of date series\n date4 = datetime(2016, 3, 8) # date after to end of date series\n\n # as datetime and in the series\n existing_row = ts.row_no(rowdate=date1, closest=1)\n 5\n\n existing_date = ts.closest_date(rowdate=date1, closest=1)\n print(datetime.fromordinal(existing_date))\n 2016-01-07 00:00:00\n\n # as datetime but date not in series\n next_row = ts.row_no(rowdate=date2, closest=1)\n 12\n\n next_date = ts.closest_date(rowdate=date2, closest=1)\n print(datetime.fromordinal(next_date))\n 2016-01-18 00:00:00\n\n prev_row = ts.row_no(rowdate=date2, closest=-1)\n 11\n\n prev_date = ts.closest_date(rowdate=date2, closest=-1)\n print(datetime.fromordinal(prev_date))\n 2016-01-15 00:00:00\n\n # this will fail -- date is outside the date series\n # as datetime but date not in series, look for earlier date\n ts.closest_date(rowdate=date3, closest=-1)\n\n # this will fail -- date is outside the date series\n ts.closest_date(rowdate=date4, closest=1)\n\nFunctions by Category\n---------------------\n\nOutput\n~~~~~~\n\nts.as\\_dict()\n^^^^^^^^^^^^^\n\n::\n\n Returns the time series as a dict with the date as the key and without\n the header information.\n\nts.as\\_json(indent=2)\n^^^^^^^^^^^^^^^^^^^^^\n\n::\n\n This function returns the timeseries in JSON format and includes the\n header information.\n\nts.as\\_list()\n^^^^^^^^^^^^^\n\n::\n\n Returns the timeseries as a list.\n\nts.header()\n^^^^^^^^^^^\n\n::\n\n This function returns a dict of the non-timeseries data.\n\nts.items(fmt=None)\n^^^^^^^^^^^^^^^^^^\n\n::\n\n This function returns the date series and the time series as if it\n is in one list. The term items used to suggest the iteration of dicts\n where items are the key, value combination.\n\n if fmt == 'str':\n the dates are output as strings\n\nts.months(include\\_partial=True)\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\n::\n\n This function provides a quick way to summarize daily (or less)\n as monthly data.\n\n It is basically a pass-through to the convert function with more\n decoration of the months.\n\n Usage:\n\n months(include_partial=True)\n\n returns a dict with year-month as keys\n\nts.years(include\\_partial=True)\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\n::\n\n This function provides a quick way to summarize daily (or less)\n as yearly data.\n\n It is basically a pass-through to the convert function with more\n decoration of the years.\n\n Usage:\n\n years(include_partial=True)\n\n returns a dict with year as keys\n\nts.datetime\\_series()\n^^^^^^^^^^^^^^^^^^^^^\n\n::\n\n This function returns the dateseries converted to a list of\n datetime objects.\n\nts.date\\_string\\_series(dt\\_fmt=None)\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\n::\n\n This function returns a list of the dates in the timeseries as\n strings.\n\n Usage:\n self.date_string_series(dt_fmt=None)\n\n dt_fmt is a datetime mask to alter the default formatting.\n\nArray Manipulation\n~~~~~~~~~~~~~~~~~~\n\nts.add(ts, match=True)\n^^^^^^^^^^^^^^^^^^^^^^\n\n::\n\n Adds two timeseries together.\n\n if match is True:\n means there should be a one to one corresponding date in each time\n series. If not raise error.\n else:\n means that timeseries with sporadic or missing dates can be added\n\n Note: this does not evaluate whether both timeseries have the same\n number of columns. It will fail if they do not.\n\n Returns the timeseries. Not in-place.\n\nts.clone()\n^^^^^^^^^^\n\n::\n\n This function returns a copy of the timeseries.\n\nts.combine(tss, discard=True, pad=None)\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\n::\n\n This function combines timeseries into a single array. Combining in\n this case means accumulating additional columns of information.\n\n Truncation takes place at the end of rows. So if the timeseries is\n sorted from latest dates to earliest dates, the older values would be\n removed.\n\n Usage:\n self.combine(tss, discard=True, pad=None)\n\n Think of tss as the plural of timeseries.\n\n If discard:\n Will truncate all timeseries lengths down to the shortest\n timeseries.\n\n if discard is False:\n An error will be raised if the all the lengths do not match\n\n unless:\n if pad is not None:\n the shorter timeseries will be padded with the value pad.\n\n Returns the new ts.\n\nts.common\\_length(ts1, ts2)\n^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\n::\n\n This static method trims the lengths of two timeseries and returns two\n timeseries with the same length.\n\n The idea is that in order to do array operations there must be a\n common length for each timeseries.\n\n Reflecting the bias for using timeseries sorted from latest info to\n earlier info, truncation takes place at the end of the array. That\n way older less important values are removed if necessary.\n\n Usage:\n ts1_new, ts2_new = self.common_length(ts1, ts2)\n\nts.convert(new\\_freq, include\\_partial=True, \\*\\*kwargs)\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\n::\n\n This function returns the timeseries converted to another frequency,\n such as daily to monthly.\n\n Usage:\n convert(new_freq, include_partial=True, **kwargs)\n\n The only kwarg is\n weekday=\n\n This is used when converting to weekly data. The weekday number\n corresponds to the the datetime.weekday() function.\n\nts.extend(ts, overlay=True)\n^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\n::\n\n This function combines a timeseries to another, taking into account the\n possibility of overlap.\n\n This assumes that the frequency is the same.\n\n This function is chiefly envisioned to extend a timeseries with\n additional dates.\n\n Usage:\n self.extend(ts, overlay=True)\n\n If overlay is True then the incoming timeseries will overlay\n any values that are duplicated.\n\nts.trunc(start=None, finish=None, new=False)\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\n::\n\n This function truncates in place, typically.\n\n truncate from (start:finish)\n remember start is lowest number, latest date\n\n This truncation works on the basis of slicing, so\n finish is not inclusive.\n\n Usage:\n self.trunc(start=None, finish=None, new=False)\n\nts.truncdate(start=None, finish=None, new=False)\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\n::\n\n This function truncates in place on the basis of dates.\n\n Usage:\n self.truncdate(start=None, finish=None, new=False)\n\n start and finish are dates, input as either datetime or the actual\n internal format of the **dseries** (ordinals or timestamps).\n\n If the dates are not actually in the list, the starting date will\n be the next viable date after the start date requested. If the finish\n date is not available, the previous date from the finish date will be\n the last.\n\n If new is True, the timeseries will not be modified in place. Rather\n a new timeseries will be returned instead.\n\nts.replace(ts, match=True)\n^^^^^^^^^^^^^^^^^^^^^^^^^^\n\n::\n\n This function replaces values where the dates match an incoming\n timeseries. So if the incoming date on the timeseries matches, the\n value in the current timeseries will be replaced by the incoming\n timeseries.\n\n Usage:\n self.replace(ts, match=True)\n\n If match is False, the incoming timseries may have dates not found in\n the self timeseries.\n\n Returns the modified timeseries. Not in place.\n\nts.reverse()\n^^^^^^^^^^^^\n\n::\n\n This function does in-place reversal of the timeseries and dateseries.\n\nts.get\\_diffs()\n^^^^^^^^^^^^^^^\n\n::\n\n This function gets the differences between values from date to date in\n the timeseries.\n\nts.get\\_pcdiffs()\n^^^^^^^^^^^^^^^^^\n\n::\n\n This function gets the percent differences between values in the\n timeseries.\n\n No provision for dividing by zero here.\n\nts.set\\_ones(fmt=None, new=False)\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\n::\n\n This function converts an existing timeseries to ones using the same\n shape as the existing timeseries.\n\n It is used as a convenience to create an empty timeseries with a\n specified date range.\n\n if fmt use as shape\n\n usage:\n set_ones(self, fmt=None, new=False)\n\nts.set\\_zeros(fmt=None, new=False)\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\n::\n\n This function converts an existing timeseries to zeros using the same\n shape as the existing timeseries.\n\n It is used as a convenience to create an empty timeseries with a\n specified date range.\n\n if fmt use as shape\n\n usage:\n set_zeros(self, fmt=None, new=False)\n\nts.sort\\_by\\_date(reverse=False, force=False)\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\n::\n\n This function converts a timeseries to either date order or reverse\n date order.\n\n Usage:\n sort_by_date(self, reverse=False, force=False)\n\n If reverse is True, then order will be newest to oldest.\n If force is False, the assumption is made that comparing the first\n and last date will determine the current order of the timeseries. That\n would mean that unnecessary sorting can be avoided. Also, if the order\n needs to be reversed, the sort is changed via the less expensive\n reverse function.\n\n If dates and values are in no particular order, with force=True, the\n actual sort takes place.\n\n This function changes the data in-place.\n\nEvaluation\n~~~~~~~~~~\n\nts.daterange(fmt=None)\n^^^^^^^^^^^^^^^^^^^^^^\n\n::\n\n This function returns the starting and ending dates of the timeseries.\n\n Usage:\n\n self.daterange()\n (735963, 735972)\n\n self.daterange('str')\n ('2015-12-31', '2016-01-09')\n\n self.daterange('datetime')\n (datetime(2015, 12, 31, 0, 0),\n datetime.datetime(2016, 1, 9, 0, 0))\n\nts.start\\_date(fmt=None)\n^^^^^^^^^^^^^^^^^^^^^^^^\n\n::\n\n This function returns the starting date of the timeseries in its\n native value, timestamp or ordinal.\n\n If fmt is 'str' returns in string format\n If fmt is 'datetime' returns in string format\n\nts.end\\_date(fmt=None)\n^^^^^^^^^^^^^^^^^^^^^^\n\n::\n\n This funtcion returns the ending date of the timeseries in its native\n value, timestamp or ordinal.\n\n If fmt is 'str' returns in string format\n If fmt is 'datetime' returns in string format\n\nts.get\\_duped\\_dates()\n^^^^^^^^^^^^^^^^^^^^^^\n\n::\n\n This function pulls dates that are duplicated. This is to be used to\n locate timeseries that are faulty.\n\n Usage:\n get_duped_dates()\n\n returns [[odate1, count], [odate2, count]]\n\nts.series\\_direction()\n^^^^^^^^^^^^^^^^^^^^^^\n\n::\n\n if a lower row is a lower date, then 1 for ascending\n if a lower row is a higher date then -1 for descending\n\nts.get\\_date\\_series\\_type()\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\n::\n\n This function returns the date series type associated with the\n timeseries. The choices are TS_ORDINAL or TS_TIMESTAMP.\n\nts.if\\_dseries\\_match(ts)\n^^^^^^^^^^^^^^^^^^^^^^^^^\n\n::\n\n This function returns True if the date series are the same.\n\nts.if\\_tseries\\_match(ts)\n^^^^^^^^^^^^^^^^^^^^^^^^^\n\n::\n\n This function returns True if the time series are the same.\n\nUtilities\n~~~~~~~~~\n\nts.date\\_native(date)\n^^^^^^^^^^^^^^^^^^^^^\n\n::\n\n This awkwardly named function returns a date in the native format of\n of the timeseries, namely ordinal or timestamp.\n\nts.row\\_no(rowdate, closest=0, no\\_error=False)\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\n::\n\n Shows the row in the timeseries\n\n Usage:\n ts.row(rowdate=)\n ts.row(rowdate=)\n\n Returns an error if the date is not found in the index\n\n if closest is invoked:\n closest = 1\n find the closest date after the rowdate\n closest = -1\n find the closest date before the rowdate\n\n If no_error\n returns -1 instead of raising an error if the date was\n outside of the timeseries.\n\nts.get\\_datetime(date)\n^^^^^^^^^^^^^^^^^^^^^^\n\n::\n\n This function returns a date as a datetime object.\n This takes into account the type of date stored in **dseries**.\n\n Usage:\n self.get_datetime(date)\n\nts.lengths()\n^^^^^^^^^^^^\n\n::\n\n This function returns the lengths of both the date series and time\n series. Both numbers are included in case a mismatch has occurred.\n\nts.shape()\n^^^^^^^^^^\n\n::\n\n This function return the shape of the timeseries. This is a shortcut\n to putting in ts.tseries.shape.\n\nts.fmt\\_date(numericdate, dt\\_type, dt\\_fmt=None)\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\n::\n\n This static method accepts a date and converts it to\n the format used in the timeseries.\n\nts.make\\_arrays()\n^^^^^^^^^^^^^^^^^\n\n::\n\n Convert the date and time series lists (if so) to numpy arrays\n\nts.get\\_fromDB(\\*\\*kwargs)\n^^^^^^^^^^^^^^^^^^^^^^^^^^\n\n::\n\n This is just a stub to suggest a viable name for getting data from a\n database.\n\nts.save\\_toDB(\\*\\*kwargs):\n^^^^^^^^^^^^^^^^^^^^^^^^^^\n\n::\n\n This is just a stub to suggest a viable name for saving data to a\n database.\n\n\n\n", "description_content_type": "", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://sidorof.github.io/Thymus-timeseries/", "keywords": "timeseries,time series", "license": "MIT", "maintainer": "", "maintainer_email": "", "name": "thymus-timeseries", "package_url": "https://pypi.org/project/thymus-timeseries/", "platform": "", "project_url": "https://pypi.org/project/thymus-timeseries/", "project_urls": { "Homepage": "https://sidorof.github.io/Thymus-timeseries/" }, "release_url": "https://pypi.org/project/thymus-timeseries/0.1.4/", "requires_dist": [ "numpy", "check-manifest ; extra == 'dev'", "unittest ; extra == 'test'" ], "requires_python": "", "summary": "An intuitive library tracking dates and timeseries in common using NumPy arrays.", "version": "0.1.4" }, "last_serial": 5347734, "releases": { "0.1.0": [ { "comment_text": "", "digests": { "md5": "5d57d4be4789951d2469fde2c75c2dde", "sha256": "fd3078e59f60c789c284b3de68b5600309a140421435a79b03552f537f804e60" }, "downloads": -1, "filename": "thymus-timeseries-0.1.0.linux-x86_64.tar.gz", "has_sig": false, "md5_digest": "5d57d4be4789951d2469fde2c75c2dde", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 36435, "upload_time": "2016-09-03T18:34:35", "url": "https://files.pythonhosted.org/packages/7d/c3/0aa4805f69955b2bea48759fd618fd3a7c170685c68442d937400187d815/thymus-timeseries-0.1.0.linux-x86_64.tar.gz" }, { "comment_text": "", "digests": { "md5": "8b44e52b31efbc8ca90728442d47ed0c", "sha256": "ad757d46ae206c7f5f75adbe59587290b0da998b8e924eea799c4cfa80f524ba" }, "downloads": -1, "filename": "thymus-timeseries-0.1.0.tar.gz", "has_sig": false, "md5_digest": "8b44e52b31efbc8ca90728442d47ed0c", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 62212, "upload_time": "2016-09-03T18:34:39", "url": "https://files.pythonhosted.org/packages/a5/82/3d5aeb39b80894f088109d638a9697b89e9cbcfc6f4e15e4e116b4f3799e/thymus-timeseries-0.1.0.tar.gz" } ], "0.1.1": [ { "comment_text": "", "digests": { "md5": "0950d0817ec08d54dd56b4f38b94835a", "sha256": "aad5d79a24e01dae9f62f7b1c394db43afff26ce1b46008f4e0d5c85974b7973" }, "downloads": -1, "filename": "thymus-timeseries-0.1.1.tar.gz", "has_sig": false, "md5_digest": "0950d0817ec08d54dd56b4f38b94835a", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 62434, "upload_time": "2016-09-07T14:01:56", "url": "https://files.pythonhosted.org/packages/12/f8/96e69c8c74d5a3638e7661e4e59f790008018c4898279bd5fbfc471729b5/thymus-timeseries-0.1.1.tar.gz" } ], "0.1.4": [ { "comment_text": "", "digests": { "md5": "450a86303d93b998d6f33441f8c1c4b0", "sha256": "9316aab0e02a9e3242783ae3afd1f55eaf7c05e2b00e96321018ef2d8a631d31" }, "downloads": -1, "filename": "thymus_timeseries-0.1.4-py3-none-any.whl", "has_sig": false, "md5_digest": "450a86303d93b998d6f33441f8c1c4b0", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 29684, "upload_time": "2019-06-02T03:04:59", "url": "https://files.pythonhosted.org/packages/14/ab/d8cdbdaa624d8e6266505923f9e4d193d0d14afe0ecbbed65e40f462719b/thymus_timeseries-0.1.4-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "4fcf42665b393c1ba922d69cba4f4710", "sha256": "b0a236b27e7e3738a97253c17faf9071d3f695ccc94a197a5b71756c5d1c8dd1" }, "downloads": -1, "filename": "thymus-timeseries-0.1.4.tar.gz", "has_sig": false, "md5_digest": "4fcf42665b393c1ba922d69cba4f4710", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 140721, "upload_time": "2019-06-02T03:05:03", "url": "https://files.pythonhosted.org/packages/d5/4b/44f2270ecb356ca21540291984d41d25f024f0eb7ed76c41e2fc99339005/thymus-timeseries-0.1.4.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "450a86303d93b998d6f33441f8c1c4b0", "sha256": "9316aab0e02a9e3242783ae3afd1f55eaf7c05e2b00e96321018ef2d8a631d31" }, "downloads": -1, "filename": "thymus_timeseries-0.1.4-py3-none-any.whl", "has_sig": false, "md5_digest": "450a86303d93b998d6f33441f8c1c4b0", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 29684, "upload_time": "2019-06-02T03:04:59", "url": "https://files.pythonhosted.org/packages/14/ab/d8cdbdaa624d8e6266505923f9e4d193d0d14afe0ecbbed65e40f462719b/thymus_timeseries-0.1.4-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "4fcf42665b393c1ba922d69cba4f4710", "sha256": "b0a236b27e7e3738a97253c17faf9071d3f695ccc94a197a5b71756c5d1c8dd1" }, "downloads": -1, "filename": "thymus-timeseries-0.1.4.tar.gz", "has_sig": false, "md5_digest": "4fcf42665b393c1ba922d69cba4f4710", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 140721, "upload_time": "2019-06-02T03:05:03", "url": "https://files.pythonhosted.org/packages/d5/4b/44f2270ecb356ca21540291984d41d25f024f0eb7ed76c41e2fc99339005/thymus-timeseries-0.1.4.tar.gz" } ] }