【问题标题】:Pandas Dataframe Creating a New Column Based on Other ColumnsPandas Dataframe 基于其他列创建新列
【发布时间】:2021-12-30 00:35:33
【问题描述】:

我有一个数据框(df)如下:

    Customer    Date_Begin  Date_End    Product
0   1   2017-01-01  2020-01-01  UsagePeriod
1   1   2017-01-02  2018-01-02  Token
2   1   2017-01-06  2018-01-06  Token
3   1   2018-12-01  2019-12-01  Token
4   1   2019-06-01  2020-06-01  Token
5   1   2019-12-21  2022-12-21  UsagePeriod
6   1   2020-01-31  2021-01-31  Token
7   1   2021-06-30  2022-06-30  Token
8   1   2021-09-30  2022-09-30  Token
9   2   2019-06-01  2022-06-01  UsagePeriod
10  2   2019-06-01  2020-06-01  Token
11  3   2019-06-01  2022-06-01  UsagePeriod
12  3   2019-06-01  2020-06-01  Token
13  3   2020-06-01  2021-06-01  Token
14  4   2017-01-01  2020-01-01  UsagePeriod
15  4   2017-02-15  2018-02-15  Token
16  4   2019-12-15  2020-12-15  Token

要达到所需的输出数据帧,需要应用一些规则:

  1. 每个客户都有一个可以购买代币的 UsagePeriod。通常令牌会在一年内(最多)过期,而 UsagePeriod 总是从 Date_Begin 开始 3 年。 Date_End 列给出了预期的到期日期。
  2. 客户不会购买新的令牌,除非他的令牌已过期。这意味着如果他(她)正在购买一个新的代币,那么他(她)已经用完了该代币。假设客户在前一个令牌到期时购买了新令牌,我想打开一个包含所有到期日期的附加列。
  3. 令牌只能在客户定义的 UsagePeriod 中使用,除非客户购买新的 Usage Period。 我想要达到的输出数据框是:
    Customer    Date_Begin  Date_End    Product Expiry
0   1   2017-01-01  2020-01-01  UsagePeriod 2020-01-01
1   1   2017-01-02  2018-01-02  Token   2017-01-06
2   1   2017-01-06  2018-01-06  Token   2018-01-06
3   1   2018-12-01  2019-12-01  Token   2019-06-01
4   1   2019-06-01  2020-06-01  Token   2019-12-21
5   1   2019-12-21  2022-12-21  UsagePeriod 2022-12-21
6   1   2020-01-31  2021-01-31  Token   2021-01-31
7   1   2021-06-30  2022-06-30  Token   2021-09-30
8   1   2021-09-30  2022-09-30  Token   2022-09-30
9   2   2019-06-01  2022-06-01  UsagePeriod 2022-06-01
10  2   2019-06-01  2020-06-01  Token   2020-06-01
11  3   2019-06-01  2022-06-01  UsagePeriod 2022-06-01
12  3   2019-06-01  2020-06-01  Token   2020-06-01
13  3   2020-06-01  2021-06-01  Token   2021-06-01
14  4   2017-01-01  2020-01-01  UsagePeriod 2020-01-01
15  4   2017-02-15  2018-02-15  Token   2018-02-15
16  4   2019-12-15  2020-12-15  Token   2020-01-01
            

我目前拥有的代码是:

def myFunc(df):
                                                                         
for i in range(0,len(df)-1): #loop through each row of dataframe
    if df.Product.loc[i] == "UsagePeriod": #When product equals "UsagePeriod"
      df['expiricy'].loc[i] = df['Date_Begin'].loc[i]  + pd.offsets.DateOffset(years=3); #update new column
    elif df.Product.loc[i] == "Token": #When product equals "Token"
      if df.Customer.loc[i] == df.Customer.loc[i+1]: #customer changed?
        if abs(df.Date_Begin.loc[i+1]-df.Date_Begin.loc[i])>= pd.Timedelta(364, 'd'): #has year increased by more than 1(year)? product = product
          df['expiricy'].loc[i] = df['Date_Begin'].loc[i]  + pd.offsets.DateOffset(years=1); #update new column
        elif abs(df.Date_Begin.loc[i+1]-df.Date_Begin.loc[i]) < pd.Timedelta(364, 'd'): #When less than a year?
          df['expiricy'].loc[i] = df['Date_Begin'].loc[i+1];

我正在努力在 UsagePeriod 中定义令牌结束期。任何帮助将不胜感激。

