【问题标题】:Dealing with None values when using Pandas Groupby and Apply with a Function使用 Pandas Groupby 和 Apply 函数时处理 None 值
【发布时间】:2016-06-01 18:48:13
【问题描述】:

我在Pandas 中有一个Dataframe,其中有一个字母和两个日期作为列。我想使用shift() 计算前一行的两个日期列之间的工作日,前提是Letter 值相同(使用.groupby())。我是用.apply() 做的。这一直有效,直到我传入一些缺少其中一个日期的数据。我将所有内容移至一个函数以使用try/except 子句处理缺失值,但现在我的函数为所有内容返回NaN。看来日期的None 值会影响函数的每次调用,而我认为只有当.groupby() 中的LetterA 时才会这样做。

import pandas as pd
from datetime import datetime
import numpy as np

def business_days(x):
    try:
      return pd.DataFrame(np.busday_count(x['First Date'].tolist(), x['Last Date'].tolist())).shift().reset_index(drop=True)
    except ValueError:
        return None

df = pd.DataFrame(data=[['A', datetime(2016, 1, 7), None],
                        ['A', datetime(2016, 3, 1), datetime(2016, 3, 8)],
                        ['B', datetime(2016, 5, 1), datetime(2016, 5, 10)],
                        ['B', datetime(2016, 6, 5), datetime(2016, 6, 7)]],
                  columns=['Letter', 'First Date', 'Last Date'])

df['First Date'] = df['First Date'].apply(lambda x: x.to_datetime().date())
df['Last Date'] = df['Last Date'].apply(lambda x: x.to_datetime().date())

df['Gap'] = df.groupby('Letter').apply(business_days)

print df

实际输出:

  Letter  First Date   Last Date  Gap
0      A  2016-01-07         NaT  NaN
1      A  2016-03-01  2016-03-08  NaN
2      B  2016-05-01  2016-05-10  NaN
3      B  2016-06-05  2016-06-07  NaN

期望的输出:

  Letter   First Day    Last Day   Gap
0      A  2016-01-07         NAT  NAN
1      A  2016-03-01  2016-03-08  NAN
2      B  2016-05-01  2016-05-10  NAN
3      B  2016-06-05  2016-06-07  7

【问题讨论】:

  • 在您当前的代码中,如果 Letter 组在一行中有一个 NaT,则 busday_count 函数会引发 ValueError 并返回 None。您希望整个 Letter 组的 Gap 值为 NaN,还是希望计算非 NaT 行的工作日?
  • @unutbu 仅适用于非 NaT 行

标签: python python-2.7 pandas


【解决方案1】:
  • 暂时忽略NaTs,注意np.busday_count计算 可以在df 的整个列上完成之前 应用groupby。这将 节省时间,因为这取代了对np.busday_count 的多次调用(每个调用一次) 组)只需一次呼叫np.busday_count。一个函数调用应用于 大数组通常比对小数组的许多函数调用要快。

  • 要处理NaTs,您可以使用pd.notnull 来识别哪些行 拥有NaTs 并屏蔽First Dates 和Last Dates 以便仅有效 日期发送到np.busday_count。然后你可以为那些填写NaNs 日期为NaTs 的行。

  • 计算完所有工作日计数后,我们需要做的就是分组 Lettershift 将值减一。这可以做到 groupby/transform('shift').


import datetime as DT
import numpy as np
import pandas as pd

def business_days(start, end):
    mask = pd.notnull(start) & pd.notnull(end)
    start = start.values.astype('datetime64[D]')[mask]
    end = end.values.astype('datetime64[D]')[mask]
    result = np.empty(len(mask), dtype=float)
    result[mask] = np.busday_count(start, end)
    result[~mask] = np.nan
    return result

df = pd.DataFrame(data=[['A', DT.datetime(2016, 1, 7), None],
                        ['A', DT.datetime(2016, 3, 1), DT.datetime(2016, 3, 8)],
                        ['B', DT.datetime(2016, 5, 1), DT.datetime(2016, 5, 10)],
                        ['B', DT.datetime(2016, 6, 5), DT.datetime(2016, 6, 7)]],
                  columns=['Letter', 'First Date', 'Last Date'])

df['Gap'] = business_days(df['First Date'], df['Last Date'])
print(df)
#   Letter First Date  Last Date  Gap
# 0      A 2016-01-07        NaT  NaN
# 1      A 2016-03-01 2016-03-08  5.0
# 2      B 2016-05-01 2016-05-10  6.0
# 3      B 2016-06-05 2016-06-07  1.0

df['Gap'] = df.groupby('Letter')['Gap'].transform('shift')
print(df)

打印

  Letter First Date  Last Date  Gap
0      A 2016-01-07        NaT  NaN
1      A 2016-03-01 2016-03-08  NaN
2      B 2016-05-01 2016-05-10  NaN
3      B 2016-06-05 2016-06-07  6.0

【讨论】:

  • 我喜欢一步将计算应用于整个列。但是,我得到了值错误,ValueError: Cannot compute a business day count with a NaT (not-a-time) date
  • 嗯,我无法重现该错误。运行我上面发布的代码时,你明白了吗?
  • 如果您在上面发布的代码中遇到 ValueError,那么您使用的 Pandas 和 NumPy 是什么版本?如果您在将business_days 应用于您自己的数据(但不是在上面的代码中)时只收到该ValueError,那么传递给business_days 的参数的dtype 是什么?
  • 我也遇到了与上述用户相同的错误。我正在使用 Pandas 0.19.2 和 Numpy 1.11.3。 <ipython-input-118-70ecbc042cd4> in business_days(start, end) 4 end = end.values.astype('datetime64[D]')[mask] 5 result = np.empty(len(mask), dtype=float) ----> 6 result[mask] = np.busday_count(start, end) 7 result[~mask] = np.nan 8 return result ValueError: Cannot compute a business day count with a NaT (not-a-time) date
  • 好的,更新到 Numpy 1.12.1 已经解决了这个问题。
猜你喜欢
  • 1970-01-01
  • 2019-08-22
  • 2021-01-12
  • 1970-01-01
  • 2014-05-15
  • 2017-09-14
  • 2017-06-20
  • 2020-01-04
  • 2022-01-01
相关资源
最近更新 更多