最近,在进行数据处理过程中,频繁使用Pandas进行DataFrame关联、合并、数据类型变换操作,当到最后数据入库(MongoDB)时,出现部分整型数据变成浮点型,以及时间转字符串存储时,偶尔出现少部分存储为时间戳整型数据(也就是说偶尔出现时间转换为字符串转换失败的情况),如下图所示。
在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
运行程序输出结果如下所示,“testint”列的数据类型由int64变成float64。
在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
以读取简单的csv数据文件为例:
import pandas as pd
df = pd.read_csv('nan.csv')
print('数据类型\n',df.dtypes)
df
数据表nan.csv中,B列有个空值,则读取数据后,B列为float64类型。
对于DataFrame表,在数据处理过程中,如果出现空值(nan)、正负无穷(inf),pandas将转换为默认的float64数据类型。
在关键点,例如存储、计算前,如有必要,按数据字典定义类型,强制统一转换为定义类型。
注意:
首先,把空值处理掉,例如填充0,或其他需要的值;
如果,一列存在多种类型数据,需要单独处理,详见后续介绍。
序号 | 功能 | 原数据类型 | 目标数据类型 | 方法 |
---|---|---|---|---|
1 | 时间转整型 | datetime[ns] | int64 | df[‘列名’].astype(‘int64’) |
2 | 时间转字符串 | datetime[ns] | str(object) | df[‘列名’].dt.strftime(‘%Y-%m-%d’) |
3 | 整型转时间 | int64 | datetime[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
df.loc[:,'datetimenum'] = df['datetimenum'].astype('datetime64[ns]')
df['datetimestr'] = df['datetime'].dt.strftime('%Y-%m-%d')
df.loc[:,'datetimestr'] = df['datetimestr'].astype('datetime64')
由于很难模拟出时间类型转字符串失败情况,文中仅仅采用按行强制赋值方式构建分析样本。
分别直接赋值整型时间戳和字符串时间,如下列所示。
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]')
对于目标为时间类型的列(本例中的datetimenum),如果某行存储一个整型数据,即使是时间戳整数,这种混合情况,表现类型为“Object”,在类型转换时将会报错。
对于这种复杂混合类型的列,可以采用逐行按具体数据类型转换到目标类型,如下文把混合时间、字符串、时间戳整数的数据统一转换为字符串类型。
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
Python中常用isinstance()和type()内置函数判断数据类型:
# 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')
补充:
type只接收一个参数,不但可以判断变量是否属于某个类型,而且可以得到参数变量未知的所属的类型;而isinstance只能判断是否属于某个已知类型,不能直接得到变量未知的所属的类型
参考:
[1].小铭博客. python中判断变量的类型. 2018.07
[2]. 肖永威. Pandas缺失值inf与nan处理实践. CSDN博客. 2022.08