从 Pandas Datetime 列中分别提取月份和年份
- 2024-12-12 08:40:00
- admin 原创
- 204
问题描述:
我有一个数据框,df
包含以下列:
ArrivalDate
936 2012-12-31
938 2012-12-29
965 2012-12-31
966 2012-12-31
967 2012-12-31
968 2012-12-31
969 2012-12-31
970 2012-12-29
971 2012-12-31
972 2012-12-29
973 2012-12-29
该列的元素是pandas.tslib.Timestamp
类型。我想要提取年份和月份。
这是我尝试过的:
df['ArrivalDate'].resample('M', how = 'mean')
这会引发以下错误:
Only valid with DatetimeIndex or PeriodIndex
然后我尝试:
df['ArrivalDate'].apply(lambda(x):x[:-2])
这会引发以下错误:
'Timestamp' object has no attribute '__getitem__'
我当前的解决方案是
df.index = df['ArrivalDate']
然后,我可以使用索引重新采样另一列。
但我仍然想要一种重新配置整个列的方法。有什么想法吗?
解决方案 1:
如果您希望新列分别显示年份和月份,您可以这样做:
df['year'] = pd.DatetimeIndex(df['ArrivalDate']).year
df['month'] = pd.DatetimeIndex(df['ArrivalDate']).month
或者...
df['year'] = df['ArrivalDate'].dt.year
df['month'] = df['ArrivalDate'].dt.month
然后,您可以将其组合起来或者按原样使用它们。
解决方案 2:
必须df['date_column']
采用日期时间格式。
df['month_year'] = df['date_column'].dt.to_period('M')
您还可以使用D
天、2M
2 个月等作为不同的采样间隔,并且如果有人拥有带时间戳的时间序列数据,我们可以采用细粒度的采样间隔,例如45Min
45 分钟、15Min
15 分钟采样等。
解决方案 3:
您可以直接访问year
和month
属性,或者请求datetime.datetime
:
In [15]: t = pandas.tslib.Timestamp.now()
In [16]: t
Out[16]: Timestamp('2014-08-05 14:49:39.643701', tz=None)
In [17]: t.to_pydatetime() #datetime method is deprecated
Out[17]: datetime.datetime(2014, 8, 5, 14, 49, 39, 643701)
In [18]: t.day
Out[18]: 5
In [19]: t.month
Out[19]: 8
In [20]: t.year
Out[20]: 2014
合并年份和月份的一种方法是使用整数对它们进行编码,例如:201408
表示 2014 年 8 月。沿着整列,您可以这样做:
df['YearMonth'] = df['ArrivalDate'].map(lambda x: 100*x.year + x.month)
或其许多变体。
不过,我不太喜欢这样做,因为这会使以后的日期对齐和算术变得很麻烦,尤其是对于那些没有使用相同约定的代码或数据的人来说。更好的方法是选择月份中的日期约定,例如最后一个非美国假日工作日或第一天等,并将数据保留为具有所选日期约定的日期/时间格式。
该calendar
模块可用于获取特定日期的数值,例如最后一个工作日。然后你可以执行以下操作:
import calendar
import datetime
df['AdjustedDateToEndOfMonth'] = df['ArrivalDate'].map(
lambda x: datetime.datetime(
x.year,
x.month,
max(calendar.monthcalendar(x.year, x.month)[-1][:5])
)
)
如果您恰巧正在寻找一种方法来解决更简单的问题,即将日期时间列格式化为一些字符串表示形式,那么您可以使用类strftime
中的函数datetime.datetime
,如下所示:
In [5]: df
Out[5]:
date_time
0 2014-10-17 22:00:03
In [6]: df.date_time
Out[6]:
0 2014-10-17 22:00:03
Name: date_time, dtype: datetime64[ns]
In [7]: df.date_time.map(lambda x: x.strftime('%Y-%m-%d'))
Out[7]:
0 2014-10-17
Name: date_time, dtype: object
解决方案 4:
如果您想要唯一的月份年份对,使用 apply 就非常方便了。
df['mnth_yr'] = df['date_column'].apply(lambda x: x.strftime('%B-%Y'))
在一列中输出月份和年份。
不要忘记先将格式更改为日期时间,我通常会忘记。
df['date_column'] = pd.to_datetime(df['date_column'])
解决方案 5:
单行:添加一个包含“年-月”对的列:(
在操作之前,“pd.to_datetime”首先将列数据类型更改为日期时间)
df['yyyy-mm'] = pd.to_datetime(df['ArrivalDate']).dt.strftime('%Y-%m')
因此,对于额外的“年份”或“月份”列:
df['yyyy'] = pd.to_datetime(df['ArrivalDate']).dt.strftime('%Y')
df['mm'] = pd.to_datetime(df['ArrivalDate']).dt.strftime('%m')
解决方案 6:
您可以先使用pandas.to_datetime转换日期字符串,这样您就可以访问所有numpy datetime 和 timedelta功能。例如:
df['ArrivalDate'] = pandas.to_datetime(df['ArrivalDate'])
df['Month'] = df['ArrivalDate'].values.astype('datetime64[M]')
解决方案 7:
@KieranPC 的解决方案是 Pandas 的正确方法,但对于任意属性来说不易扩展。为此,您可以getattr
在生成器理解中使用并结合使用pd.concat
:
# input data
list_of_dates = ['2012-12-31', '2012-12-29', '2012-12-30']
df = pd.DataFrame({'ArrivalDate': pd.to_datetime(list_of_dates)})
# define list of attributes required
L = ['year', 'month', 'day', 'dayofweek', 'dayofyear', 'weekofyear', 'quarter']
# define generator expression of series, one for each attribute
date_gen = (getattr(df['ArrivalDate'].dt, i).rename(i) for i in L)
# concatenate results and join to original dataframe
df = df.join(pd.concat(date_gen, axis=1))
print(df)
ArrivalDate year month day dayofweek dayofyear weekofyear quarter
0 2012-12-31 2012 12 31 0 366 1 4
1 2012-12-29 2012 12 29 5 364 52 4
2 2012-12-30 2012 12 30 6 365 52 4
解决方案 8:
感谢jaknap32,我想根据年份和月份汇总结果,因此这样做有效:
df_join['YearMonth'] = df_join['timestamp'].apply(lambda x:x.strftime('%Y%m'))
输出很简洁:
0 201108
1 201108
2 201108
解决方案 9:
假设ArrivalDate
已经是datetime64[ns]
dtype 列(如果不使用 进行转换pd.to_datetime(df['ArrivalDate'])
),
如果你喜欢更快的方法,可以使用 numpy(由于开销较小,因此比 pandas 更快):1
df['year'] = df['ArrivalDate'].to_numpy('datetime64[Y]').view('int64') + 1970
df['month'] = df['ArrivalDate'].to_numpy('datetime64[M]').view('int64') % 12 + 1
如果你喜欢单行代码,请使用
timetuple()
:2
df[['year', 'month']] = df['ArrivalDate'].apply(lambda x: x.timetuple()[:2]).tolist()
# or use a list comprehension
df[['year', 'month']] = [x.timetuple()[:2] for x in df['ArrivalDate'].tolist()]
1可以使用方法datetime64[ns]
以特定数据类型访问pandas 列的底层 numpy 数组。一旦转换为 numpy 数组,它就可以使用 被视为自 UNIX 纪元以来的年数,因此将 1970 添加到结果中会产生正确的年份。同样,可以使用+和正确 dtypes的组合将列转换为自 UNIX 纪元以来的月份数。然后,因为我们想要找到月份,所以我们取除以 12 后的余数并加 1。datetime64[Y]
`.to_numpy().view('int64')
datetime64[ns]to_numpy()
view()`
2 Pandas 的Timestamp
对象相当于 Python 的datetime
对象,所以它还定义了.timetuple()
一个方法,返回一个命名元组,其前两个元素是年份和月份,所以切片前两个元素就可以了。
解决方案 10:
df['year_month']=df.datetime_column.apply(lambda x: str(x)[:7])
这对我来说很完美,我不认为熊猫会将结果字符串日期解释为日期,但是当我进行绘图时,它非常清楚我的议程并且字符串 year_month 的顺序正确... 一定会喜欢熊猫!
解决方案 11:
然后我尝试:
df['ArrivalDate'].apply(lambda(x):x[:-2])
我认为这里正确的输入应该是字符串。
df['ArrivalDate'].astype(str).apply(lambda(x):x[:-2])
扫码咨询,免费领取项目管理大礼包!