Python 高效地将大数据帧列从float转换为int
这不同于,因为我需要保持NaN值,所以我选择使用实验性的。这个问题的关键是试图避免循环 我们有许多大型医学数据集,我正在从SAS导入熊猫。大多数字段都是枚举类型,应该表示为整数,但它们以float64的形式出现,因为许多字段包含NaN值。熊猫实验中的积分阵列类型解决了NaN问题。但是,这些数据集非常大,我想根据数据本身在脚本中转换它们。下面的脚本可以工作,但速度非常慢,我已经找到了一种更具python风格或“Pandorable”风格的编写方法Python 高效地将大数据帧列从float转换为int,python,pandas,dataframe,Python,Pandas,Dataframe,这不同于,因为我需要保持NaN值,所以我选择使用实验性的。这个问题的关键是试图避免循环 我们有许多大型医学数据集,我正在从SAS导入熊猫。大多数字段都是枚举类型,应该表示为整数,但它们以float64的形式出现,因为许多字段包含NaN值。熊猫实验中的积分阵列类型解决了NaN问题。但是,这些数据集非常大,我想根据数据本身在脚本中转换它们。下面的脚本可以工作,但速度非常慢,我已经找到了一种更具python风格或“Pandorable”风格的编写方法 # Convert any non-float f
# Convert any non-float fields to IntegerArray (Int)
# Note than IntegerArrays are an experimental addition in Pandas 0.24. They
# allow integer columns to contain NaN fields like float columns.
#
# This is a rather brute-force technique that loops through every column
# and every row. There's got to be a more efficient way to do it since it
# takes a long time and uses up a lot of memory.
def convert_integer (df):
for col in df.columns:
intcol_flag = True
if df[col].dtype == 'float64': # Assuming dtype is "float64"
# TODO: Need to remove inner loop - SLOW!
for val in df[col]:
# If not NaN and the int() value is different from
# the float value, then we have an actual float.
if pd.notnull(val) and abs(val - int(val)) > 1e-6:
intcol_flag = False
break;
# If not a float, change it to an Int based on size
if intcol_flag:
if df[col].abs().max() < 127:
df[col] = df[col].astype('Int8')
elif df[col].abs().max() < 32767:
df[col] = df[col].astype('Int16')
else: # assuming no ints greater than 2147483647
df[col] = df[col].astype('Int32')
print(f"{col} is {df[col].dtype}")
return df
而且还是一样慢
以下是一些示例数据和所需的输出:
np.random.seed(10)
df = pd.DataFrame(np.random.choice([1, 2, 3.3, 5000, 111111, np.NaN], (3,9)),
columns=[f'col{i}' for i in range(9)])
df
col0 col1 col2 col3 col4 col5 col6 col7 col8
0 2.0 NaN 111111.0 1.0 2.0 5000.0 111111.0 2.0 NaN
1 1.0 NaN 2.0 3.3 1.0 2.0 1.0 3.3 1.0
2 111111.0 5000.0 1.0 111111.0 5000.0 1.0 5000.0 3.3 2.0
结果应该是:
col0 is Int32
col1 is Int16
col2 is Int32
col3 is float64
col4 is Int16
col5 is Int16
col6 is Int32
col7 is float64
col8 is Int8
找到需要对每种类型进行类型转换的列,然后对每种类型一次执行所有操作 样本数据 代码
找到需要对每种类型进行类型转换的列,然后对每种类型一次执行所有操作 样本数据 代码
可能重复的
apply
本质上是一个for循环,所以它对您没有好处。使用s=df[col].notnull()&df[col].sub(df[col].astype(int)).abs().gt(1e6)
是否需要保留NaN值?这些是浮子型的。请参阅建议的重复QQ。您可以尝试对代码的不同部分计时,以了解需要花费很长时间的内容@DavidZemens是的,我想保留NAN,熊猫V0.24中添加的实验积分对这一点很有效。所以转换不是问题,只是效率(和丑陋的循环)。可能重复的apply
本质上是一个for循环,所以它对您没有好处。使用s=df[col].notnull()&df[col].sub(df[col].astype(int)).abs().gt(1e6)
是否需要保留NaN值?这些是浮子型的。请参阅建议的重复QQ。您可以尝试对代码的不同部分计时,以了解需要花费很长时间的内容@DavidZemens是的,我想保留NAN,熊猫V0.24中添加的实验积分对这一点很有效。所以转换不是问题,只是效率(和丑陋的循环)。我喜欢你的做法,但有一件事我没有说清楚,就是少数列实际上包含浮点值,而这些列无法转换。如果您不介意的话,我可以借用您的数据来解决这个问题。在我的问题中添加了数据,并修改了您的代码以包含浮点数据字段。@MikeBopf我更新了,这是一个小改动。我认为你在这个问题上的预期输出有点偏离。我修正了我的预期输出-糟糕的剪切和粘贴。我仍在尝试让您的解决方案与我的数据一起工作,因为我有一些特殊情况。但我认为它会起作用。我遇到了硬件问题,因此无法在我的完整数据集上测试它,但解决方案可以在测试数据上运行,我喜欢答案的巧妙性。我喜欢你的做法,但有一件事我并没有弄清楚,就是有一小部分列实际上包含浮点值,而这些列不能被转换。如果您不介意的话,我可以借用您的数据来解决这个问题。在我的问题中添加了数据,并修改了您的代码以包含浮点数据字段。@MikeBopf我更新了,这是一个小改动。我认为你在这个问题上的预期输出有点偏离。我修正了我的预期输出-糟糕的剪切和粘贴。我仍在尝试让您的解决方案与我的数据一起工作,因为我有一些特殊情况。不过,我认为它会起作用。我遇到了硬件问题,因此无法在完整的数据集上测试它,但解决方案可以在测试数据上运行,我喜欢答案的巧妙性。
col0 is Int32
col1 is Int16
col2 is Int32
col3 is float64
col4 is Int16
col5 is Int16
col6 is Int32
col7 is float64
col8 is Int8
import pandas as pd
import numpy as np
np.random.seed(10)
df = pd.DataFrame(np.random.choice([1, 2, 3.3, 5000, 111111, np.NaN], (3,9)),
columns=[f'col{i}' for i in range(9)])
s = pd.cut(df.max(), bins=[0, 127, 32767, 2147483647], labels=['Int8', 'Int16', 'Int32'])
s = s.where((df.dtypes=='float') & (df.isnull() | (df%1 == 0)).all())
# Cast previously # If all values are
# float columns # "I"nteger-like
for idx, gp in s.groupby(s):
df.loc[:, gp.index] = df.loc[:, gp.index].astype(idx)
df.dtypes
#col0 Int32
#col1 Int16
#col2 Int32
#col3 float64
#col4 Int16
#col5 Int16
#col6 Int32
#col7 float64
#col8 Int8
#dtype: object
print(df)
# col0 col1 col2 col3 col4 col5 col6 col7 col8
#0 2 NaN 111111 1.0 2 5000 111111 2.0 NaN
#1 1 NaN 2 3.3 1 2 1 3.3 1
#2 111111 5000 1 111111.0 5000 1 5000 3.3 2