【问题标题】:New column to get the previous date for a certain category (Python)获取某个类别的上一个日期的新列(Python)
【发布时间】:2020-07-17 12:38:33
【问题描述】:

我正在尝试创建某个预测模型。我决定用 这次用python代替DAX(pbi)来学习python。

我有 2 列与此问题相关:客户和日期。 每行都是在该特定日期为该客户创建的发票。

我正在尝试为每一行(发票)获取上一个发票日期。了解这一点很重要 新列必须考虑客户,这意味着对于每个客户的发票,我想获得发票的上一个日期。

这就是它的样子:

data = [['A', 17/07/2020], ['B', 15/07/2020], ['C', 14/07/2020], ['C', 10/07/2020], ['B', 09/07/2020]]
df = pd.DataFrame(data, columns = ['Customer', 'Date'])
print(df)

Customer Date
A        17/07/2020
B        15/07/2020
C        14/07/2020
C        10/07/2020
B        09/07/2020  

这是我寻求的结果:

Customer Date        PrevInvoiceDate
A        17/07/2020  NaT
B        15/07/2020  09/07/2020
C        14/07/2020  10/07/2020
C        10/07/2020  NaT
B        09/07/2020  NaT

我尝试使用 pandas 的 shift、loc、filter 等。但没有运气, 我将很感激学习正确的方法来进行这种操作并向大家学习。 谢谢。

【问题讨论】:

    标签: python pandas data-science data-manipulation


    【解决方案1】:

    试试这个:

    import pandas as pd
    data = [['A', '17/07/2020'], ['B', '15/07/2020'], ['C', '14/07/2020'], ['C', '10/07/2020'], ['B', '09/07/2020']]
    df = pd.DataFrame(data, columns = ['Customer', 'Date'])
    df=df.sort_values(by=['Customer','Date'])
    df['test']=df.groupby('Customer')['Date'].shift()
    print(df)
      Customer        Date        test
    0        A  17/07/2020         NaN
    4        B  09/07/2020         NaN
    1        B  15/07/2020  09/07/2020
    3        C  10/07/2020         NaN
    2        C  14/07/2020  10/07/2020
    

    【讨论】:

      【解决方案2】:

      首先,您的Date 列的类型似乎是字符串而不是日期时间。让我们将其转换为日期时间。然后,按Date 对数据框进行排序。

      df['Date'] = pd.to_datetime(df['Date'])
      df = df.sort_values('Date')
      
      # Output:
      Customer    Date
      0   A   17/07/2020
      1   B   15/07/2020
      2   C   14/07/2020
      3   C   10/07/2020
      4   B   09/07/2020
      

      然后,将数据帧按Customer 分组,然后使用apply() 函数。对于每个组(特定客户的所有发票),将 Date 列移动 1。

      df['PrevInvoiceDate'] = df.groupby('Customer')['Date'].shift(periods=1)
      
      # Output:
      Customer    Date    PrevInvoiceDate
      2   C   2020-07-14  NaT
      1   B   2020-07-15  NaT
      0   A   2020-07-17  NaT
      4   B   2020-09-07  2020-07-15
      3   C   2020-10-07  2020-07-14
      

      此外,shift() 函数默认会将列值向下移动 1,因此您可以摆脱 periods=1。我在这里只是为了确保您了解它的作用。

      最后,如果您想恢复原来的日期格式,我们可以将日期时间转换回字符串。

      df['Date'] = df['Date'].dt.strftime('%d/%m/%Y')
      df['PrevInvoiceDate'] = df['PrevInvoiceDate'].dt.strftime('%d/%m/%Y')
      
      df.sort_index()  # (Optional) Sort the dataframe by its original index
      
      # Output:
          Customer    Date    PrevInvoiceDate
      0   A   17/07/2020  NaN
      1   B   15/07/2020  NaN
      2   C   14/07/2020  NaN
      3   C   07/10/2020  14/07/2020
      4   B   07/09/2020  15/07/2020
      

      【讨论】:

      • 这与我需要的完全相反,但这对于我需要获得与我这次需要的相反的情况非常有用。谢谢。
      • @DanielMillionshik,不幸的是我没有注意到我以相反的方式对数据框进行排序。但是,只想指出您接受的方法并不安全。它在将日期字符串转换为日期对象之前对数据框进行了排序,这可能会给您带来错误的结果。
      【解决方案3】:

      这是一个卷发。一种方法是left merge dfgroupby 结果,使用apply 选择每个组中的最后一个。选择重复的索引并将它们清空

           import numpy as np
      df2=df.merge(df.groupby('Customer')['Date'].apply(lambda x: x.iloc[1:]).\
                   reset_index().rename(columns={'Date':'PrevInvoiceDate'}),\
                   how='left',on='Customer').drop(columns=['level_1'])
      
      df2.loc[df2.loc[df2["PrevInvoiceDate"].duplicated('first')].\
              index,'PrevInvoiceDate']=np.nan
      
      
      
           Customer        Date      PrevInvoiceDate
      0        A       17/07/2020             NaN
      1        B       15/07/2020      09/07/2020
      2        C       14/07/2020      10/07/2020
      3        C       10/07/2020             NaN
      4        B       09/07/2020             NaN
      

      【讨论】:

      • 这行得通,但有一种更简单的方法可以做到这一点。不过,我会将其用于其他情况,谢谢。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-03-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-09-13
      相关资源
      最近更新 更多