【问题标题】:Renaming months from number to name in pandas在熊猫中将月份从数字重命名为名称
【发布时间】:2020-09-02 15:51:58
【问题描述】:

我有以下数据框:

High    Low Open    Close   Volume  Adj Close   year    pct_day
month   day                             
1   1   NaN NaN NaN NaN NaN NaN 2010.0  0.000000
2   7869.853149 7718.482498 7779.655014 7818.089966 7.471689e+07    7818.089966 2010.0  0.007826
3   7839.965652 7719.758224 7775.396255 7777.940002 8.185879e+07    7777.940002 2010.0  0.002582
4   7747.175260 7624.540007 7691.152083 7686.288672 1.018877e+08    7686.288672 2010.0  -0.000744
5   7348.487095 7236.742135 7317.313616 7287.688546 1.035424e+08    7287.688546 2010.0  -0.002499
... ... ... ... ... ... ... ... ... ...
12  27  7849.846680 7760.222526 7810.902051 7798.639258 4.678145e+07    7798.639258 2009.5  -0.000833
28  7746.209996 7678.152204 7713.497907 7710.449358 4.187133e+07    7710.449358 2009.5  0.000578
29  7357.001540 7291.827806 7319.393874 7338.938345 4.554891e+07    7338.938345 2009.5  0.003321
30  7343.726938 7276.871507 7322.123779 7302.545316 3.967812e+07    7302.545316 2009.5  -0.000312
31  NaN NaN NaN NaN NaN NaN 2009.5  0.000000

由于从上面粘贴的数据帧中看不清楚,下面是一个快照:

月份是 1,2 3 ... 是否可以将月份索引重命名为 Jan Feb Mar 格式?

编辑:

我很难实现@ChihebNexus 的示例

我的代码如下,因为它是一个日期时间:

full_dates = pd.date_range(start, end)
data = data.reindex(full_dates)
data['year'] = data.index.year
data['month'] = data.index.month
data['week'] = data.index.week
data['day'] = data.index.day
data.set_index('month',append=True,inplace=True)
data.set_index('week',append=True,inplace=True)
data.set_index('day',append=True,inplace=True)
df = data.groupby(['month', 'day']).mean()

【问题讨论】:

  • @Raju 您能否详细说明一下,我不确定您所说的替换命令是什么意思
  • @newcoder,你能更好地了解你的数据框吗?看起来您的年份是整数,而月份和日期是索引。我建议从这 3 列中创建一个日期,并使用 strftime 从该新列中提取月份名称。看看docs.python.org/3/library/…
  • df.replace({'month': {1:' jan', 2: 'feb',....}})

标签: python python-3.x pandas


【解决方案1】:

我会使用 calendar 和 pd.CategoricalDtype 来确保排序正常工作。

import pandas as pd
import numpy as np
import calendar

#Create dummy dataframe
dateindx = pd.date_range('2019-01-01', '2019-12-31', freq='D')

df = pd.DataFrame(np.random.randint(0,1000, (len(dateindx), 5)), 
             index=pd.MultiIndex.from_arrays([dateindx.month, dateindx.day]),
             columns=['High', 'Low','Open', 'Close','Volume'])

#Use calendar library for abbreviations and order
dd=dict((enumerate(calendar.month_abbr)))

#rename level zero of multiindex
df = df.rename(index=dd,level=0)

#Create calendar month data type with order for sorting
cal_dtype = pd.CategoricalDtype(list(calendar.month_abbr), ordered=True)

#Change the dtype of the level zero index
df.index = df1.index.set_levels(df.index.levels[0].astype(cal_dtype), level=0)
df

输出:

        High  Low  Open  Close  Volume
Jan 1    501  720   671    943     586
    2    410   67   207    945     284
    3    473  481   527    415     852
    4    157  809   484    592     894
    5    294   38   458     62     945
...      ...  ...   ...    ...     ...
Dec 27   305  354   347      0     726
    28   764  987   564    260      72
    29   730  151   846    137     118
    30   999  399   634    674      81
    31   347  980   441    600     676

[365 rows x 5 columns]

