我从 .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
我该如何解决这个问题?
在 0.24.+ 版本中,pandas 获得了保存具有缺失值的整数 dtype 的能力。
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')
整数列中缺少 NaN 代表是 pandas "gotcha"。
通常的解决方法是简单地使用浮点数。
df = df.astype(pd.Int32Dtype())
(转换整个数据帧,或)df['col'] = df['col'].astype(pd.Int32Dtype())
。其他可接受的可为空整数类型是 pd.Int16Dtype
和 pd.Int64Dtype
。选择你的毒药。
我的用例是在加载到数据库表之前修改数据:
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。
它不漂亮,但它完成了工作!
pandas
的解决方案,请参阅 stackoverflow.com/questions/58029359/…
现在可以创建一个包含 NaN 作为 dtype int
的 pandas 列,因为它现在已正式添加到 pandas 0.24.0
pandas 0.24.x release notes 引用:“Pandas 已经获得了保存具有缺失值的整数 dtype 的能力
无论您的熊猫系列是 object
数据类型还是简单的 float
数据类型,以下方法都可以使用
df = pd.read_csv("data.csv")
df['id'] = df['id'].astype(float).astype('Int64')
如果你绝对想在一列中组合整数和 NaN,你可以使用 'object' 数据类型:
df['col'] = (
df['col'].fillna(0)
.astype(int)
.astype(object)
.where(df['col'].notnull())
)
这将用整数替换 NaN(不管是哪个),转换为 int,转换为 object,最后重新插入 NaN。
几周前我遇到了一些被格式化为“对象”的离散特征的问题。这个解决方案似乎有效。
for col in discrete:
df[col] = pd.to_numeric(df[col],errors='coerce').astype(pd.Int64Dtype())
如果可以删除具有 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
从 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
如果您可以修改存储的数据,请使用缺少 id
的标记值。一个常见的用例,由列名推断,即 id
是一个整数,严格大于零,您可以使用 0
作为标记值,以便您可以编写
if row['id']:
regular_process(row)
else:
special_process(row)
这里的大多数解决方案都会告诉您如何使用占位符整数来表示空值。如果您不确定整数不会出现在源数据中,那么这种方法就没有帮助。我的方法将格式化没有十进制值的浮点数并将空值转换为无。结果是一个对象数据类型,当加载到 CSV 中时,它看起来像一个具有空值的整数字段。
keep_df[col] = keep_df[col].apply(lambda x: None if pandas.isnull(x) else '{0:.0f}'.format(pandas.to_numeric(x)))
使用 .fillna()
将所有 NaN
值替换为 0
,然后使用 astype(int)
将其转换为 int
df['id'] = df['id'].fillna(0).astype(int)
import pandas as pd
df= pd.read_csv("data.csv")
df['id'] = pd.to_numeric(df['id'])
edit
添加其他信息和/或使用源文档补充您的解释。
如果要在链接方法时使用它,可以使用 assign:
df = (
df.assign(col = lambda x: x['col'].astype('Int64'))
)
对于任何需要在包含 NULL/NaN 的列中具有 int 值,但在无法使用其他答案中提到的 pandas 版本 0.24.0 可空整数特性的约束下工作的人,我建议使用 pd.where 将列转换为对象类型:
df = df.where(pd.notnull(df), None)
这会将数据框中的所有 NaN 转换为 None,将混合类型的列视为对象,但将 int 值保留为 int,而不是 float。
首先,您需要指定可以处理空整数数据的较新整数类型 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})
执行此操作。
这应该有助于强制与空值混合的整数列保持格式化为整数并将空值更改为您喜欢的任何值。我不能说这种方法的效率,但它适用于我的格式化和打印目的。
对于 pandas >.24 版本,类型 Int64
支持 nan。
如果您的花车没有被弄圆、落地、天花板或圆形,您可能会遇到错误。
df['A'] = np.floor(pd.to_numeric(df['A'], errors='coerce')).astype('Int64')
来源:https://stackoverflow.com/a/67021201/1363742
我在使用 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
尝试这个:
df[['id']] = df[['id']].astype(pd.Int64Dtype())
如果您打印它是 dtypes
,您将得到 id Int64
而不是正常的 one int64
以下解决方案是唯一符合我目的的解决方案,我认为这是使用最新 Pandas 版本时的最佳解决方案。
df['A'] = np.floor(pd.to_numeric(df['A'],
errors='coerce'))
.astype('Int64')
我在 StackOverflow 上找到了解决方案,请参阅下面的链接以获取更多信息。 https://stackoverflow.com/a/67021201/9294498
首先删除包含 NaN 的行。然后对剩余的行进行整数转换。最后再次插入删除的行。希望它会起作用
与许多其他解决方案一样,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)
有类似的问题。那是我的解决方案:
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'])
既然这里没有看到答案,那还不如补充一下:
如果您由于某种原因仍然无法像我一样在依赖具有旧版 pandas 的库时处理 np.na 或 pd.NA ,则将 NAN 转换为空字符串的单线:
df.select_dtypes('number').fillna(-1).astype(str).replace('-1', '')
我认为 @Digestible1010101 的方法更适合 Pandas 1.2.+ 版本,这样的事情应该可以完成:
df = df.astype({
'col_1': 'Int64',
'col_2': 'Int64',
'col_3': 'Int64',
'col_4': 'Int64', })
假设您的 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'))
使用 pd.to_numeric()
df["DateColumn"] = pd.to_numeric(df["DateColumn"])
简单干净
不定期副业成功案例分享
"Int64"
而不是"int64"
(第一个 'i' 必须大写)df.myCol = df.myCol.astype('Int64')
或df['myCol'] = df['myCol'].astype('Int64')
Int16
、Int32
),如果数据帧非常大以节省内存,确实可能应该使用。TypeError: cannot safely cast non-equivalent float64 to int64