当前位置: 首页 > news >正文

Pandas:从一个DataFrame中直接索引赋值到另一个索引位置出错的Bug及其解决方案

这里写自定义目录标题

  • 动机
    • 代码1,这个代码是有问题的
    • 代码2,这个代码是我调试代码。拆分代码,最后找到问题所在,这个代码是正确的
    • 代码3。本以为找到问题所在之后,又稍微修改了下代码 2,这个代码还是没问题的
    • 代码4。本以为找到问题所在之后,又稍微修改了下代码 1,这个代码还是没问题的

动机

今天写代码,处理通量站数据的时候出错。代码逻辑没问题,但是就是得不到想要的结果,然后做个笔记。可能问题是我自己遇到的,在这里其他人也没经历,所以也看不懂。总体而言:Pandas:从一个DataFrame中直接索引赋值到另一个索引位置出错。必须使用一个中间变量去固定。虽然解决了问题,好像还是不知道为什么。我尝试过换python 版本(3.7 和 3.10),但是没用。

代码1,这个代码是有问题的

import pandas as pd
import numpy as np

# 假设 siteData_reindexed 是你的 DataFrame
# 这里是一个示例 DataFrame
# siteData_reindexed = pd.DataFrame({
#     'SW_IN': [np.nan, 1, 2, np.nan, 4, np.nan, 6, 7, 8, 9, 10, np.nan],
#     'LW_IN': [1, 2, np.nan, 4, np.nan, 6, 7, np.nan, 9, 10, np.nan, 12],
#     'WS': [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]
# }, index=pd.date_range(start="2019-06-26 14:00:00", end="2020-11-17 10:00:00", freq='60min'))

# 计算每天的缺失值比例
rad_daily_miss_rate = siteData_reindexed[["SW_IN", "LW_IN"]].resample('D').apply(lambda x: x.isnull().mean())

# 创建一个新的 DataFrame 来存储填补后的数据
filled_data = siteData_reindexed.copy()

# 遍历每天的缺失值比例
for date, ratios in rad_daily_miss_rate.iterrows():
    print("##" * 30)
    sw_in_ratio = ratios['SW_IN']
    lw_in_ratio = ratios['LW_IN']

    print(date, sw_in_ratio, lw_in_ratio)
    print("前:")
    print(filled_data.loc[date - pd.Timedelta(hours=1): date + pd.Timedelta(hours=23), ["SW_IN", "LW_IN"]])

    # 检查缺失比例
    if sw_in_ratio == 0 and lw_in_ratio == 0:
        print("没有参加填补")
        # 如果缺失比例为0,什么都不做
        continue
    elif sw_in_ratio < 0.4 and lw_in_ratio < 0.4:
        # 如果缺失比例小于40%,使用 .ffill() 和 .bfill() 填补当天的 'SW_IN' 和 'LW_IN'
        filled_data.loc[date:date + pd.Timedelta(hours=23), ['SW_IN', 'LW_IN']] = filled_data.loc[date:date + pd.Timedelta(hours=23), ['SW_IN', 'LW_IN']].ffill().bfill()
    else:
        # 否则,使用前一天的24小时数据填补 'SW_IN' 和 'LW_IN'
        previous_day = date - pd.Timedelta(days=1)
        if previous_day in filled_data.index:
            print(f"填补前一天的数据: {previous_day}")
            print(filled_data.loc[previous_day:previous_day + pd.Timedelta(hours=23), ['SW_IN', 'LW_IN']])
            # 这里就是问题所在的位置
            filled_data.loc[date:date + pd.Timedelta(hours=23), ['SW_IN', 'LW_IN']] = filled_data.loc[previous_day:previous_day + pd.Timedelta(hours=23), ['SW_IN', 'LW_IN']]
        else:
            print(f"前一天 {previous_day} 的数据不存在")

    print("后:")
    print(filled_data.loc[date - pd.Timedelta(hours=1): date + pd.Timedelta(hours=23), ["SW_IN", "LW_IN"]])

# 结果
# print(filled_data)

问题出在这里 filled_data.loc[date:date + pd.Timedelta(hours=23), ['SW_IN', 'LW_IN']] = filled_data.loc[previous_day:previous_day + pd.Timedelta(hours=23), ['SW_IN', 'LW_IN']]。必须使用一个中间变量去将数值固定,否则在内存中索引,会匹配错误。我是这么理解的。可能也是我写代码习惯不太好。

代码2,这个代码是我调试代码。拆分代码,最后找到问题所在,这个代码是正确的

"""

"""

# 计算每天的缺失值比例
rad_daily_miss_rate = siteData_reindexed[["SW_IN","LW_IN"]].resample('D').apply(lambda x: x.isnull().mean())

# 创建一个新的 DataFrame 来存储填补后的数据
filled_data= siteData_reindexed.copy()

