cycdfixle 2021-02-19 11:53 采纳率: 100%
浏览 280
已采纳

时间序列数据,python预处理

类似于图片的时间序列数据,这是我EXCEL处理完毕的。

拿到数据之后需要做三件事,第一件,检查数据缺失情况,序列是每周一个数据,如果发现上下两个数据之间缺少一周数据,那么插入一条数据,数值为上下两条记录值的均值。最大可能连续缺失两个数据。

第二,检查日期是否为周五,如果不是周五把日期修正为周五,(最近的没数据的周五)

第三,如果一年周五的周数有53周,那么将52周和53周数据去掉。用51周和第二年第一周数据平均,记为52周数据,日期为51周和第二年第一周中间(不要求周五)

 

还有一个问题,就是要解决类似上述问题,有什么书或资源推荐?

 

  • 写回答

5条回答 默认 最新

  • ProfSnail 2021-02-19 11:57
    关注

    代码编辑完成,基本实现三个需求。

    # coding='utf-8'
    
    import os
    import datetime
    import shutil
    import openpyxl
    from openpyxl import load_workbook
    
    pathOri = r'C:\Coding\Python\CSDN\dateSequence'
    
    xlsxName = 'input.xlsx'
    outputName = 'output.xlsx'
    
    def getDate(value):
    	# 因为excel里面保存的可能是日期格式,也可能是字符串形式。
    	if(str(value.__class__) == "<class 'datetime.datetime'>"):
    		# datetime.datetime格式
    		return value
    	else:
    		# 字符串格式。
    		value_list = value.split('/')
    		year = int(value_list[0])
    		month = int(value_list[1])
    		day = int(value_list[2])
    		rowDay = datetime.date(year, month, day)
    		return rowDay
    
    
    
    def dealEachSheet(inputSheet, outputSheet):
    	inputRows = inputSheet.max_row
    	inputCols = inputSheet.max_column
    	# 将表头原样复制到新文件中
    	for i in range(1, 3):
    		for j in range(1, inputCols+1):
    			outputSheet.cell(row=i, column=j).value = inputSheet.cell(i, j).value
    
    	outputSheet.cell(row=1, column=3).value = "周"
    	outputSheet.cell(row=1, column=4).value = "星期"
    
    	# 假设日期是第二列
    	dateColumn = 1
    	valueColumn = dateColumn + 1
    	weekIndexColumn = dateColumn + 2
    	weekdayColumn = dateColumn + 3
    
    
    	valueDict = {}
    
    	# 记下来上一条记录是几月几号
    	lastDate = None
    	for i in range(3, inputRows+1):
    		eachDate = getDate(inputSheet.cell(i, dateColumn).value)
    		if(eachDate.weekday() != 4):
    			# 因为是从上到下遍历,所以如果不是周五,则优先填充上一周。
    			if eachDate.weekday() < 4:
    				eachDate = eachDate + datetime.timedelta(days=-3-eachDate.weekday())
    			else:
    				eachDate = eachDate + datetime.timedelta(days=4-eachDate.weekday())
    			# 填充上一周
    			if(eachDate != lastDate):
    				pass
    			# 填充到这一周
    			else:
    				eachDate = eachDate + datetime.timedelta(days=7)
    			inputSheet.cell(i, dateColumn).value = eachDate
    		valueDict[eachDate] = inputSheet.cell(i, valueColumn).value
    
    
    	startDate = getDate(inputSheet.cell(3, 1).value)
    	endDate = getDate(inputSheet.cell(inputRows, 1).value)
    
    	week53Dates = []
    
    	eachDate = startDate
    	lastDate = eachDate
    	while eachDate != endDate:
    		# 遍历所有的周五,进行数据插值
    		eachDate = eachDate + datetime.timedelta(days=7)
    		if eachDate not in valueDict.keys():
    			# 如果这一周是个缺失数值,则找到字典中有数值的上一个和下一个,并取这两个数值的平均数
    			# 如果有多个缺失值,比如说是1 缺失 缺失 缺失 10
    			# 则首先补充第一个,补充为  1 5.5 缺失 缺失 10
    			# 接下来补充第二个,补充为  1 5.5 7.75 缺失 10
    			# 接下来补充第三个,补充为  1 5.5 7.75 8.875 10
    			# 采用的是二分插值方法。
    			# 因为每次填充之后,上一个日期总是在列表中的,所以只需要找到下一个进行插分即可。
    			nextDate = eachDate + datetime.timedelta(days=7)
    			while nextDate not in valueDict.keys():
    				nextDate = nextDate + datetime.timedelta(days=7)
    			valueDict[eachDate] = (valueDict[lastDate] + valueDict[nextDate]) / 2;
    		lastDate = eachDate
    		# 在这次遍历中,同时记录一下有53周的日期
    		if eachDate.isocalendar()[1] == 53:
    			week53Dates.append(eachDate)
    
    	# 如果有53周,则用51周五和第二年第一周的日期中间值进行替代。
    	for eachWeek53Date in week53Dates:
    		# 第二年第一周周五
    		week1date = eachWeek53Date + datetime.timedelta(days=7)
    		# 第一年第51周周五
    		week51date = eachWeek53Date + datetime.timedelta(days=-14)
    		# 第一年第52周周五
    		week52date = eachWeek53Date + datetime.timedelta(days=-7)
    		diff = (week1date - week51date) / 2
    
    		# 计算51周周五和第二年第一周周五的中间那一天
    		midDate = week51date + datetime.timedelta(days=diff.days)
    		# 计算中间那一天的数值
    		midValue = (valueDict[week51date] + valueDict[week1date]) / 2
    		# 删除第52周和53周
    		valueDict.pop(eachWeek53Date)
    		valueDict.pop(week52date)
    		valueDict[midDate] = midValue
    
    	keys = sorted(valueDict)
    
    	id = 3
    	weekDict = {0:'星期一',1:'星期二',2:'星期三',3:'星期四',4:'星期五',5:'星期六',6:'星期日'}
    	for key in keys:
    		outputSheet.cell(id, dateColumn).value = key.strftime('%Y/%m/%d')
    		outputSheet.cell(id, valueColumn).value = valueDict[key]
    		outputSheet.cell(id, weekIndexColumn).value = key.isocalendar()[1]
    		outputSheet.cell(id, weekdayColumn).value = weekDict[key.weekday()]
    		id += 1
    
    def main():
    	# 读取文件
    	# 因为原始数据中有许多地方是用公式进行计算得到的,需要指定data_only=True使得读入的时候就是完整的数值。
    	# 比如A286=A285+7等
    	inputWorkbook = load_workbook(os.path.join(pathOri, xlsxName), data_only=True)
    	inputSheet = inputWorkbook[inputWorkbook.sheetnames[0]]
    
    	# 输出文件
    	outputWorkbook = openpyxl.Workbook()
    	outputSheet = outputWorkbook.active
    	outputSheet.title = inputWorkbook.sheetnames[0]
    
    	# 处理文件
    	dealEachSheet(inputSheet, outputSheet)
    	for i in range(1, len(inputWorkbook.sheetnames)):
    		sheetName = inputWorkbook.sheetnames[i]
    		inputSheet = inputWorkbook[sheetName]
    		outputSheet = outputWorkbook.create_sheet(sheetName)
    		dealEachSheet(inputSheet, outputSheet)
    
    	outputWorkbook.save(os.path.join(pathOri, outputName))
    
    
    if __name__ == '__main__':
    	main()
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(4条)

报告相同问题?

悬赏问题

  • ¥15 关于#vscode#的问题:ESP32开发板对接MQTT实现小灯泡的开关
  • ¥15 TMC2209串口模式下读取不到寄存器的值串口助手蓝色字体是发过去的消息,绿色字体是收到的消息,第二行发送读取寄存器的指令但是没有读取到寄存器的值串口助手如下图:接线如下图,如何解决?
  • ¥15 高通安卓11提取完整线刷包软件,或者优博讯dt50顺丰刷机包
  • ¥20 C,有个译码器,换了信道就跑不出原来数据
  • ¥15 MIMIC数据库安装问题
  • ¥60 基于JTag协议开发Fpga下载器上位机,哪位大🐂有偿指导?
  • ¥20 全书网Java爬取数据
  • ¥15 怎么获取红包封面的原始链接,并且获取红包封面序列号
  • ¥100 微信小程序跑脚本授权的问题
  • ¥100 房产抖音小程序苹果搜不到安卓可以付费悬赏