ChatGPT解决这个技术问题 Extra ChatGPT

将包含 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

我该如何解决这个问题?

我认为如果缺少/NaN 值,则整数值无法转换或存储在系列/数据框中。我认为这与 numpy 兼容性有关(我在这里猜),如果您想要缺少值兼容性,那么我会将值存储为浮点数
见这里:pandas.pydata.org/pandas-docs/dev/…;当您缺少值时,您必须有一个 float dtype(或者技术上是 object dtype,但效率低下);您使用 int 类型的目标是什么?
我相信这是一个 NumPy 问题,而不是特定于 Pandas。很遗憾,因为在很多情况下,拥有允许空值可能性的 int 类型比一大列浮点数更有效。
我也有这个问题。我有多个数据框,我想根据几个“整数”列的字符串表示来合并它们。但是,当其中一个整数列具有 np.nan 时,字符串转换会产生一个“.0”,这会引发合并。只是让事情稍微复杂一些,如果有简单的解决方法会很好。
@Rhubarb,可选的 Nullable 整数支持现已正式添加到 pandas 0.24.0 - 终于 :) - 请在下面找到更新的答案。 pandas 0.24.x release notes

j
jezrael

在 0.24.+ 版本中,pandas 获得了保存具有缺失值的整数 dtype 的能力。

Nullable Integer Data Type

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')

请注意,dtype 必须是 "Int64" 而不是 "int64"(第一个 'i' 必须大写)
df.myCol = df.myCol.astype('Int64')df['myCol'] = df['myCol'].astype('Int64')
这对某些人来说可能很明显,但我认为仍然值得注意的是,您可以使用任何 Int(例如 Int16Int32),如果数据帧非常大以节省内存,确实可能应该使用。
@jezrael,在这种情况下这不起作用......?它对我不起作用,我找不到通用的解决方案。
我得到TypeError: cannot safely cast non-equivalent float64 to int64
3
3 revs, 2 users 83%

整数列中缺少 NaN 代表是 pandas "gotcha"

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


除了像花车一样对待它们之外,还有其他解决方法吗?
@jsc123 你可以使用 object dtype。这带有一个小的健康警告,但在大多数情况下效果很好。
你能提供一个如何使用 object dtype 的例子吗?我一直在浏览 pandas 文档和谷歌搜索,我读过这是推荐的方法。但是,我还没有找到如何使用 object dtype 的示例。
在 v0.24 中,您现在可以执行 df = df.astype(pd.Int32Dtype())(转换整个数据帧,或)df['col'] = df['col'].astype(pd.Int32Dtype())。其他可接受的可为空整数类型是 pd.Int16Dtypepd.Int64Dtype。选择你的毒药。
这是 NaN 值,但 isnan 检查根本不起作用:(
h
hibernado

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

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。

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


我一直在努力加载序列号,其中一些为空,其余为浮点数,这救了我。
OP想要一列整数。将其转换为字符串不满足条件。
仅当 col 还没有 -1 时才有效。否则会弄乱数据
那么如何回到int ..??
这会产生一列字符串!有关当前版本 pandas 的解决方案,请参阅 stackoverflow.com/questions/58029359/…
m
mork

现在可以创建一个包含 NaN 作为 dtype int 的 pandas 列,因为它现在已正式添加到 pandas 0.24.0

pandas 0.24.x release notes 引用:“Pandas 已经获得了保存具有缺失值的整数 dtype 的能力


A
Abhishek Bhatia

无论您的熊猫系列是 object 数据类型还是简单的 float 数据类型,以下方法都可以使用

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

谢谢@Abhishek Bhatia,这对我有用。
j
jmenglund

如果你绝对想在一列中组合整数和 NaN,你可以使用 'object' 数据类型:

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

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


K
Kamil

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

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

e
elomage

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

df = df.dropna(subset=['id'])

或者,使用 .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

B
Bradon

从 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')

此处的文档https://pandas.pydata.org/pandas-docs/stable/user_guide/integer_na.html


g
gboffi

如果您可以修改存储的数据,请使用缺少 id 的标记值。一个常见的用例,由列名推断,即 id 是一个整数,严格大于零,您可以使用 0 作为标记值,以便您可以编写

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

C
Corbin

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

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

这种方法会增加很多内存开销,尤其是在较大的数据帧上
A
Alex Metsai

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

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

有效,但我认为用 0 替换 NaN 会改变数据的含义。
M
Monaheng Ramochele
import pandas as pd

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

您是否有理由更喜欢这个公式而不是接受的答案中提出的公式?如果是这样,编辑您的答案以提供该解释会很有用 - 特别是因为有十个额外的答案正在争夺注意力。
虽然此代码可能会解决 OP 的问题,但最好包含关于您的代码如何/为什么解决它的解释。通过这种方式,未来的访问者可以从您的帖子中学习,并将其应用到他们自己的代码中。 SO 不是编码服务,而是知识资源。此外,高质量、完整的答案更有可能得到支持。这些功能,以及所有帖子都是独立的要求,是 SO 的一些优势,因为它是一个区别于论坛的平台。您可以edit添加其他信息和/或使用源文档补充您的解释。
M
Mehdi Golzadeh

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

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

T
TWebbs

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

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

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


D
Digestible1010101

首先,您需要指定可以处理空整数数据的较新整数类型 Int8 (...Int64)(pandas 版本 >= 0.24.0)

df = df.astype('Int8')

但是您可能只想针对具有与 NaN/null 混合的整数数据的特定列:

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

此时,NaN 被转换为 <NA>,如果您想使用 df.fillna() 更改默认的 null 值,您需要在要更改的列上强制转换对象数据类型,否则您将看到 {2 }

如果您不介意将每个列数据类型更改为对象(单独地,仍然保留每个值的类型),您可以通过 df = df.astype(object) 执行此操作...或者如果您更喜欢针对单个列,则可以通过 df = df.astype({"col1": object,"col2": object}) 执行此操作。

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


l
luca992

对于 pandas >.24 版本,类型 Int64 支持 nan。

如果您的花车没有被弄圆、落地、天花板或圆形,您可能会遇到错误。

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

来源:https://stackoverflow.com/a/67021201/1363742


N
Neuneck

我在使用 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

N
Nikhil Redij

尝试这个:

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

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


b
buhtz

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

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

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


请解释您的解决方案。
k
kamran kausar

首先删除包含 NaN 的行。然后对剩余的行进行整数转换。最后再次插入删除的行。希望它会起作用


W
WolVes

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

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

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

m
mqx

有类似的问题。那是我的解决方案:

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'])

l
lassebenninga

既然这里没有看到答案,那还不如补充一下:

如果您由于某种原因仍然无法像我一样在依赖具有旧版 pandas 的库时处理 np.na 或 pd.NA ,则将 NAN 转换为空字符串的单线:

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


谨慎使用这种方法...如果您的任何数据确实是-1,它将被覆盖。
N
Nimantha

我认为 @Digestible1010101 的方法更适合 Pandas 1.2.+ 版本,这样的事情应该可以完成:

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

J
Justin Malinchak

假设您的 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'))

K
KeepLearning

使用 pd.to_numeric()

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

简单干净


如果列中有 NaN 值,则 pd.to_numeric 会将 dtype 转换为 float 而不是 int,因为 NaN 被视为浮点数。