pandas:参照列属性将一行转换为多行-时间精度分片

pandas技巧太多了,往往有想法但无从下手,话不多说,开始

图一转换为图二:实现不同时间段都按10分钟的精度去划分,并且实现一行变多行

 

                   图一   (显示不全)                 

                                             

                                     

图二(显示不全)

                                 

 

该函数是用来将不是10分钟整的时间设置为10分钟整的类型:采用四舍五入取舍数据。

import datetime
#时间划分函数(StartTime:开始时间,EndTime:结束时间)
def TimeClassfy(StartTime,EndTime):
    Start1 = int((StartTime.split(':')[1])[0:1]) #开始十位
    End1 = int((EndTime.split(':')[1])[0:1]) #结束十位
    Start2 = int((StartTime.split(':')[1])[1:2]) #开始个位
    End2 = int((EndTime.split(':')[1])[1:2]) #结束个位
    #字符串转时间类型
    StartTime = datetime.datetime.strptime(StartTime,"%H:%M:%S")
    EndTime = datetime.datetime.strptime(EndTime,"%H:%M:%S")
    #计算时间间隔(跨0点)
    dar = EndTime - (StartTime - datetime.timedelta(days=1)) if EndTime < StartTime else EndTime - StartTime
    #将时间类型转化为字符串类型
    def Utiler(StartTime,EndTime):
        StartTime = StartTime.strftime('%H:%M:%S')
        EndTime = EndTime.strftime('%H:%M:%S')
        return StartTime,EndTime
    #结束时间分钟为整数
    if End2 == 0:
        if dar < datetime.timedelta(minutes=10):
            StartTime = StartTime+datetime.timedelta(minutes=-Start2)
        else:   
            if Start2 >= 5:
                StartTime = StartTime+datetime.timedelta(minutes=+10-Start2)
            else:
                StartTime = StartTime+datetime.timedelta(minutes=-Start2)
        return Utiler(StartTime,EndTime)
    elif Start1 == End1:
        if dar < datetime.timedelta(minutes=10):
            StartTime = StartTime+datetime.timedelta(minutes=-Start2)
            EndTime = EndTime+datetime.timedelta(minutes=+10-End2)
        else:   
            if Start2 >= 5:
                StartTime = StartTime+datetime.timedelta(minutes=+10-Start2)
            else:
                StartTime = StartTime+datetime.timedelta(minutes=-Start2)
            if End2 >= 5:
                EndTime = EndTime+datetime.timedelta(minutes=+10-End2)
            else:
                EndTime = EndTime+datetime.timedelta(minutes=-End2)
        return Utiler(StartTime,EndTime)
    elif (End2-0) >= (10-Start2):
        if End2 >= 5 and Start2 < 5:
            StartTime = StartTime+datetime.timedelta(minutes=-Start2)
            EndTime = EndTime+datetime.timedelta(minutes=+10-End2)
            return Utiler(StartTime,EndTime)
        else:
            StartTime = StartTime+datetime.timedelta(minutes=+10-Start2)
            EndTime = EndTime+datetime.timedelta(minutes=+10-End2)
            return Utiler(StartTime,EndTime)
    elif (End2-0) < (10-Start2):
        if End2 >= 5:
            StartTime = StartTime+datetime.timedelta(minutes=-Start2)
            EndTime = EndTime+datetime.timedelta(minutes=+10-End2)
            return Utiler(StartTime,EndTime)
        else:
            StartTime = StartTime+datetime.timedelta(minutes=-Start2)
            EndTime = EndTime+datetime.timedelta(minutes=-End2)
            return Utiler(StartTime,EndTime)

 错误做法:使用apply方法根据原表多列属性生成一个表------错误地方:apply是根据一行或一列操作,每一行生成一个表会出现:could not broadcast input array from shape (x,y) into shape (x) ,这里我的做法是生成一个list

import numpy as np
import pandas as pd
import matplotlib
#时间分割函数(按10分钟的精度划分)
def TimeSlice(TUCASEID,start,end,TRCODE,state):
    #将输入的字符串转化为时间类型,由于判断两个时间间隔是否10分钟内
    less_start = datetime.datetime.strptime(start,'%H:%M:%S')
    less_end = datetime.datetime.strptime(end,'%H:%M:%S')
    #时间间隔不足10分时,less为True
    if less_end < less_start:
        less_start = less_start - datetime.timedelta(days=1)
    less = True if (less_end-less_start) < datetime.timedelta(minutes=10) else False
    #10分钟划分函数
    startby = TimeClassfy(start,end)[0]
    endby = TimeClassfy(start,end)[1]
    #处理成时间类型,便于计算
    datestart = datetime.datetime.strptime(startby,'%H:%M:%S')
    dateend = datetime.datetime.strptime(endby,'%H:%M:%S')
    FourTime = datetime.datetime.strptime('04:00:00','%H:%M:%S')
   
    dateend = dateend - datetime.timedelta(minutes=10)
    #处理不足10分钟的活动
    if dateend <= datestart:
        dateend+=datetime.timedelta(minutes=10)   
    data_list = list()
    timestand = datetime.datetime.strptime('00:00:00','%H:%M:%S')
    #1.开始时间少于或等于结束时间的情况
    if datestart <= dateend:
        #1.1 开始时间少于或等于结束时间,时间间隔少于10分钟
        if less:
            data_list.append(datestart.strftime('%H:%M:%S')) 
        #1.2 开始时间少于或等于结束时间,时间间隔大于10分钟
        else:
            #1.2.1 开始时间少于4点(解决最后一个时间段的问题),则令EndTime='04:00:00'
            if datestart < FourTime and dateend > FourTime:
                dateend = FourTime
            while datestart <= dateend:
                data_list.append(datestart.strftime('%H:%M:%S')) 
                datestart+=datetime.timedelta(minutes=10)
    #2.开始时间在24点前,结束时间24点后的情况
    else:
        #2.1如果结束时间在4点后
        if dateend > FourTime:
            dateend = FourTime
        #2.2开始时间在24点前,结束时间24点后
        while datestart <= (timestand-datetime.timedelta(minutes=10) + datetime.timedelta(days=1)):
            data_list.append(datestart.strftime('%H:%M:%S')) 
            datestart+=datetime.timedelta(minutes=10)
        while timestand < dateend:
            data_list.append(timestand.strftime('%H:%M:%S')) 
            timestand+=datetime.timedelta(minutes=10)
    return ','.join(data_list)

 关键在于将每行生成的list保持在新的列中,col.str.split(',',expand=True)一列分多列,在重塑(Stack),重塑后要重设第二级索引,series转dataframe,列换名,去除多余列并拼接。

#在原表里添加一列临时开始时间列表
finadf['STARTTEMP'] = finadf.apply(lambda row:TimeSlice(row['TUCASEID'], row['TUSTARTTIM'], row['TUSTOPTIME'],row['TRCODE'],row['state']), axis=1)
#将临时开始时间列表分成多列
t1 = finadf['STARTTEMP'].str.split(',', expand=True)
#关键:使用此方法可以实现根据列属性,将表一行变多行
t2 = t1.stack()
t3 = t2.reset_index(level=1, drop=True)
t4 = t3.to_frame()
t4.rename(columns={0:'TUSTARTTIM'},inplace=True)
#去除多余列并拼接新的列
DataTable = finadf.drop(['TUSTARTTIM','TUSTOPTIME','STARTTEMP'], axis=1).join(t4)
DataTable.head(50)

 

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值