Pandas: 列和索引之间的多索引应用函数

Pandas: Multi-index apply function between column and index

我有一个多索引数据框,如下所示:

In[13]: df
Out[13]:
              Last Trade
Date       Ticker           
1983-03-30 CLM83  1983-05-18
           CLN83  1983-06-17
           CLQ83  1983-07-18
           CLU83  1983-08-19
           CLV83  1983-09-16
           CLX83  1983-10-18
           CLZ83  1983-11-18
1983-04-04 CLM83  1983-05-18
           CLN83  1983-06-17
           CLQ83  1983-07-18
           CLU83  1983-08-19
           CLV83  1983-09-16
           CLX83  1983-10-18
           CLZ83  1983-11-18

索引有两个级别(即'Date'和'Ticker')。我想对列 'Last Trade' 应用一个函数,让我知道这个 'Last Trade' 日期与索引 'Date' 相隔多少个月 我找到了一个进行计算的函数:

from calendar import monthrange

def monthdelta(d1, d2):
    delta = 0
    while True:
        mdays = monthrange(d1.year, d1.month)[1]
        d1 += datetime.timedelta(days=mdays)
        if d1 <= d2:
            delta += 1
        else:
            break
    return delta

我尝试应用以下函数 h 但它 returns 给我一个 AttributeError: 'Timestamp' object has no attribute 'index':

In[14]: h = lambda x: monthdelta(x.index.get_level_values(0),x)

In[15]: df['Last Trade'] = df['Last Trade'].apply(h)

如何应用一个同时使用列和索引值的函数?

感谢您的提示,

使用df.index.to_series().str.get(0)获取第一级索引。

(df['Last Trade'].dt.month - df.index.to_series().str.get(0).dt.month) + \
(df['Last Trade'].dt.year - df.index.to_series().str.get(0).dt.year) * 12

Date        Ticker
1983-03-30  CLM83     2
            CLN83     3
            CLQ83     4
            CLU83     5
            CLV83     6
            CLX83     7
            CLZ83     8
1983-04-04  CLM83     1
            CLN83     2
            CLQ83     3
            CLU83     4
            CLV83     5
            CLX83     6
            CLZ83     7
dtype: int64

时机

鉴于df

pd.concat([df for _ in range(10000)])

试试这个而不是你的函数:

选项 1

你得到一个整数

def monthdelta(row):
    trade = row['Last Trade'].year*12 + row['Last Trade'].month
    date = row['Date'].year*12 + row['Date'].month
    return trade - date

df.reset_index().apply(monthdelta, axis=1)

受 PiRsquared 启发:

df = df.reset_index()
(df['Last Trade'].dt.year*12 + df['Last Trade'].dt.month) -\
(df['Date'].dt.year*12 + df['Date'].dt.month)

选项 2

你得到一个numpy.timedelta64

可以直接用于其他日期计算。但是,这将以天而不是月的形式出现,因为 days in a month are not constant.

的数量
def monthdelta(row):
    return row['Last Trade'] - row['Date']

df.reset_index().apply(monthdelta, axis=1)

受 PiRsquared 启发:

df = df.reset_index()
df['Last Trade'] - df['Date']

方案2当然会更快,因为它涉及的计算更少。选择你喜欢的!


要取回索引:df.index = df[['Date', 'Ticker']]