• Pandas数据类型自行变换及数据类型转换失败情况分析与解决方法


    最近,在进行数据处理过程中,频繁使用Pandas进行DataFrame关联、合并、数据类型变换操作,当到最后数据入库(MongoDB)时,出现部分整型数据变成浮点型,以及时间转字符串存储时,偶尔出现少部分存储为时间戳整型数据(也就是说偶尔出现时间转换为字符串转换失败的情况),如下图所示。
    在这里插入图片描述

    1. 整型变浮点型情况

    1.1. 问题情况再现

    1.1.1. 空值情况

    在DataFrame表间关联(merge)、合并(concat)过程中,容易出现数据为空的情况,则其对应的数据列将为float64

    import pandas as pd
    
    df1 = pd.DataFrame({'yearmonth': ['202201','202202','202203'],
                       'monthnum': [1,2,3]})
    
    df2 = pd.DataFrame({'yearmonth': ['202201','202202'],
                       'testint': [11,12]})
    print('df2数据类型\n',df2.dtypes)
    df = pd.merge(left=df1,right=df2,how='left',on=['yearmonth'])
    print('连接合并后数据类型\n',df.dtypes)
    df
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    运行程序输出结果如下所示,“testint”列的数据类型由int64变成float64。
    在这里插入图片描述

    1.1.2. 正负无穷情况(除数为0)

    在DataFrame表中,进行数据计算过程中,如果出现除数为零,则表示为正负无穷,对应的列为float64类型。

    import pandas as pd
    
    df1 = pd.DataFrame({'yearmonth': ['202201','202202','202203'],
                       'monthnum': [1,2,3]})
    print('df1数据类型\n',df1.dtypes)
    df1.loc[:,'monthnum'] = df1['monthnum']/0
    print('除零后,df1数据类型\n',df1.dtypes)
    df1
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    在这里插入图片描述

    1.1.3. 读取含有空值的数据源

    以读取简单的csv数据文件为例:

    import pandas as pd
    df = pd.read_csv('nan.csv')
    print('数据类型\n',df.dtypes)
    df
    
    • 1
    • 2
    • 3
    • 4

    数据表nan.csv中,B列有个空值,则读取数据后,B列为float64类型。
    在这里插入图片描述

    1.2. 小结

    对于DataFrame表,在数据处理过程中,如果出现空值(nan)、正负无穷(inf),pandas将转换为默认的float64数据类型。

    1.3. 解决方案

    在关键点,例如存储、计算前,如有必要,按数据字典定义类型,强制统一转换为定义类型。

    注意:
    首先,把空值处理掉,例如填充0,或其他需要的值;
    如果,一列存在多种类型数据,需要单独处理,详见后续介绍。

    2. 时间类型转字符串失败情况

    2.1. 关于pandas时间类型与整型、字符串型转换

    序号功能原数据类型目标数据类型方法
    1时间转整型datetime[ns]int64df[‘列名’].astype(‘int64’)
    2时间转字符串datetime[ns]str(object)df[‘列名’].dt.strftime(‘%Y-%m-%d’)
    3整型转时间int64datetime[ns]df[‘列名’].astype(‘datetime64[ns]’)
    4字符串转时间str(object)datetime[ns]df[‘列名’]…astype(‘datetime64’)

    其中:时间类型单个数据的类型为对象,其他为正常python数据类型,例如int、str等。

    import pandas as pd
    import time
    
    df = pd.DataFrame({'yearmonth': ['202201','202202','202202'],
                       'monthnum': [1,2,1],
                       'datetime': [pd.Timestamp('2018-03-10 21:00:01'),pd.Timestamp('2019-03-10 12:02:00'),pd.Timestamp('2019-09-10 12:02:00')]})
    df['datetimenum'] = df['datetime'].astype('int64')
    df
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    在这里插入图片描述

    df.loc[:,'datetimenum'] = df['datetimenum'].astype('datetime64[ns]')
    df['datetimestr'] = df['datetime'].dt.strftime('%Y-%m-%d')
    df.loc[:,'datetimestr'] = df['datetimestr'].astype('datetime64')
    
    
    • 1
    • 2
    • 3
    • 4

    在这里插入图片描述

    2.2. 单列复杂数据类型情况及解决方法

    由于很难模拟出时间类型转字符串失败情况,文中仅仅采用按行强制赋值方式构建分析样本。
    分别直接赋值整型时间戳和字符串时间,如下列所示。

    df.loc[1,'datetimenum'] = 1611532800000
    df.loc[2,'datetimestr'] = '2022-08-10'
    df.dtypes
    
    # 下面代码报错!
    df.loc[:,'datetimenum'] = df['datetimenum'].astype('datetime64')
    df.loc[:,'datetimenum'] = df['datetimenum'].astype('datetime64[ns]')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    对于目标为时间类型的列(本例中的datetimenum),如果某行存储一个整型数据,即使是时间戳整数,这种混合情况,表现类型为“Object”,在类型转换时将会报错。

    • ValueError: mixed datetimes and integers in passed array

    对于这种复杂混合类型的列,可以采用逐行按具体数据类型转换到目标类型,如下文把混合时间、字符串、时间戳整数的数据统一转换为字符串类型。

    import numpy as np
    import time
    
    def f(timeNum):
        if type(timeNum) == type(1):
            timeTemp = float(timeNum/1000)
            tupTime = time.localtime(timeTemp)
            #stadardTime = time.strftime("%Y-%m-%d %H:%M:%S", tupTime)
            stadardTime = time.strftime("%Y-%m-%d", tupTime)
        elif type(timeNum) == type('2022-08-18'):
            stadardTime = timeNum
        else:
            print(type(timeNum))   
            #stadardTime = timeNum.strftime("%Y-%m-%d %H:%M:%S")
            stadardTime = timeNum.strftime("%Y-%m-%d")
            
        print(timeNum)
    
        return pd.Series([stadardTime])
    
    df['datetimestr'] = df['datetimestr'].apply(lambda x:f(x))
    df
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    在这里插入图片描述

    2.3. 相关内容,数据类型识别

    Python中常用isinstance()和type()内置函数判断数据类型:

    • isinstance()是Python中的一个内建函数。是用来判断一个对象的变量类型。
      isinstance(object, classinfo)
      如果参数object是classinfo的实例,或者object是classinfo类的子类的一个实例, 返回True。如果object不是一个给定类型的的对象, 则返回结果总是False。
    • type函数是Python的内置函数,返回参数的类型。
    # type函数
    variateint = 100
    variatestr = '100'
    if type(variateint) == type(1):
        print('int')
    if type(variatestr) == type('hello'):
        print('str')
    # isinstance函数
    if isinstance(variateint,int):
        print('int')
    if isinstance(variatestr,str):
        print('str')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    补充: 
    type只接收一个参数,不但可以判断变量是否属于某个类型,而且可以得到参数变量未知的所属的类型;而isinstance只能判断是否属于某个已知类型,不能直接得到变量未知的所属的类型

    参考:

    [1].小铭博客. python中判断变量的类型. 2018.07
    [2]. 肖永威. Pandas缺失值inf与nan处理实践. CSDN博客. 2022.08

  • 相关阅读:
    IDEA spring-boot项目启动,无法加载或找到启动类问题解决
    QT·ListView 的增删改查实现
    Avalonia 实现简单的IM即时通讯、视频通话(源码,支持国产系统,统信、银河麒麟)
    HTML5+CSS3+JS小实例:鼠标滚轮水平滚动
    全面的ASP.NET Core Blazor简介和快速入门
    微信公众号密码转换的密钥
    【Pytorch with fastai】第 12 章 :从零开始的语言模型
    git项目管理中如何fork别人的代码以及如何拉取最新的源项目代码
    【Vue】事件处理
    保持数据库唯一的三种方式
  • 原文地址:https://blog.csdn.net/xiaoyw/article/details/126411007