【问题标题】:Copying column from one data frame to another based on matching of combination of two columns基于两列组合的匹配将列从一个数据帧复制到另一个数据帧
【发布时间】:2020-01-11 08:23:46
【问题描述】:

我有两个数据框(即 df1 和 df2)。

df1 包含日期和时间列。时间列包含 30 分钟间隔的时间序列:

df1:
         date      time
0       2015-04-01  00:00:00
1       2015-04-01  00:30:00
2       2015-04-01  01:00:00
3       2015-04-01  01:30:00
4       2015-04-01  02:00:00

df2 包含日期、开始时间、结束时间、值:

df2
       INCIDENT_DATE INTERRUPTION_TIME RESTORE_TIME  WASTED_MINUTES
0        2015-04-01             00:32        01:15          1056.0
1        2015-04-01             01:20        02:30          3234.0
2        2015-04-01             01:22        03:30          3712.0
3        2015-04-01             01:30        03:15          3045.0

现在,当两个数据帧的日期列相同且 df2 列的 Interruption_time 位于 df1 的时间列时,我想将 wasted_minutes 列从 df2 复制到 df1。所以输出应该是这样的:

df1:
                date      time      Wasted_columns
    0       2015-04-01  00:00:00       NaN
    1       2015-04-01  00:30:00       1056.0
    2       2015-04-01  01:00:00       6946.0
    3       2015-04-01  01:30:00       3045.0
    4       2015-04-01  02:00:00       NaN

我尝试了合并命令(基于日期列),但没有产生预期的结果,因为我不确定如何检查时间是否以 30 分钟为间隔?谁能指导如何解决这个问题?

【问题讨论】:

  • 你好,如果中断时间和restore_time只覆盖2个日期时间怎么办
  • 总是伴随着中断时间。

标签: python python-3.x pandas


【解决方案1】:

time 转换为timedelta 并分配回df1。将INTERRUPTION_TIME 转换为timedelta,将floor 转换为30 分钟间隔并分配给s。 Groupby df2 by INCIDENT_DATE, s 并致电sum of WASTED_MINUTES。最后将joingroupby的结果返回df1

df1['time'] = pd.to_timedelta(df1['time'].astype(str)) #cast to str before calling `to_timedelta`
s = pd.to_timedelta(df2.INTERRUPTION_TIME+':00').dt.floor('30Min')
df_final = df1.join(df2.groupby(['INCIDENT_DATE', s]).WASTED_MINUTES.sum(), 
                    on=['date', 'time'])

Out[631]:
         date     time  WASTED_MINUTES
0  2015-04-01 00:00:00             NaN
1  2015-04-01 00:30:00          1056.0
2  2015-04-01 01:00:00          6946.0
3  2015-04-01 01:30:00          3045.0
4  2015-04-01 02:00:00             NaN

【讨论】:

  • 这里是错误:您正在尝试合并对象和 timedelta64[ns] 列。
  • @user2293224: 你能检查一下df1['time'] 是在timedelta dtype 中吗?
  • df1['time'] 是对象。我修改了代码:修改是我在代码中转换时间时使用了 .astype(str) 。它执行了。但是,它 WASTED_MINUTES 列具有 NaN 值。有什么建议吗?
  • 在我的代码中 s 是 timedelta,因此您需要将 df1['time'] 保留在 timedelta dtype 中以使 join 工作。否则,如果要将df1['time'] 转换为对象,还需要在调用join 内部的groupby 之前将s 转换为对象
  • 当我将 s 转换为 .astype(str) 时,错误是 ValueError: You are trying to merge on timedelta64[ns] 和 object 列。如果你想继续,你应该使用 pd.concat
【解决方案2】:

你可以这样做

df1['time']=pd.to_datetime(df1['time'])
df1['Wasted_columns']=df1.apply(lambda x: df2.loc[(pd.to_datetime(df2['INTERRUPTION_TIME'])>= x['time']) & (pd.to_datetime(df2['INTERRUPTION_TIME'])< x['time']+pd.Timedelta(minutes=30)),'WASTED_MINUTES'].sum(), axis=1)
df1['time']=df1['time'].dt.time

如果你在 lambda 函数本身中转换“时间”列,那么它只是下面的一行代码

df1['Wasted_columns']=df1.apply(lambda x: df2.loc[(pd.to_datetime(df2['INTERRUPTION_TIME'])>= pd.to_datetime(x['time'])) & (pd.to_datetime(df2['INTERRUPTION_TIME'])< pd.to_datetime(x['time'])+pd.Timedelta(minutes=30)),'WASTED_MINUTES'].sum(), axis=1)

输出

          date     time     Wasted_columns
0   2015-04-01  00:00:00    0.0
1   2015-04-01  00:30:00    1056.0
2   2015-04-01  01:00:00    6946.0
3   2015-04-01  01:30:00    3045.0
4   2015-04-01  02:00:00    0.0

【讨论】:

    【解决方案3】:

    想法: + 转换为日期时间 + 四舍五入到最近的 30 分钟 + 合并

    from datetime import datetime, timedelta
    
    def ceil_dt(dt, delta):
        return dt + (datetime.min - dt) % delta
    
    # Convert
    df1['dt'] = (df1['date'] + ' ' + df1['time']).apply(datetime.strptime, args=['%Y-%m-%d %H:%M:%S'])
    df2['dt'] = (df2['INCIDENT_DATE '] + ' ' + df2['INTERRUPTION_TIME']).apply(datetime.strptime, args=['%Y-%m-%d %H:%M'])
    
    # Round
    def ceil_dt(dt, delta):
        return dt + (datetime.min - dt) % delta
    
    df2['dt'] = df2['dt'].apply(ceil_dt, args=[timedelta(minutes=30)])
    
    # Merge
    final = df1.merge(df2.loc[:, ['dt', 'wasted_column'], on='dt', how='left'])
    

    此外,如果在 30 分钟的时间范围内发生多起事件,您可能希望先在 df2 上进行分组,并先用四舍五入的 dt col 总结浪费然后合并

    【讨论】:

      猜你喜欢
      • 2021-04-03
      • 1970-01-01
      • 2020-08-31
      • 2021-03-10
      • 2018-02-23
      • 2020-09-18
      • 1970-01-01
      • 1970-01-01
      • 2020-06-04
      相关资源
      最近更新 更多