将包含nan的Pandas列转换为dtype ' int '

我将数据从.csv文件读取到Pandas数据框架,如下所示。对于其中一列,即id,我想将列类型指定为int。问题是id系列有缺失/空值。

当我试图在读取.csv时将id列转换为整数时,我得到:

df= pd.read_csv("data.csv", dtype={'id': int})
error: Integer column has NA values

或者,我尝试转换列类型后,阅读如下,但这一次我得到:

df= pd.read_csv("data.csv")
df[['id']] = df[['id']].astype(int)
error: Cannot convert NA to integer

我该如何解决这个问题?

353128 次浏览

整数列中缺少NaN代表是熊猫“问题”

通常的解决方法是简单地使用浮动。

如果你可以修改你存储的数据,使用一个哨兵值缺少id。一个常见的用例,由列名推断,因为id是一个整数,严格大于零,你可以使用0作为哨兵值,这样你就可以写

if row['id']:
regular_process(row)
else:
special_process(row)

假设您的DateColumn格式3312018.0应该转换为03/31/2018作为字符串。并且,一些记录丢失或为0。

df['DateColumn'] = df['DateColumn'].astype(int)
df['DateColumn'] = df['DateColumn'].astype(str)
df['DateColumn'] = df['DateColumn'].apply(lambda x: x.zfill(8))
df.loc[df['DateColumn'] == '00000000','DateColumn'] = '01011980'
df['DateColumn'] = pd.to_datetime(df['DateColumn'], format="%m%d%Y")
df['DateColumn'] = df['DateColumn'].apply(lambda x: x.strftime('%m/%d/%Y'))

我的用例是在加载到DB表之前修改数据:

df[col] = df[col].fillna(-1)
df[col] = df[col].astype(int)
df[col] = df[col].astype(str)
df[col] = df[col].replace('-1', np.nan)

删除nan,转换为int,转换为str,然后重新插入nan。

它不漂亮,但它完成了工作!

我在使用pyspark时遇到了这个问题。由于这是运行在jvm上的代码的python前端,它需要类型安全,使用float而不是int是不可取的。我通过将pandas pd.read_csv包装在一个函数中来解决这个问题,该函数将在将用户定义的列转换为所需类型之前,用用户定义的填充值填充用户定义的列。这是我最终使用的:

def custom_read_csv(file_path, custom_dtype = None, fill_values = None, **kwargs):
if custom_dtype is None:
return pd.read_csv(file_path, **kwargs)
else:
assert 'dtype' not in kwargs.keys()
df = pd.read_csv(file_path, dtype = {}, **kwargs)
for col, typ in custom_dtype.items():
if fill_values is None or col not in fill_values.keys():
fill_val = -1
else:
fill_val = fill_values[col]
df[col] = df[col].fillna(fill_val).astype(typ)
return df

首先删除包含NaN的行。然后对其余行进行整型转换。 最后再次插入删除的行。 希望它将工作

如果可以删除带有NaN值的行,则可以使用.dropna()

df = df.dropna(subset=['id'])
< p >或者, 使用.fillna().astype()将NaN替换为值并将其转换为int

我在处理具有大整数的CSV文件时遇到了这个问题,而其中一些整数缺失(NaN)。使用float作为类型是不可取的,因为我可能会失去精度。

我的解决方案是使用STR作为中间类型。 然后,您可以在稍后的代码中将字符串转换为int。我将NaN替换为0,但你可以选择任何值
df = pd.read_csv(filename, dtype={'id':str})
df["id"] = df["id"].fillna("0").astype(int)

为了说明,这里有一个浮动可能会失去精度的例子:

s = "12345678901234567890"
f = float(s)
i = int(f)
i2 = int(s)
print (f, i, i2)

输出为:

1.2345678901234567e+19 12345678901234567168 12345678901234567890

如果你确实想在一个列中组合整数和nan,你可以使用'object'数据类型:

df['col'] = (
df['col'].fillna(0)
.astype(int)
.astype(object)
.where(df['col'].notnull())
)

这将用一个整数替换nan(不管哪个),转换为int,转换为object,最后重新插入nan。

这里的大多数解决方案都告诉您如何使用占位符整数来表示null。但是,如果不确定源数据中不会出现整数,那么这种方法就没有帮助。我的方法将格式浮动没有他们的十进制值,并将null转换为None。结果是一个对象数据类型,当加载到CSV中时,它看起来像一个带空值的整数字段。

keep_df[col] = keep_df[col].apply(lambda x: None if pandas.isnull(x) else '{0:.0f}'.format(pandas.to_numeric(x)))

在0.24版本中。+ pandas获得了保存缺少值的整型dtypes的能力。

可空整数数据类型

Pandas可以使用arrays.IntegerArray表示可能缺少值的整数数据。这是在pandas中实现的扩展类型。它不是整数的默认dtype,也不会被推断出来;必须显式地将dtype传递给array()Series:

arr = pd.array([1, 2, np.nan], dtype=pd.Int64Dtype())
pd.Series(arr)


0      1
1      2
2    NaN
dtype: Int64

将列转换为可空整数使用:

df['myCol'] = df['myCol'].astype('Int64')

现在可以创建一个pandas列,其中包含dtype int的nan,因为它现在正式添加在pandas 0.24.0上

pandas 0.24。X发行说明 引用:“Pandas获得了保存缺少值的整型dtypes的能力 < / p >