# 遍历每天的缺失值比例
for date, ratios in rad_daily_miss_rate.iterrows():

    if date <= pd.Timestamp("2019-06-29 23:00:00") :

        sw_in_ratio = ratios['SW_IN']
        lw_in_ratio = ratios['LW_IN']

        # 检查缺失比例
        if sw_in_ratio == 0 and lw_in_ratio == 0:
            print("没有参加填补")
            # 如果缺失比例为0,什么都不做
            continue
        elif sw_in_ratio < 0.4 and lw_in_ratio < 0.4:
            print("进入  sw_in_ratio < 0.4 and lw_in_ratio < 0.4 ")
            # 如果缺失比例小于30%,使用 .ffill() 和 .bfill() 填补当天的 'SW_IN' 和 'LW_IN'
            filled_data.loc[date:date + pd.Timedelta(hours=23), ['SW_IN', 'LW_IN']] = filled_data.loc[date:date + pd.Timedelta(hours=23), ['SW_IN', 'LW_IN']].ffill().bfill()
        else:
            print("进入 else")
            # 否则,使用前一天的24小时数据填补 'SW_IN' 和 'LW_IN'
            # 这个放置位置的索引
            timeRange = pd.date_range(start= date, end=date + pd.Timedelta(days=1), freq='60min')
            for date_index in timeRange:

                # 确保匹配到的是前一天的数据
                print(f"date_index: {date_index}")
                # 必须使用一个中间变量去将数值固定,否则在内存中索引,会匹配错误
                previous_day_value = siteData_reindexed.loc[date_index - pd.Timedelta(days=1), ['SW_IN', 'LW_IN']]
                print(f"前一天数据: {previous_day_value}")

                # 检查是否能成功填充
                filled_data.loc[date_index, ['SW_IN', 'LW_IN']] = previous_day_value
                print(f"填补后的数据: {filled_data.loc[date_index, ['SW_IN', 'LW_IN']]}")

        print("后:")
        print(filled_data.loc[date:date + pd.Timedelta(hours=23),["SW_IN","LW_IN"]])
# 结果
# print(filled_data)

代码3。本以为找到问题所在之后,又稍微修改了下代码 2,这个代码还是没问题的

"""

"""

# 计算每天的缺失值比例
rad_daily_miss_rate = siteData_reindexed[["SW_IN","LW_IN"]].resample('D').apply(lambda x: x.isnull().mean())

# 创建一个新的 DataFrame 来存储填补后的数据
filled_data= siteData_reindexed.copy()

# 遍历每天的缺失值比例
for date, ratios in rad_daily_miss_rate.iterrows():

    if date <= pd.Timestamp("2019-06-29 23:00:00") :

        sw_in_ratio = ratios['SW_IN']
        lw_in_ratio = ratios['LW_IN']

        # 检查缺失比例
        if sw_in_ratio == 0 and lw_in_ratio == 0:
            print("没有参加填补")
            # 如果缺失比例为0,什么都不做
            continue
        elif sw_in_ratio < 0.4 and lw_in_ratio < 0.4:
            print("进入  sw_in_ratio < 0.4 and lw_in_ratio < 0.4 ")
            # 如果缺失比例小于30%,使用 .ffill() 和 .bfill() 填补当天的 'SW_IN' 和 'LW_IN'
            filled_data.loc[date:date + pd.Timedelta(days=1), ['SW_IN', 'LW_IN']] = filled_data.loc[date:date + pd.Timedelta(hours=23), ['SW_IN', 'LW_IN']].ffill().bfill()
        else:
            print("进入 else")
            # 否则,使用前一天的24小时数据填补 'SW_IN' 和 'LW_IN'
            # 变量前一天
            previous_day = date - pd.Timedelta(days=1)
            # 前一天的数据
            previous_day_data = siteData_reindexed.copy().loc[previous_day:date, ['SW_IN', 'LW_IN']]

            filled_data.loc[date:date + pd.Timedelta(days=1), ['SW_IN', 'LW_IN']] = previous_day_data

            # 这个放置位置的索引
            # timeRange = pd.date_range(start= date, end=date + pd.Timedelta(days=1), freq='60min')
            # for date_index in timeRange:
            #
            #     # 确保匹配到的是前一天的数据
            #     print(f"date_index: {date_index}")
            #     # 必须使用一个中间变量去将数值固定,否则在内存中索引,会匹配错误
            #     previous_day_value = siteData_reindexed.loc[date_index - pd.Timedelta(days=1), ['SW_IN', 'LW_IN']]
            #     print(f"前一天数据: {previous_day_value}")
            #
            #     # 检查是否能成功填充
            #     filled_data.loc[date_index, ['SW_IN', 'LW_IN']] = previous_day_value
            #     print(f"填补后的数据: {filled_data.loc[date_index, ['SW_IN', 'LW_IN']]}")

        print("后:")
        print(filled_data.loc[date:date + pd.Timedelta(hours=23),["SW_IN","LW_IN"]])
