【问题标题】:Adding a new column in data frame after calculation on time按时计算后在数据框中添加新列
【发布时间】:2016-10-17 10:48:35
【问题描述】:

我有一个这样的DataFrame

          Name           first_seen       last_seen
   0      Random guy 1   5/22/2016 18:12  5/22/2016 18:15 
   1      Random guy 2   5/22/2016 12:03  5/22/2016 12:03 
   2      Random guy 3   5/22/2016 21:06  5/22/2016 21:06
   3      Random guy 4   5/22/2016 16:20  5/22/2016 16:20 
   4      Random guy 5   5/22/2016 14:46  5/22/2016 14:46 

现在我必须添加一个名为 Visit_periodcolumn,当该人 (row) 花费的最大时间落入时,它采用 4 个值之一 [morning,afternoon,evening,night]

 - morning: 08:00 to 12:00 hrs
 - afternoon: 12:00 to 16:00 hrs
 - evening: 16:00 to 20:00 hrs
 - night: 20:00 to 24:00 hrs

所以对于以上五行输出将是这样的。

   visit_period
        evening
      afternoon
          night
        evening
      afternoon  

我提到了花费的最大时间,因为可能会发生某些人的first_seen 是 14:30 而last_seen 是 16:21。我想分配值afternoon,因为他在下午的平板上花了 30 分钟,在晚上的平板上花了 21 分钟。 我正在使用 python 2.7。

【问题讨论】:

  • 你试过什么?
  • @JulienBernu 这是我遇到问题的整个代码的一小部分。如果你能给出一些也有帮助的逻辑地图。
  • 合乎逻辑的路线图是在要求人们为您完成工作之前先尝试一些事情。如果您已经尝试过某些东西并且无法理解它出了什么问题,那么请分享您的代码和没有意义的具体问题。 minimal reproducible exampleHow to Ask
  • @JulienBernu 感谢您的建议,我以后会记住这一点。

标签: python python-2.7 pandas


【解决方案1】:

您可以将apply 与以下main_visit_period 函数一起使用,该函数尝试根据您概述的条件分配访问时间:

times = list(range(8, 21, 4))
labels = ['morning', 'afternoon', 'evening', 'night']
periods = dict(zip(times, labels))

给出:

{8: 'morning', 16: 'evening', 12: 'afternoon', 20: 'night'}

现在分配句点的功能:

def period(row):
    visit_start = {'hour': row.first_seen.hour, 'min': row.first_seen.minute} # get hour, min of visit start
    visit_end = {'hour': row.last_seen.hour, 'min': row.last_seen.minute} # get hour, min of visit end
    for period_start, label in periods.items():
        period_end = period_start + 4
        if period_start <= visit_start['hour'] < period_end:
            if period_start <= visit_end['hour'] < period_end or (period_end - visit_start['hour']) * 60 - visit_start['min'] > (visit_end['hour'] - period_end) * 60 + visit_end['min']:
                return label
            else:
                return periods[period_end] # assign label of following period  

最后是.apply():

df['period'] = df.apply(period, axis=1)

得到:

           Name          first_seen           last_seen     period
0  Random guy 1 2016-05-22 18:12:00 2016-05-22 18:15:00    evening
1  Random guy 2 2016-05-22 12:03:00 2016-05-22 12:03:00  afternoon
2  Random guy 3 2016-05-22 21:06:00 2016-05-22 21:06:00      night
3  Random guy 4 2016-05-22 16:20:00 2016-05-22 16:20:00    evening
4  Random guy 5 2016-05-22 14:46:00 2016-05-22 14:46:00  afternoon

【讨论】:

  • 感谢这个。会尝试。只是一个问题,因为我已经在每一行数据帧中为代码的其他部分运行了一个循环,所以如果我可以在那里添加它而不是再运行一个循环,我想这将是最佳的。
  • 如果您想以分钟为单位比较时间段,可能需要添加更多粒度,只需使用上面的hour。如果只想根据最近的时间来判断,即last_seen,可以使用last_seen.dt.hourmap()对应的时间段。如果您有大量数据,您可能还需要使用矢量化解决方案来检查timedeltas
  • 感谢您的建议,是的,我确实想按分钟进行,而不仅仅是最新的。我有一个大数据集,我不明白最后一行。会试着弄清楚。
  • 这给出错误:times = list(range(8, 21, 4)) TypeError: 'list' object is not callable
  • 按分钟添加区分。您的代码中是否有一个名为list 的变量? stackoverflow.com/questions/31087111/…
【解决方案2】:

你可以这样做:

start  = pd.datetime(2016, 05, 22, 8, 00, 00)
d = ["Morning", "Afternoon", "Evening", "Night"]

def max_spent(fs, ls):

    # Transform your date into timedelta in seconds:
    sr = np.arange(8,25,4)*3600
    fss = (fs-start).seconds
    lss = (ls-start).seconds

    # In which slot would it fit ?
    fs_d = sr.searchsorted(fss)
    ls_d = sr.searchsorted(lss)
    # If it's not the same for both date:
    if fs_d != ls_d:
        # get the one with the biggest amount of time:
        if fss - sr[fs_d - 1] > lss - sr[ls_d - 1]:
            return d[fs_d-1]
        else:
            return d[ls_d-1]
    else:
        return d[ls_d-1]

然后,您只需:

df["visit_period"] = df.apply(lambda x: max_spent(x["first_seen"], x["last_seen"]), axis=1)

你会得到:

df 
   Name          first_seen           last_seen visit_period
0  guy1 2016-05-22 18:12:00 2016-05-22 18:15:00      Evening
1  guy2 2016-05-22 12:03:00 2016-05-22 12:03:00    Afternoon
2  guy3 2016-05-22 21:06:00 2016-05-22 21:06:00        Night
3  guy4 2016-05-22 16:20:00 2016-05-22 16:20:00      Evening
4  guy5 2016-05-22 14:46:00 2016-05-22 14:46:00    Afternoon
5  guy6 2016-05-22 14:30:00 2016-05-22 16:21:00    Afternoon

使用 pd.cut 的先前版本,我认为如果不需要评估哪些列最好:

# Transform your date into timedelta in seconds:
df["sec"] = map(lambda x: x.seconds, df.last_seen-start)

# Apply Cut on this column:
df["visit_period"] = pd.cut(df.sec, np.arange(8,25,4)*3600, labels=d)

我只在 last_seen 上完成了它,但是您可以使用对应的值创建另一列来执行所花费的最大时间,然后您可以在该列上执行此操作。

HTH

【讨论】:

    猜你喜欢
    • 2017-08-05
    • 2019-08-05
    • 1970-01-01
    • 1970-01-01
    • 2018-10-11
    • 1970-01-01
    • 1970-01-01
    • 2017-11-27
    • 2016-12-24
    相关资源
    最近更新 更多