Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting 'Day of Year' array from a numpy array inputs in Python

I have data in numpy array that include Year, Month, and Day as columns, I want to calculate the Julian day or the 'Day of Year' (DOY) that should be a numpy array as well.

The formula to calculate DOY is:

import datetime
y = 2017
m = 4
d = 13
DOY = int(dt.datetime(y, m, d).strftime('%j')

it will print 103

Assuming we have y_ar, m_ar, and d_ar as the arrays of years, months, and days,

I tried this:

julians = int(dt.datetime(y_ar, m_ar, d_ar).strftime('%j'))

it gives my TypeError: only length-1 arrays can be converted to Python scalars I tried something else which succeeded:

julians = np.array(map(lambda (y, m, d): int(dt.datetime(y, m, d).strftime('%j')), zip(y_ar, m_ar, d_ar)))

Although it gives me what I want, but I feel that it is a bit time consuming to take element by element, then to output a list, then to convert it back no numpy array!

Can anyone help me determine why the error occurs, and wheather there is a better, faster way to do so?

Sample arrays to help to test the solution:

y_ar = np.array([1990, 2000, 2015, 2017])
m_ar = np.array([5, 8, 1, 12])
d_ar = np.array([13, 7, 30, 29])
like image 663
Mohammad ElNesr Avatar asked Sep 08 '26 05:09

Mohammad ElNesr


1 Answers

Using datetime in combination with numpy arrays will be slow in general because it will create arrays with dtype=object. However, starting with version 1.7.0 numpy has a builtin datetime64 type.

It is a bit strange to use, but this seems to work:

original solution (list comprehension instead of map)

import datetime as dt

y_ar = np.array([1990, 2000, 2015, 2017])
m_ar = np.array([5, 8, 1, 12])
d_ar = np.array([13, 7, 30, 29])

julians_ref = np.array([int(dt.datetime(y, m, d).strftime('%j')) for y, m, d in zip(y_ar, m_ar, d_ar)])

native numpy solution

y_ar = (y_ar - 1970).astype('M8[Y]')
m_ar = (m_ar - 1).astype('m8[M]')
d_ar = (d_ar - 1).astype('m8[D]')

date_ar = y_ar + m_ar + d_ar  # full date
julians = date_ar - y_ar + 1  # days since first day of the year

print(julians_ref)  # [133 220  30 363]
print(julians)  # [133 220  30 363]

julians = int(dt.datetime(y_ar, m_ar, d_ar).strftime('%j'))

it gives my TypeError: only length-1 arrays can be converted to Python scalars I tried

This is because datetime.datetime is not aware of numpy arrays. is expects a scalar (=a single) value for year, month, and day. When the interpreter tries to convert an array into a scalar this fails, unless the array is equivalent to a scalar (it has only one element).

like image 109
MB-F Avatar answered Sep 10 '26 18:09

MB-F



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!