将Matlab的datenum格式转换为Python

Fre*_*d S 14 python matlab

我刚开始从Matlab迁移到Python 2.7,我在阅读我的.mat文件时遇到了一些麻烦.时间信息以Matlab的datenum格式存储.对于那些不熟悉它的人:

序列日期编号表示日历日期,作为自固定基准日期以来经过的天数.在MATLAB中,序列号1是1月1日0000.

MATLAB还使用连续时间来表示从午夜开始的几天的分数; 例如,下午6点等于0.75连续日.所以MATLAB中的字符串'31 -Oct-2003,6:00 PM'是日期号731885.75.

(取自Matlab文档)

我想将其转换为Pythons时间格式,我找到了本教程.简而言之,作者说明了这一点

如果你使用python解析它,datetime.fromordinal(731965.04835648148)那么结果可能看起来合理[...]

(在任何进一步的转换之前),这对我不起作用,因为datetime.fromordinal需要一个整数:

>>> datetime.fromordinal(731965.04835648148) 
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: integer argument expected, got float
Run Code Online (Sandbox Code Playgroud)

虽然我可以将它们整理成日常数据,但实际上我需要输入精确的时间序列.有没有人有这个问题的解决方案?我想避免重新格式化我的.mat文件,因为它们有很多,我的同事也需要使用它们.

如果它有所帮助,其他人则要求反过来.可悲的是,我对Python太新了,无法真正理解那里发生的事情.

/ edit(2012-11-01):这已在上面发布的教程中修复.

car*_*sdc 18

您链接到解决方案,它有一个小问题.就是这个:

python_datetime = datetime.fromordinal(int(matlab_datenum)) + timedelta(days=matlab_datenum%1) - timedelta(days = 366)
Run Code Online (Sandbox Code Playgroud)

可以在这里找到更长的解释

  • 我必须将 timedelta 的输入也转换为 int:`timedelta(days=int(matlab_datenum%1))`。否则我得到:`TypeError:timedelta天组件不支持的类型:numpy.int32` (2认同)

Ric*_*ell 10

为了防止对其他人有用,这里有一个从Matlab mat文件加载时间序列数据的完整示例,使用carlosdc的答案(定义为函数)将Matlab datenums的向量转换为日期时间对象列表,然后绘制为熊猫时间序列:

from scipy.io import loadmat
import pandas as pd
import datetime as dt
import urllib

# In Matlab, I created this sample 20-day time series:
# t = datenum(2013,8,15,17,11,31) + [0:0.1:20];
# x = sin(t)
# y = cos(t)
# plot(t,x)
# datetick
# save sine.mat

urllib.urlretrieve('http://geoport.whoi.edu/data/sine.mat','sine.mat');

# If you don't use squeeze_me = True, then Pandas doesn't like 
# the arrays in the dictionary, because they look like an arrays
# of 1-element arrays.  squeeze_me=True fixes that.

mat_dict = loadmat('sine.mat',squeeze_me=True)

# make a new dictionary with just dependent variables we want
# (we handle the time variable separately, below)
my_dict = { k: mat_dict[k] for k in ['x','y']}

def matlab2datetime(matlab_datenum):
    day = dt.datetime.fromordinal(int(matlab_datenum))
    dayfrac = dt.timedelta(days=matlab_datenum%1) - dt.timedelta(days = 366)
    return day + dayfrac

# convert Matlab variable "t" into list of python datetime objects
my_dict['date_time'] = [matlab2datetime(tval) for tval in mat_dict['t']]

# print df
<class 'pandas.core.frame.DataFrame'>
DatetimeIndex: 201 entries, 2013-08-15 17:11:30.999997 to 2013-09-04 17:11:30.999997
Data columns (total 2 columns):
x    201  non-null values
y    201  non-null values
dtypes: float64(2)

# plot with Pandas
df = pd.DataFrame(my_dict)
df = df.set_index('date_time')
df.plot()
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述


jon*_*nas 6

使用pandas,您可以将datenum值的整个数组转换为小数部分:

import numpy as np
import pandas as pd
datenums = np.array([737125, 737124.8, 737124.6, 737124.4, 737124.2, 737124])
timestamps = pd.to_datetime(datenums-719529, unit='D')
Run Code Online (Sandbox Code Playgroud)

值719529是Unix历元开始(1970-01-01),这是默认的datenum值originpd.to_datetime()

我使用以下Matlab代码进行了设置:

datenum('1970-01-01')  % gives 719529
datenums = datenum('06-Mar-2018') - linspace(0,1,6)  % test data
datestr(datenums)  % human readable format
Run Code Online (Sandbox Code Playgroud)


Dou*_*gal 5

numpy.datetime64这是一种使用, 而不是来转换它们的方法datetime

origin = np.datetime64('0000-01-01', 'D') - np.timedelta64(1, 'D')
date = serdate * np.timedelta64(1, 'D') + origin
Run Code Online (Sandbox Code Playgroud)

这适用于serdate单个整数或整数数组。