Python 将包含NaN的列转换为dtype`int`

Python 将包含NaN的列转换为dtype`int`,python,pandas,na,Python,Pandas,Na,我将数据从.csv文件读取到熊猫数据框,如下所示。对于其中一列,即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']] = d

我将数据从.csv文件读取到熊猫数据框,如下所示。对于其中一列,即
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 rep是一个问题


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

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

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

假设您的DateColumn格式为332018.0,应将其作为字符串转换为2018年3月31日。并且,某些记录丢失或为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\u 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'])
或者, 使用
.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。

这里的大多数解决方案告诉您如何使用占位符整数来表示空值。如果您不确定整数不会出现在源数据中,那么这种方法是没有帮助的。我的方法将格式化不带小数点的浮点,并将空值转换为无值。结果是一个对象数据类型,当加载到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获得了保存缺失值的整数数据类型的能力

熊猫可以使用表示可能缺少值的整数数据。这是在pandas中实现的扩展类型。它不是整数的默认数据类型,不会被推断;必须将数据类型显式传递到或
系列中

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
,因为它现在正式添加到pandas 0.24.0中

Quote:“熊猫已经获得了保存缺失值的整数数据类型的能力

使用pd.to\u numeric()

import pandas as pd

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

简单明了

从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(pd.Int64Dtype())


如果您打印的是
dtypes
,您将获得
id Int64
,而不是正常的
一个Int64

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

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
值,它们将被替换为
值,这些值与默认的'NaN'函数不兼容,如
isnull()
fillna()
。或者,如果将值转换为
-1
,则可能会导致删除信息的情况。我的解决方案有点蹩脚,但将提供
int
值和
np.nan
,从而允许
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


对于任何需要在包含NULL/NaN的列中包含int值,但无法使用其他答案中提到的pandas版本0.24.0可为NULL的整数功能的人,我建议使用pd将列转换为对象类型。其中:

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

这会将dataframe中的所有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楠楠楠


首先需要指定较新的整数类型Int8(。
df['id'] = df['id'].fillna(0).astype(int)
df = df.where(pd.notnull(df), None)
def toint(zahl = 1.1):
    try:
        zahl = int(zahl)
    except:
        zahl = np.nan
    return zahl

print(toint(4.776655), toint(np.nan), toint('test'))
df = pd.read_csv("data.csv") 
df['id'] = df['id'].astype(float)
df['id'] = toint(df['id'])