用python对数据表格处理(筛选并删除)失败,求各位看看?

想要解决的问题:每个人入院日期条两两对比,需要找出间隔小于3天的数据行删除。如某某入院日期分别为“2023-01-01,2023-02-07,2023-02-08,2023-05-01,2023-05-02”,需要删除其中2023-02-08,2023-05-02数据所在行。
代码如下,我运行成功后没有达到想要的效果,请问是什么原因?怎么修改避免?非常期待各位的解答~


import pandas as pd
from datetime import datetime, timedelta

# 读取Excel数据
df = pd.read_excel('原始数据.xlsx')

# 将入住时间列转换为datetime类型
df['入院日期'] = pd.to_datetime(df['入院日期'],format='"%Y-%m-%d"',errors='coerce')

# 按姓名列分组
grouped = df.groupby('姓名')

# 定义函数用于处理每个分组
def process_group(group):
    # 对每个分组按入院日期列升序排序
    group = group.sort_values('入院日期')

    # 初始化索引和循环标志
    index = 0
    keep_looping = True

    while keep_looping:
        if index >= len(group) - 1:
            # 已经到达分组末尾,退出循环
            keep_looping = False
        else:
            # 当前行和下一行的入院日期差值
            time_diff = group.iloc[index+1]['入院日期']

            if time_diff <= timedelta(days=3):
                # 入院日期相隔小,删除下一行数据
                group = group.drop(group.index[index+1])
            else:
                index += 1
                # 入院日期相隔大于三天,索引加一继续对 += 1

    return group

# 使用apply方法对每个分处理函数
processed_df = grouped.apply(process_group)

