I have a large library (four packages) of data processing code that I have written over the last 12 months. I am quite new to python and would like to see if I am doing things correctly.
This utility/convenience code is currently kept in a module called utils that is imported in many places (for an example, see this question). I thought it would be a simple place to start as it has no dependency on my other code.
The purpose of the first two functions is to switch between cumulative energy meter readings and actual energy consumption values.
The second two functions allow me to move between datetime and timestamp values, usually because I store datetime information in numpy arrays of timestamps for some calculations but need them as datetimes for formatting.
The switching between gaps and flags is useful because data interpolation identifies missing data and records it as boolean numpy arrays (flags) but I often need to identify contiguous chunks of missing data.
import numpy as np, datetime, time, logging
def movement_from_integ(integ):
return np.append(np.nan, np.diff(integ))
def integ_from_movement(movement):
return np.append(0.0, np.cumsum(movement[1:]))
def timestamp_from_datetime(dt):
return np.array([time.mktime(d.timetuple()) for d in dt])
def datetime_from_timestamp(ts):
return [datetime.datetime.fromtimestamp(s) for s in ts]
def gaps_from_flags(flags, ts):
logger = logging.getLogger('gaps_from_flags')
"""given missing flags and timestamps produces a list of contiguous gaps"""
_gap = {'from': None, 'to': None}
result = []
for i in xrange(len(flags)):
if not flags[i]:
logger.debug(flags[i])
if _gap['from'] != None:
result.append(_gap)
logger.debug('Gap saved [%s -> %s]' % (_gap['from'], _gap['to']))
_gap = {'from': None, 'to': None}
else:
if _gap['from'] == None:
logger.debug('%s: New gap initialised at %s' % (flags[i], ts[i]))
_gap['from'] = ts[i]
logger.debug('%s: Gap extended to %s' % (flags[i], ts[i]))
_gap['to'] = ts[i]
if _gap['from'] != None:
result.append(_gap)
logger.debug('Gap saved [%s -> %s]' % (_gap['from'], _gap['to']))
return result
def flags_from_gaps(gaps, ts):
"""given gaps and timestamps produces an array of boolean values indicating whether data are missing at each timestamp"""
flags = np.array([False]*len(ts), dtype=bool)
for g in gaps:
a = (ts >= g['from']) & (ts <=g['to'])
flags[a] = True
return flags
Is it OK to keep a set of functions like this in an otherwise object oriented project?
Am I doing the flags->gaps->flags processing in a sensible way?
I am aware there is such a thing as a masked array in numpy but I'm not sure how much work it would be to convert my entire code base over to using it.