【讨论】:

    【解决方案2】:

    例如,如果我们有这个 DataFrame,我们可以在这个 datetime format table 中使用 datetime 包,如下例所示:

    import pandas as pd
    from datetime import datetime
    
    df = pd.DataFrame(range(1, 13), columns=['month']) 
    df['month'] = df.apply(
        lambda row: '{:%b}'.format(datetime.strptime(str(row['month']), '%m')),
        axis=1
    ) 
    print(df)
    

    输出:

    0    Jan
    1    Feb
    2    Mar
    3    Apr
    4    May
    5    Jun
    6    Jul
    7    Aug
    8    Sep
    9    Oct
    10   Nov
    11   Dec
    

    更新:正如@Ch3steR 建议的那样。您正在使用MultiIndex DataFrame。 所以,这里有一个例子,你可以如何修改它的一级索引:

    import pandas as pd
    import numpy as np
    from datetime import datetime
    
    tuples = [(1, 10), (1, 12), (1, 13), (2, 1), (2, 20), (2, 10)]
    index  = pd.MultiIndex.from_tuples(tuples, names=['month', 'day'])
    serie = pd.Series(np.random.randn(len(tuples)), index=index)
    df = pd.DataFrame(serie, columns=['data']) 
    
    print(df)
    
                   data
    month day          
    1     10  -0.463804
          12   1.979072
          13   0.087430
    2     1    0.928077
          20  -0.697795
          10  -0.275762
    
    idx = pd.Index(df.index).get_level_values(0)
    # Set new index, but keep the multindex levels
    df = df.set_index(pd.MultiIndex.from_tuples(((
            '{:%b}'.format(datetime.strptime(str(k), '%m')), 
            v 
    ) for k, v in idx), names=['month', 'day']), ['month', 'day']) 
    print(df)
    
                   data
    month day          
    Jan   10  -0.463804
          12   1.979072
          13   0.087430
    Feb   1    0.928077
          20  -0.697795
          10  -0.275762
    

    更新2:

    我发现您很难将我的答案实施到您的代码中。这就是为什么我进行此更新以向您展示如何在您添加到问题的代码中实现我的代码。这是一个例子:

    from datetime import datetime
    import pandas as pd
    
    
    start = '1/4/2020'
    end = '3/5/2020'
    
    data = pd.DataFrame()
    full_dates = pd.date_range(start, end)
    data = data.reindex(full_dates)
    data['year'] = data.index.year
    data['month'] = data.index.month
    data['week'] = data.index.week
    data['day'] = data.index.day
    data.set_index('month', append=True, inplace=True)
    data.set_index('week', append=True, inplace=True)
    data.set_index('day', append=True, inplace=True)
    df = data.groupby(['month', 'day']).mean()
    idx = pd.Index(df.index).get_level_values(0)
    df = df.set_index(pd.MultiIndex.from_tuples(((
        '{:%b}'.format(datetime.strptime(str(k), '%m')),
        v
    ) for k, v in idx), names=['month', 'day']), ['month', 'day'])
    print(df)
    

    输出:

               year
    month day      
    Jan   4    2020
          5    2020
          6    2020
          7    2020
          8    2020
    ...         ...
    Mar   1    2020
          2    2020
          3    2020
          4    2020
          5    2020
    
    [62 rows x 1 columns]
    

    【讨论】:

    • OP 有multiIndex,其中级别 0 是月份,级别 1 是一天。他用清晰的照片更新了问题。
    • 他可以使用df.rename并将级别指定为0,并提供一个dict进行转换,如{0:'Jan',1:'Feb',...}
    • @Ch3steR 感谢您的 cmets。对于multiIndex,我将添加另一个示例,OP 如何处理它们。 YESrename 可以是一个解决方案,但就我个人而言,我不会在生产程序中使用它。维护这样的列表会很痛苦......如果你明白我的意思。
    • 是的,完全同意。这就是我将其添加为评论的原因。可以使用pd Index.get_level_values 提取级别 0 索引
    • 没有 2 月 30 日 ;-)(至少目前没有,但谁知道...)
    【解决方案3】:

    使用dt.month_name in pandas.Series 将月份数字转换为名称很容易,即:

    pd.to_datetime(np.arange(12)+1, format='%m').to_series().dt.month_name().str[:3].values
    

    输出:

    array(['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep',
           'Oct', 'Nov', 'Dec'], dtype=object)
    

    如果你想用它来更新你的索引,那就有点复杂了,因为pd.MultiIndex是一个不可变类型。应该可以在数据框中添加带有月份名称和日期的新列,然后用新索引替换旧索引,即。鉴于“月”和“日”是数据框中的第 0 和第 1 个索引级别:

    df['month'] = pd.to_datetime(df.index.levels[0], formatt='%m').to_series().dt.month_name().str[:3]
    df['day'] = df.index.levels[1]
    df.set_index(['month', 'day'], inplace=True)
    

    【讨论】:

      【解决方案4】:

      我实际上认为使用内置日期时间属性(如 mac13k 所述)是最 Pythonic 的解决方案,或者只是按照 Raju 在 cmets 中的建议在创建 df 之前提取月份。

      但是,如果您在重新标记索引时需要更大的灵活性,您可以使用 pd.DataFrame 的 .rename 方法重命名 0 级索引。

      作为一个应该直接在你的 df 上工作的例子:

      # set up df to match format of question
      month = np.arange(1, 13)
      day = np.ones(len(months))
      a = np.zeros(len(months))
      df = pd.DataFrame({'month':month, 'day':day, 'a':a})
      df = df.set_index(['month', 'day'])
      
      # create personalised mapping to rename index
      months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
      month_map = {i+1:month for i, month in enumerate(months)}
      
      # rename the level 0 index
      df.rename(index=month_map, level=0, inplace=True)
      

      就地编辑 df 以产生:

                     a
      month   day 
      Jan     1.0   0.0
      Feb     1.0   0.0
      Mar     1.0   0.0
      Apr     1.0   0.0
      May     1.0   0.0
      Jun     1.0   0.0
      Jul     1.0   0.0
      Aug     1.0   0.0
      Sep     1.0   0.0
      Oct     1.0   0.0
      Nov     1.0   0.0
      Dec     1.0   0.0
      

      【讨论】:

        【解决方案5】:

        您可以尝试导入日历,从数字 -> 名称创建字典映射,然后应用该映射。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2021-12-12
          • 1970-01-01
          • 2020-11-12
          • 2011-03-18
          • 1970-01-01
          • 2011-06-04
          • 1970-01-01
          • 2012-08-07
          相关资源
          最近更新 更多