【问题讨论】:

  • 欢迎来到 SO - 请使用 tour 并阅读 How to Ask 以改进,edit 并格式化您的问题。谢谢
  • 你想要下一个token的Date_begin作为到期日吗??
  • 根据客户,如果令牌和下一个令牌之间的间隔小于一年,则应将其更新为下一个令牌的开始日期。如果超过一年,则应将其更新为令牌的结束日期。但是,如果 End_date 超过该客户的 UsagePeriod 的 End_date,则无论到期日期应该保留/结束在客户的定义 UsagePeriod 中

标签: python pandas dataframe loops date


【解决方案1】:

首先将日期列转换为日期时间对象。您将需要它来进行有效的比较。

df["Date_Begin"] = pd.to_datetime(df["Date_Begin"])
df["Date_End"] = pd.to_datetime(df["Date_End"])

所有以 Token 作为产品的行在客户组中向后移动:

df["Expiry"] = df.loc[df["Product"].eq("Token"), "Date_Begin"].groupby(df["Customer"]).shift(-1)

结果:

    Customer Date_Begin   Date_End      Product     Expiry
0          1 2017-01-01 2020-01-01  UsagePeriod        NaT
1          1 2017-01-02 2018-01-02        Token 2017-01-06
2          1 2017-01-06 2018-01-06        Token 2018-12-01
3          1 2018-12-01 2019-12-01        Token 2019-06-01
4          1 2019-06-01 2020-06-01        Token 2020-01-31
5          1 2019-12-21 2022-12-21  UsagePeriod        NaT
6          1 2020-01-31 2021-01-31        Token 2021-06-30
7          1 2021-06-30 2022-06-30        Token 2021-09-30
8          1 2021-09-30 2022-09-30        Token        NaT
9          2 2019-06-01 2022-06-01  UsagePeriod        NaT
10         2 2019-06-01 2020-06-01        Token        NaT
11         3 2019-06-01 2022-06-01  UsagePeriod        NaT
12         3 2019-06-01 2020-06-01        Token 2020-06-01
13         3 2020-06-01 2021-06-01        Token        NaT
14         4 2017-01-01 2020-01-01  UsagePeriod        NaT
15         4 2017-02-15 2018-02-15        Token 2019-12-15
16         4 2019-12-15 2020-12-15        Token        NaT

然后我们将 Date_End 与当前的 Expiry 进行比较。如果 Date_End 更早,我们使用 date end 否则 Expiry。

df["Expiry"] = df["Expiry"].where(df["Expiry"].lt(df["Date_End"]), df["Date_End"])

这还将产品为使用期的值设置为 Date_End 值。

Customer Date_Begin   Date_End      Product     Expiry
0          1 2017-01-01 2020-01-01  UsagePeriod 2020-01-01
1          1 2017-01-02 2018-01-02        Token 2017-01-06
2          1 2017-01-06 2018-01-06        Token 2018-01-06
3          1 2018-12-01 2019-12-01        Token 2019-06-01
4          1 2019-06-01 2020-06-01        Token 2020-01-31
5          1 2019-12-21 2022-12-21  UsagePeriod 2022-12-21
6          1 2020-01-31 2021-01-31        Token 2021-01-31
7          1 2021-06-30 2022-06-30        Token 2021-09-30
8          1 2021-09-30 2022-09-30        Token 2022-09-30
9          2 2019-06-01 2022-06-01  UsagePeriod 2022-06-01
10         2 2019-06-01 2020-06-01        Token 2020-06-01
11         3 2019-06-01 2022-06-01  UsagePeriod 2022-06-01
12         3 2019-06-01 2020-06-01        Token 2020-06-01
13         3 2020-06-01 2021-06-01        Token 2021-06-01
14         4 2017-01-01 2020-01-01  UsagePeriod 2020-01-01
15         4 2017-02-15 2018-02-15        Token 2018-02-15
16         4 2019-12-15 2020-12-15        Token 2020-12-15

按UsagePeriod限制:

df["End_Usage"] = df["Date_End"].where(df["Product"].eq("UsagePeriod")).ffill()
df["Expiry"] = df["Expiry"].where(df["Expiry"].le(df["End_Usage"]), df["End_Usage"])

【讨论】:

  • 感谢您的回答!我很难解决的唯一问题是第 16 行,令牌的到期时间超过了其定义的 UsagePeriod。令牌应保留在其定义的 UsagePeriod 中,因此对于第 16 行,到期时间应为 2020-01-01。
  • 我为此添加了解决方案。第 4 行也发生了变化。
  • 谢谢!!这很有帮助
  • 没有问题,请接受答案并点赞。
猜你喜欢
  • 2016-02-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-04-25
  • 1970-01-01
  • 2017-08-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多