【问题标题】:Pandas: Date comparison with column addition based on values in rowsPandas:基于行中的值与列添加进行日期比较
【发布时间】:2016-08-01 18:40:39
【问题描述】:

我有许多格式类似的 excel 文件:

|name| email| cat1| cat2| cat3
 smith email 01JAN2016 01JAN2014 01JAN2015

前两列包含字符串(姓名和电子邮件地址),接下来的每一列包含每个人完成 cat(x) 中每个项目的日期。

我想与 current_date 进行比较,添加一个新列“status”,根据一行中的任何日期是否早于当前日期,该列的值将是“compliant”或“delinquent”,然后输出新的数据框到 Excel 电子表格。

我最初的尝试让我可以轻松地过滤“旧”日期,但是,当我尝试使用条件添加一列时,一切都开始中断:

import pandas as pd
import numpy as np
import datetime

current_date = datetime.datetime.now()
writer = pd.ExcelWriter('pd_output.xlsx', engine='xlsxwriter', datetime_format= 'mmm d yyy')

df = pd.read_excel(tracker,'Sheet1')

print(df.values)    # Displays dates as 'Timestamp('2016-01-01 00:00:00') any value which is < current_date displays as 'True' else 'False'

print(df < current_date)  # removes dates that are not older than current_date but does not delete column, ie someone with no old dates will still show up with column 3+ being blank

# a couple version of what I have been trying - unsuccessfully
df['Status'] = np.where(df[df < current_date], 'delinquent', 'compliant'  # error: 'wrong number of items passed

df['Status'] = np.where(df == 'True', 'delinquent', 'compliant'  # error: 'str' obj has no attr 'view'  

df['Status' = df.Set.map(lambda x: 'delinquent' if 'True' in df else 'compliant'  # from another post - error 'no attr 'Set' or 'map'

  # send to output excel
  df.to_excel(writer,sheet_name='Sheet1')

我希望有一个输出显示行,其中添加了“状态”列,显示行中存在“违规日期”的位置 - 以“合规”或“拖欠”引爆。我觉得我的比较不正确(使用 True 而不是另一个 .where),但似乎无法做到正确。

【问题讨论】:

    标签: python excel date pandas


    【解决方案1】:

    当您想要基于一个或多个其他列的值创建新列时,通常使用apply 函数之一。当函数是多列时,就像这里的情况一样,你使用DataFrame.apply。这是我认为您正在尝试做的近似值:

    df['Status'] = df.apply (
        lambda df : (
          'delinquent' 
              if any (df[i] < current_date for i in ("cat1","cat2","cat3")) 
           else 'compliant'
        ) ,
        axis = 1
    )
    

    (仅供参考,根据您的逻辑,我认为“拖欠”意味着日期早于当前日期,如果我错了,请将上面的 &lt; 符号反转为 &gt;。)

    让我们稍微拆开包装。 apply 将矢量化函数应用于整个数据帧。我们需要应用到整个数据框,因为我们正在查看不止一列;很快,我们将指定哪些。该函数是我们定义的lambdaaxis = 1 参数告诉 apply 将 lambda 应用于每一行(这不是默认值,默认值为 axis = 0,它适用于每一列 - 不是我们想要的)。 lambda 本身会按名称查看所有 3 个日期列,如果其中任何一个列在当前日期之前,则返回“拖欠”。我使用 any() 和内部的生成器表达式,以避免编写 if df["cat1"] &lt; current_date or df["cat2"] &lt; current_date or df["cat3"] &lt; current_date 之类的苦差事。

    请注意,所有这些都取决于您的 3 个日期列的类型为 datetime - 我假设它们是。

    如果您只有一个日期列,例如“cat1”,您可以在该列上使用稍微简单的Series.apply

    df['Status'] = df['cat1'].apply (
        lambda x : 'delinquent' if x < current_date else 'compliant' 
    )
    

    这样做的基本原理是更简单的函数和缺少axis 参数。所以一般来说,人们在应用一个只有一列的函数时使用Series.apply,如果函数是多列的,则使用DataFrame.apply

    【讨论】:

    • 这完全符合我的期望。我真的很感谢你的时间和补充解释(为了我未来的教育)。我很高兴您能够解释我的问题,即使我无法雄辩地表达我的问题。干杯!
    • 很高兴为您提供帮助!我很高兴我添加的其他内容也很有帮助 - apply 绝对是一个有用的工具。感谢您的接受。
    猜你喜欢
    • 2021-03-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多