# 将处理后的数据保存为新的Excel文件
processed_df.to_excel('processed_file.xlsx', index=False)
不知道你这个问题是否已经解决, 如果还没有解决的话:
  • 你可以参考下这个问题的回答, 看看是否对你有帮助, 链接: https://ask.csdn.net/questions/7672390
  • 你也可以参考下这篇文章:Python 请将字符串中所有字母全部向后移一位,最后一个字母放在字符串的开头,对比输出修改前和修改后的字符串。
  • 除此之外, 这篇博客: Python时间戳、时间类型转换、日期时间子特征的提取及合并中的 三、时间类型的相互转换 部分也许能够解决你的问题, 你可以仔细阅读以下内容或跳转源博客中阅读:

    1. 时间戳转datetime
    常用场景:分析时需要将数据date字段存储的数字转为直观形式

    datetime.fromtimestamp(1580572800.0) #输出:datetime.datetime(2020, 2, 2, 0, 0)
    datetime.utcfromtimestamp(1580572800.0) #输出: datetime.datetime(2020, 2, 1, 16, 0)
    

    可以发现同一个时间戳数据1580572800.0,fromtimestamp是在localtime背景下,将1970年01月01日08时00分00秒视为起点,将1580572800.0视为总秒数,算出来是2020, 2, 2, 0, 0。utcfromtimestamp是将1970年01月01日00时00分00秒视为起点,所以转换后比上一个时间晚8个小时。

    datetime.fromtimestamp(9999999999) #datetime.datetime(2286, 11, 21, 1, 46, 39)
    

    扩展知识:time.ctime函数可以把一个时间戳(按秒计算的浮点数)转化为time.asctime()形式的str。

    time.ctime(1580572800.0)  #输出'Sun Feb  2 00:00:00 2020'
    

    2. 时间转时间戳
    常用场景:需要将一个时间存储为时间戳,然后存储在数据表中。
    (1)获得localtime的时间戳,最简单方法:time.time()
    (2)把一个任意的datetime时间转时间戳float:
    具体过程:datetime–time.struct_time–float
    time.mktime方法将struct_time时间转为时间戳,需要将datetime时间先通过timetuple()函数转为struct_time类型

    s = time.mktime(datetime(2020,2,2).timetuple())
    print(s)
    

    问题:Python为什么需要struct_time类型做转换中介?
    datetime时间虽然直观,但不能subscriptable(通过index或下标访问),并且datetime object is not iterable。所以当要取一个时刻的年、月、日等子特征时就比较麻烦。如果将其转换为time.struct_time类型后,就可以很方便根据索引或下标形式访问时间子特征。

    datetime.now().timetuple().tm_year  #当前时刻所在年
    datetime.now().timetuple()[1]  #当前时刻所在月份
    

    struct_time包括的9个属性:
    tm_year 年
    tm_mon 月,范围1~12
    tm_mday 日,范围1~31
    tm_hour 小时,范围0~23
    tm_min 分钟,范围0~59
    tm_sec 秒,范围0~61(60或61是闰秒)
    tm_wday 星期,范围0~6(周一为0)
    tm_yday 一年内第几天,范围0~366
    tm_isdst 夏时令,-1,0,1

    mktime的逆函数为localtime和gmtime,既然是逆方法,所以返回值为struct_time类型。

    s = time.mktime(datetime(2020,2,2).timetuple()) #获取时间戳
    time.localtime(s) #时间戳转local时间
    time.gmtime(s) #时间戳转格林威治时间
    time.gmtime(s)[0] #获得tm_year子特征
    

    3.time_struct转datetime
    一种方法是先通过time.mktime转为时间戳,然后通过datetime.fromtimestamp转为datetime。更简便的方法如下:

    structTime = time.localtime()  #time.localtime()返回time_struct格式的当前时间
    datetime(*structTime[:6])
    

    time_struct类似于tuple,tuple是可以切片的,structTime[:6]的type是tuple。星号出现在函数的参数structTime[:6]前面,代表解包。即在列表、元组、集合、字典及其他可迭代对象作为实参,并在前面加*时,系统自动进行解包然后传递给函数的多个单变量参数。

    而如果:

    datetime(*structTime)
    

    会提示:TypeError: function takes at most 8 positional arguments (9 given),思考一下为什么会出现异常?

    4. pandas的pd.to_datetime方法【重点】
    (1)函数定义
    pandas.to_datetime(arg, errors=‘ignore’, dayfirst=False, utc=None, box=True, format=None, exact=True, coerce=False, unit=‘ns’, infer_datetime_format=False)
    该函数常用于原始数据中date字段的转换。函数的返回值依据于输入数据的类型,输入输出对应关系如下:
    list-like: DatetimeIndex
    Series: Series of datetime64 dtype
    scalar: Timestamp

    (2)转换实例
    pandas读取源数据时,比如csv文件,有可能将日期时间特征在定义为object类型。
    举例1:

    s = pd.Series('01/02/1965',dtype='object')
    d = pd.to_datetime(s,format='%m/%d/%Y')
    print(d)
    

    运行结果:
    0 1965-01-02
    dtype: datetime64[ns]
    这个例子中,format=’%m/%d/%Y’参数不写也可。

    s = pd.Series('01/02/1965',dtype='object')
    d = pd.to_datetime(s)
    print(d)
    

    这是因为pandas能猜测出来其为1965年1月2日,但如果日期时间的格式不太符合常理或pandas猜不准情况下就会产生异常。这时需要程序员指定日期时间的格式。

    举例2:

    data = pd.DataFrame({'date':['02/Apr/2013:23:55:00 +0530']})
    pd.to_datetime(data['date'],format='%d/%b/%Y:%H:%M:%S %z')
    

    源数据中的时间’02/Apr/2013:23:55:00 +0530’,如果直接不指定format参数,pandas将无法进行转换为时间。其中的+0530为时区信息,表示相对格林威治时间提前5小时30分钟,即19800秒。

    如果提示错误:‘z’ is a bad directive in format ‘%d/%b/%Y:%H:%M:%S %z’,请升级pandas版本至0.24.2及以上版本,对应命令为:‘conda update pandas’。

    (3)两个坑:
    坑1:原数据如果是时间戳,注意参数unit默认为ns,需要根据情况判断是否将其改为s。
    坑2:转换后的时间极有可能不包含时区属性,如果原数据集是我们国内的数据集,分析时直接用pd.to_datetime转换后,这个时间可能要比我们自认为的时间要晚8个小时。所以用pd.DataFrame转换时间戳时,除非这是一份来自英国这种使用格林威治时间国家的数据,一般都需要用Timestamp.tz_localize方法为没有时区的时间序列赋予时区,然后调用tz_convert函数将其转换到原数据集对应的时区。

    t = pd.to_datetime(1580572800.0,unit='s') #Timestamp('2020-02-01 16:00:00')
    t = t.tz_localize('UTC') #为没有时区的时间序列赋予时区,UTC代表协调世界时,又称为世界统一时间
    t.tz_convert('Asia/Shanghai') #指定到特定时区后,可以用tz_convert将其转换到其它时区
    #上述三行代码可简化为:
    t = pd.to_datetime(1580572800.0,unit='s',utc=True) #utc默认值为None
    t.tz_convert('Asia/Shanghai')  #转换为北京时间
    

    其它时区,可import pytz后,通过pytz.common_timezones来查看

    import pytz
    pytz.common_timezones[-6:]
    

    之前的datetime.now(),默认创建localtime时间,如果要创建格林威治时间,可以如下操作:

    datetime.now(pytz.utc) #输出:datetime.datetime(2020, 2, 9, 14, 22, 25, 565437, tzinfo=<UTC>) 参数写为pytz.UTC也可。
    

    (4)扩展阅读:
    协调世界时(英:Coordinated Universal Time ,法:Temps Universel Coordonné),又称世界统一时间,世界标准时间,国际协调时间。英文(CUT)和法文(TUC)的缩写不同,作为妥协,简称UTC。
    世界标准时间UTC:GMT+0
    GMT:格林尼治平时
    即格林威治时间
    CST时间:也就是北京时间
    北京时间CST:GMT+8

    5. 将pandas中的 Timestamp转换为datetime
    Timestamp是从Python标准库的datetime类继承过来的,表示时间轴上的一个时刻。分辨率为纳秒,64位整数存储,其最小时刻和最大时刻如下:

    pd.Timestamp.min
    #Timestamp('1677-09-21 00:12:43.145225')
    pd.Timestamp.max
    #Timestamp('2262-04-11 23:47:16.854775807')
    

    所以如下代码会报错:

    pd.to_datetime('13000101', format='%Y%m%d')
    

    解决方案为:

    pd.to_datetime('13000101', format='%Y%m%d', errors='ignore')
    #datetime.datetime(1300, 1, 1, 0, 0)
    

    或:

    pd.to_datetime('13000101', format='%Y%m%d', errors='coerce')
    #NaT
    

    pd.to_pydatetime方法可以Convert a Timestamp object to a native Python datetime object.

     pd.Timestamp.to_pydatetime(pd.to_datetime('2020/2/3'))
    

    6.字符串到时间类型的转换
    (1)字符串到struct_time
    调用方法: time.strptime(string[, format])
    python中日期时间格式化符号:
    %y 两位数的年份表示(00-99)
    %Y 四位数的年份表示(000-9999)
    %m 月份(01-12)
    %d 月内中的一天(0-31)
    %H 24小时制小时数(0-23)
    %I 12小时制小时数(01-12)
    %M 分钟数(00=59)
    %S 秒(00-59)
    %a 本地简化星期名称
    %A 本地完整星期名称
    %b 本地简化的月份名称
    %B 本地完整的月份名称
    %c 本地相应的日期表示和时间表示
    %j 年内的一天(001-366)
    %p 本地A.M.或P.M.的等价符
    %U 一年中的星期数(00-53)星期天为星期的开始
    %w 星期(0-6),星期天为星期的开始
    %W 一年中的星期数(00-53)星期一为星期的开始
    %x 本地相应的日期表示
    %X 本地相应的时间表示
    %Z 当前时区的名称
    %% %号本身

    time.strptime('2020-02-05 13:45:20','%Y-%m-%d %H:%M:%S')
    

    结果为:
    time.struct_time(tm_year=2020, tm_mon=2, tm_mday=5, tm_hour=13, tm_min=45, tm_sec=20, tm_wday=2, tm_yday=36, tm_isdst=-1)

    (2)struct_time到字符串

    t = time.strptime('2020-02-05 13:45:20','%Y-%m-%d %H:%M:%S')
    s = time.strftime('%Y-%m-%d',t)
    print(s)  #输出2020-02-05
    

    各种时间类型转换示意图如下图所示。
    在这里插入图片描述
    上图中,其实datetime和字符串之间其实还可以画出来两条线,datetime.strptime和datetime.strftime,功能自行百度。

  • 您还可以看一下 Toby老师的python机器学习-乳腺癌细胞挖掘课程中的 非平衡数据是什么?对模型有什么坏处?小节, 巩固相关知识点

如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 写成博客, 将相关链接放在评论区, 以帮助更多的人 ^-^