如何在熊猫中将日历年转换为水年

Posted

技术标签:

【中文标题】如何在熊猫中将日历年转换为水年【英文标题】:How to convert calendar year to water year in pandas 【发布时间】:2019-02-05 22:00:08 【问题描述】:

这个问题已经用 R 解决了,但是我还没有看到 Python 有用的例子。我想了解如何将日历年(1990 年 1 月 1 日至 2010 年 12 月 31 日)排放数据转换为水年数据(即 1990 年 1 月 1 日至 2010 年 9 月 31 日)。感谢您的帮助。

【问题讨论】:

df['date'] = df['date'] + pd.DateOffset(months=9) 【参考方案1】:

使用来自USGS 03335500 WABASH RIVER AT LAFAYETTE, IN的数据

日期:2001-10-01 - 2017-09-31

'datetime' 列必须设置为datetimedtype,通过使用parse_dates 导入数据,或在导入数据后使用pd.to_datetime()

使用pandas.Series.where确定水年。

使用.dt accessor 提取monthyear 数字。 如果月份数小于10,则水年为.dt.year,否则,水年为.dt.year + 1 对于此 DataFrame 中的 282757 行,比来自此 answer 的 .apply 函数快 13 倍。
import pandas as pd

# Load the data
df = pd.read_csv('WabashRiver_Flow.csv', parse_dates=['datetime'])

# drop na values
df = df.dropna()

# determine the water year
df['water_year'] = df.datetime.dt.year.where(df.datetime.dt.month < 10, df.datetime.dt.year + 1)

# display(df.head())
  agency_cd  site_no            datetime tz_cd  discharge_cfps  water_year
0      USGS  3335500 2001-10-01 00:00:00   EST            2610        2002
1      USGS  3335500 2001-10-01 01:00:00   EST            2610        2002
2      USGS  3335500 2001-10-01 02:00:00   EST            2610        2002
3      USGS  3335500 2001-10-01 03:00:00   EST            2630        2002
4      USGS  3335500 2001-10-01 04:00:00   EST            2630        2002

按水年计算平均流量

annual_mean_discharge_rate = df.groupby('water_year')[['discharge_cfps']].mean()

# display(annual_mean_discharge_rate)
            discharge_cfps
water_year                
2002           9379.829589
2003           8678.468324
2004           8562.505005
2005           8928.776256
2006           6710.805312
2007          10331.564789
2008          10626.336623
2009           8972.046607
2010           5298.569557
2011          10519.540869
2012           9013.624424
2013           9007.924205
2014           9079.561658
2015          12267.393776
2016           6445.875810
2017          10240.721464

annual_mean_discharge_rate.plot.bar(figsize=(8, 6), xlabel='Water Year', ylabel='Discharge (cubic feet / sec)', legend=False)


%%timeit比较

pandas.Series.wherepandas.Series.applynp.where 相比,以及来自另一个答案的功能。 .Series.where 是矢量化的,而 .apply 不是。
import numpy as np

# function from other answer; updated because pd.datetime is deprecated
def assign_wy(row):
    if row.month>=10:
        return(row.year + 1)
    else:
        return(row.year)


%%timeit
df.datetime.dt.year.where(df.datetime.dt.month < 10, df.datetime.dt.year + 1)
[out]:
66.9 ms ± 1.67 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

%%timeit
df.datetime.apply(lambda v: np.where(v.month >= 10, v.year + 1, v.year))
[out]:
1.38 s ± 23 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

%%timeit
df.datetime.apply(lambda x: assign_wy(x))
[out]:
861 ms ± 9.3 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

【讨论】:

【参考方案2】:

您可以使用apply 并编写自己的函数来创建一个新列WY

如果你有df:

                 Date  Discharge
0 2011-10-01 00:00:00  0.0
1 2011-10-01 01:00:00  0.0
2 2011-10-01 02:00:00  0.0
3 2011-10-01 03:00:00  0.0
4 2011-10-01 04:00:00  0.0

然后:

import pandas as pd

def assign_wy(row):
    if row.Date.month>=10:
        return(pd.datetime(row.Date.year+1,1,1).year)
    else:
        return(pd.datetime(row.Date.year,1,1).year)

df['WY'] = df.apply(lambda x: assign_wy(x), axis=1)

【讨论】:

以上是关于如何在熊猫中将日历年转换为水年的主要内容,如果未能解决你的问题,请参考以下文章

如何在熊猫中将列转换为一个日期时间列?

如何在熊猫中将月度数据转换为季度

如何在熊猫中将字符串日期转换为数字[重复]

如何在多级列(熊猫)中将一级索引转换为新级别

如何在熊猫中将 4 位数字转换为小时:分钟时间格式

如何在熊猫中将 N/A (NaT) 转换为 0