import pandas as pd


df= pd.read_csv("data.csv")
df['id'] = pd.to_numeric(df['id'])

使用pd.to_numeric ()

df["DateColumn"] = pd.to_numeric(df["DateColumn"])

简单干净

从Pandas 1.0.0开始,你可以使用Pandas了。NA的价值观。这不会强制缺少值的整数列为浮点数。

在读取数据时,您需要做的是:

df= pd.read_csv("data.csv", dtype={'id': 'Int64'})

注意'Int64'被引号括起来,I是大写的。这区分了Panda的'Int64'和numpy的'Int64'。

作为旁注,这也适用于.astype()

df['id'] = df['id'].astype('Int64')
< p >文档 https://pandas.pydata.org/pandas-docs/stable/user_guide/integer_na.html < / p >

试试这个:

df[['id']] = df[['id']].astype(pd.Int64Dtype())

如果你打印它是dtypes,你将得到id Int64而不是正常的one int64

几周前,我遇到了一些离散的功能被格式化为“对象”的问题。这个解决方案似乎奏效了。

for col in discrete:
df[col] = pd.to_numeric(df[col],errors='coerce').astype(pd.Int64Dtype())

如果你想在链接方法时使用它,你可以使用assign:

df = (
df.assign(col = lambda x: x['col'].astype('Int64'))
)

与许多其他解决方案一样,Int64的问题是,如果你有null值,它们会被<NA>值替换,而这些值不适用于熊猫默认的'NaN'函数,如isnull()fillna()。或者如果你将值转换为-1,你可能会在删除你的信息的情况下结束。我的解决方案有点蹩脚,但将用np.nan提供int值,允许nan函数在不影响您的值的情况下工作。

            def to_int(x):
try:
return int(x)
except:
return np.nan


df[column] = df[column].apply(to_int)

使用.fillna()将所有NaN值替换为0,然后使用astype(int)将其转换为int

df['id'] = df['id'].fillna(0).astype(int)

对于任何需要在包含NULL/ nan的列中具有int值,但在其他答案中提到的不能使用pandas版本0.24.0可空整数特性的约束下工作的人,我建议使用pd.where将列转换为对象类型:

df = df.where(pd.notnull(df), None)

这将数据帧中的所有nan转换为None,将混合类型的列作为对象,但将int值保留为int,而不是float。

我也遇到过类似的问题。这就是我的解决方案:

def toint(zahl = 1.1):
try:
zahl = int(zahl)
except:
zahl = np.nan
return zahl


print(toint(4.776655), toint(np.nan), toint('test'))

4楠楠

df = pd.read_csv("data.csv")
df['id'] = df['id'].astype(float)
df['id'] = toint(df['id'])

首先,你需要指定新的整数类型Int8(…Int64),它可以处理空整数数据(pandas version >= 0.24.0)

df = df.astype('Int8')

但是你可能想要只针对包含NaN/null的整数数据的特定列:

df = df.astype({'col1':'Int8','col2':'Int8','col3':'Int8')

在这一点上,NaN被转换为<NA>,如果你想用df.fillna()改变默认的空值,你需要在你想改变的列上强制对象数据类型,否则你会看到 TypeError: <U1 cannot be converted to an IntegerDtype < / p >

你可以通过 df = df.astype(object)如果你不介意将每个列的数据类型更改为object(单独地,每个值的类型仍然保留)…或

. df = df.astype({"col1": object,"col2": object})

这应该有助于强制将混合了null值的整数列保持为整数格式,并将空值更改为您喜欢的任何值。我不能说这种方法的效率,但它适用于我的格式化和打印目的。

我认为@Digestible1010101的方法更适合Pandas 1.2。+版本,像这样的东西应该做的工作:

df = df.astype({
'col_1': 'Int64',
'col_2': 'Int64',
'col_3': 'Int64',
'col_4': 'Int64', })

无论你的pandas系列是object数据类型还是简单的float数据类型,下面的方法都是有效的

df = pd.read_csv("data.csv")
df['id'] = df['id'].astype(float).astype('Int64')

因为我在这里没有看到答案,我不妨加上它:

如果你因为某种原因仍然不能处理np,可以用一行程序将nan转换为空字符串。Na或者pd。我和我一样,在使用旧版本的熊猫库时:

df.select_dtypes('number').fillna(-1).astype(str).replace('-1', '')

和熊猫一起。24版本,类型Int64支持nan。

如果你的浮点数没有四舍五入、上下五舍五入或四舍五入,你可能会遇到一个错误。

df['A'] = np.floor(pd.to_numeric(df['A'], errors='coerce')).astype('Int64')
< p >来源: https://stackoverflow.com/a/67021201/1363742 < / p >

下面的解决方案是唯一符合我的目的的解决方案,我认为在使用最新的Pandas版本时,它是最佳的解决方案。

df['A'] = np.floor(pd.to_numeric(df['A'],
errors='coerce'))
.astype('Int64')

我在StackOverflow上找到了解决方案,请参阅下面的链接了解更多信息。 https://stackoverflow.com/a/67021201/9294498 < / p >

类似于@hibernado的答案,但保持为整数(而不是字符串)

df[col] = df[col].fillna(-1)
df[col] = df[col].astype(int)
df[col] = np.where(df[col] == -1, np.nan, df[col])
df.loc[~df['id'].isna(), 'id'] = df.loc[~df['id'].isna(), 'id'].astype('int')