2
votes

Ajout d'un mois à datetime64 avec timedelta

Quand j'essaye ceci:

1996-01-30 10:29:06.

Je m'attends à voir

1996-01-31

mais à la place j'obtiens

>>> a = numpy.datetime64('1995-12-31')
>>> b = a + pandas.Timedelta(1, unit='M')
>>> print(b)

Une idée pourquoi? Merci beaucoup.


0 commentaires

5 Réponses :


1
votes

Un delta temporel d'un mois est la longueur d'une année divisée par 12.

Vous devez examiner votre date et ajouter la quantité appropriée de jours. Vous pouvez également incrémenter le numéro du mois (en passant à l'année suivante, si nécessaire) et laisser le numéro du jour inchangé.


1 commentaires

"Un delta temporel d'un mois est la longueur d'une année divisée par 12." Cela semble être les pandas (mais pas numpy ) façon de penser.



0
votes

Vous pouvez remplacer la partie day pour imiter l'exigence.

import numpy as np
import pandas as pd
a = np.datetime64('1995-12-31')
b = a + pd.Timedelta(1, unit='M')
print(b.replace(day=pd.to_datetime(a).day))

Utilisez .date () si vous n'êtes intéressé que par la partie date


0 commentaires

0
votes

Il y a une ambiguïté inhérente à l'ajout d'un «mois» à une heure, car les mois varient en longueur.

Créez une date:

In [254]: b = a.item()                                                          
In [255]: b                                                                     
Out[255]: datetime.date(1995, 12, 31)

en ajoutant des jours à cela fonctionne très bien:

In [251]: a.astype('datetime64[M]')                                             
Out[251]: array('1995-12', dtype='datetime64[M]')
In [252]: a.astype('datetime64[M]') + np.array(1, 'timedelta64[M]')             
Out[252]: numpy.datetime64('1996-01')

L'ajout d'un mois génère une erreur:

In [250]: a + np.array(1, 'timedelta64[M]')                                     
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-250-a331f724d7e7> in <module>
----> 1 a + np.array(1, 'timedelta64[M]')

TypeError: Cannot get a common metadata divisor for NumPy datetime metadata [D] and [M] because they have incompatible nonlinear base time units

Nous pourrions lancer un comme un mois - alors cela fonctionne:

In [249]: a + np.array(31, 'timedelta64[D]')                                    
Out[249]: numpy.datetime64('1996-01-31')

Changer le mois dans l'objet datetime correspondant peut être la manière la plus propre de travailler avec ceci: p >

In [247]: a = np.array('1995-12-31','datetime64[D]')                            
In [248]: a                                                                     
Out[248]: array('1995-12-31', dtype='datetime64[D]')

Je n'ai pas suffisamment travaillé avec les objets datetime pour effectuer le changement sans consulter ses documents.


0 commentaires

0
votes

Une manière concise d'ajouter un mois en laissant le jour inchangé si possible serait de tronquer en mois, d'ajouter 1 puis de lire ce qui a été tronqué:

>>> b = np.minimum((am + 1) + (a - am), (am + 2) - np.timedelta64(1, 'D'))
>>> b
numpy.datetime64('1995-02-28')

De toute évidence, cela ne fonctionne pas si le le jour d'origine n'existe pas le mois suivant:

>>> a = np.datetime64('1995-01-31')
>>> am = a.astype('M8[M]')
>>> b = (am + 1) + (a - am)
>>> b
numpy.datetime64('1995-03-03')

Mais on ne sait pas quelle devrait être la réponse dans ce cas, de toute façon.

Une possibilité serait être au maximum au dernier jour de ce mois:

>>> a = np.datetime64('1995-12-31')                                                              
>>> am = a.astype('M8[M]')                                                    
>>> b = (am + 1) + (a - am)                                                        
>>> b                                                                                            
numpy.datetime64('1996-01-31')                                                                   


0 commentaires

5
votes

Comme déjà mentionné @hpaulj dans sa réponse:

Il y a une ambiguïté inhérente à l'ajout d'un «mois» à une heure, car les mois varient en longueur.

De plus, comme à la version 0.25.0 , Pandas a abandonné le support pour l'utilisation des unités M (mois) et Y (années) dans les fonctions Timedelta .

Mais comme indiqué dans les pandas officiels guide , vous devez utiliser Timedelta pour la durée absolue et DateOffset pour relative durée qui respecte l'arithmétique du calendrier, qui est exactement ce dont nous avons besoin dans votre cas:

Le DateOffset de base agit de manière similaire à dateutil.relativedelta ( documentation relativedelta ) qui décale une date et une heure de la durée de calendrier correspondante spécifiée.

Donc, en utilisant votre exemple:

In [7]: a = numpy.datetime64('1995-12-31')
      : b = pandas.Timestamp(a) + pandas.DateOffset(months=1)
      : b
Out[7]: Timestamp('1996-01-31 00:00:00')

NB: vous pouvez toujours utiliser la méthode to_numpy , si vous avez besoin de convertir pandas.Timestamp à numpy.datetime64.


0 commentaires