# 结果
# print(filled_data)

代码4。本以为找到问题所在之后,又稍微修改了下代码 1,这个代码还是没问题的

import pandas as pd
import numpy as np

# 创建一个示例 DataFrame
data = {
    'SW_IN': [np.nan, 1, 2, np.nan, 4, np.nan, 6, 7, 8, 9, 10, np.nan],
    'LW_IN': [1, 2, np.nan, 4, np.nan, 6, 7, np.nan, 9, 10, np.nan, 12],
    'WS': [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]
}
index = pd.date_range(start="2019-06-26 14:00:00", end="2020-11-17 10:00:00", freq='60min')
siteData_reindexed = pd.DataFrame(data, index=index)

# 计算每天的缺失值比例
rad_daily_miss_rate = siteData_reindexed[["SW_IN", "LW_IN"]].resample('D').apply(lambda x: x.isnull().mean())

# 创建一个新的 DataFrame 来存储填补后的数据
filled_data = siteData_reindexed.copy()

# 遍历每天的缺失值比例
for date, ratios in rad_daily_miss_rate.iterrows():
    print("##" * 30)
    sw_in_ratio = ratios['SW_IN']
    lw_in_ratio = ratios['LW_IN']

    print(date, sw_in_ratio, lw_in_ratio)
    print("前:")
    print(filled_data.loc[date - pd.Timedelta(hours=1): date + pd.Timedelta(hours=23), ["SW_IN", "LW_IN"]])

    # 检查缺失比例
    if sw_in_ratio == 0 and lw_in_ratio == 0:
        print("没有参加填补")
        continue
    elif sw_in_ratio < 0.4 and lw_in_ratio < 0.4:
        # 填补当天的缺失值
        filled_data.loc[date:date + pd.Timedelta(hours=23), ['SW_IN', 'LW_IN']] = filled_data.loc[date:date + pd.Timedelta(hours=23), ['SW_IN', 'LW_IN']].ffill().bfill()
    else:
        # 使用前一天的24小时数据填补
        previous_day = date - pd.Timedelta(days=1)
        if previous_day in filled_data.index:
            print(f"填补前一天的数据: {previous_day}")
            previous_data = filled_data.loc[previous_day:previous_day + pd.Timedelta(hours=23), ['SW_IN', 'LW_IN']]
            print("前一天的数据:")
            print(previous_data)

            # 确保赋值的索引对齐
            filled_data.loc[date:date + pd.Timedelta(hours=23), ['SW_IN', 'LW_IN']] = previous_data.copy()
        else:
            print(f"前一天 {previous_day} 的数据不存在")

    print("后:")
    print(filled_data.loc[date - pd.Timedelta(hours=1): date + pd.Timedelta(hours=23), ["SW_IN", "LW_IN"]])

# 结果
# print(filled_data)

相关文章:

  • 定时器——时基
  • 谈谈 wait 和 notify
  • Web项目测试专题(七)安全性测试
  • AI前端开发赋能自主创业:ScriptEcho助你乘风破浪
  • 前端布局的方式有哪些
  • Qt 中使用 ffmpeg 获取采集卡数据录制视频
  • K8s 证书认知(K8s Certificate Awareness)
  • 洛谷P8707 [蓝桥杯 2020 省 AB1] 走方格
  • HBuilderX中uni-app打开页面时,如何用URL传递参数,Query参数传递
  • Java 与设计模式(15):模板方法模式
  • 前端如何实现一个五星评价,鼠标滑动,前边星星颜色的变黄,后边的不变;
  • java后端开发day16--字符串(二)
  • 25/2/17 <嵌入式笔记> 桌宠代码解析
  • VisionMaster4.4 python脚本 图像处理 转换函数 爱之初体验
  • recent移除task时,结束其所有进程和service(全Android版本)
  • 日常开发中,使用JSON.stringify来实现深拷贝的坑
  • PHP支付宝--转账到支付宝账户
  • 计算机专业知识【探秘 C/S 工作模式:原理、应用与网络协议案例】
  • NBT群落物种级丰度鉴定新方法sylph
  • 【C语言】有序数组的平方
  • 德州一女子做医美突发心脏骤停昏迷一个多月,涉事机构已关门拆招牌
  • 四川省外卖骑手接单将不再强制要求上传健康证
  • 美发布“金穹”导弹防御系统发展规划
  • 广东茂名信宜出现龙卷,一家具厂铁皮房受损
  • 国家发改委:内卷式竞争扭曲市场机制、扰乱公平竞争秩序,必须整治
  • 甘肃白银煤矿透水事故仍有3人失联,现场约510立方米煤泥拥堵巷道