Pandas `read_csv` 的性能优化技巧:`chunksize`, `dtype`, `usecols`

Pandas read_csv 性能优化三剑客:chunksize, dtype, usecols,让你的数据飞起来!🚀

各位观众老爷们,大家好!我是你们的老朋友,数据魔法师 Pandas 侠!今天,咱们不谈情怀,不聊人生,就聊聊 Pandas 的 read_csv 函数,这个看似简单却暗藏玄机的家伙。

相信各位数据玩家都遇到过这样的场景:兴高采烈地拿到一份巨大的 CSV 文件,满怀期待地想用 Pandas 把它读进来,结果……电脑风扇开始狂转,CPU 利用率飙升,然后……就是漫长的等待。⏳ 时间一分一秒地流逝,你开始怀疑人生,甚至开始考虑要不要转行卖烤串。

别慌!今天 Pandas 侠就来拯救你于水火之中,传授你三个绝世武功,让你用 read_csv 函数也能像开跑车一样,体验数据分析的快感!这三个武功就是:chunksizedtypeusecols

第一剑:chunksize – 化整为零,分而治之的智慧

想象一下,你要搬一座大山,你是选择一口气搬完,还是选择一点一点地搬?答案显而易见。chunksize 就相当于把你的大 CSV 文件切分成一个个小块,让 Pandas 一块一块地读取,处理完一块再读取下一块。

为什么要这么做?

因为直接读取整个大文件可能会超出你的内存容量,导致程序崩溃或者运行极其缓慢。而 chunksize 可以让你在有限的内存中处理无限大的数据。

chunksize 怎么用?

很简单,只需要在 read_csv 函数中设置 chunksize 参数即可。chunksize 的值代表每次读取的行数。

import pandas as pd

# 设置 chunksize 为 10000 行
chunk_iterator = pd.read_csv('large_file.csv', chunksize=10000)

# 遍历每个 chunk
for chunk in chunk_iterator:
    # 在这里对每个 chunk 进行处理
    print(f"Chunk shape: {chunk.shape}")
    # 例如:计算每个 chunk 的平均值
    print(f"Chunk mean: {chunk.mean()}")

    # 注意:在这个例子中,我们只是简单地打印形状和平均值。
    # 在实际应用中,你需要根据你的需求对每个 chunk 进行处理,
    # 例如:数据清洗、特征工程、模型训练等等。

举个栗子:

假设你有一个 100 万行的 CSV 文件,你的电脑内存只有 4GB。如果你直接用 read_csv 读取,很可能会爆内存。但是,如果你设置 chunksize=10000,那么 Pandas 每次只读取 10000 行,占用的内存就会大大减少,你就可以轻松地处理这个大文件了。

使用 chunksize 的注意事项:

  • chunksize 的大小需要根据你的电脑内存和数据量来调整。如果 chunksize 太小,会增加 I/O 操作的次数,影响性能;如果 chunksize 太大,仍然可能超出内存限制。
  • read_csv 函数返回的是一个 TextFileReader 对象,你需要遍历这个对象才能获取每个 chunk。
  • 在处理每个 chunk 的时候,你需要考虑数据的完整性。例如,如果你的数据是按时间顺序排列的,你需要确保每个 chunk 包含完整的时间段。

总结:

chunksize 就像一把锋利的刀,可以将庞大的数据切分成易于处理的小块。掌握了这把刀,你就可以轻松驾驭各种规模的数据,不再畏惧大数据带来的挑战。 💪

第二剑:dtype – 知己知彼,百战不殆的数据类型

数据类型就像数据的灵魂,决定了数据的存储方式和操作方式。Pandas 默认会根据数据的内容自动推断数据类型,但是有时候 Pandas 的推断并不准确,或者说并不是最优的。

为什么要指定 dtype

  • 节省内存: 例如,如果你的数据是整数,但是 Pandas 把它识别成了浮点数,那么就会浪费大量的内存空间。
  • 提高性能: 不同数据类型的计算速度不同。例如,整数的加减运算比浮点数快得多。
  • 避免错误: 有些数据类型可能会导致计算错误。例如,如果你的数据包含缺失值,你需要将其转换为 float 类型才能进行数值运算。

dtype 怎么用?

read_csv 函数中使用 dtype 参数,传入一个字典,指定每一列的数据类型。

import pandas as pd

# 指定每一列的数据类型
dtype_dict = {
    'id': 'int32',
    'name': 'string',
    'age': 'int8',
    'salary': 'float32',
    'city': 'category'
}

df = pd.read_csv('data.csv', dtype=dtype_dict)

# 查看每一列的数据类型
print(df.dtypes)

常用的 Pandas 数据类型:

数据类型 描述
int8, int16, int32, int64 整数类型,分别占用 1, 2, 4, 8 个字节。
uint8, uint16, uint32, uint64 无符号整数类型,分别占用 1, 2, 4, 8 个字节。
float16, float32, float64 浮点数类型,分别占用 2, 4, 8 个字节。
bool 布尔类型,取值为 TrueFalse
object 字符串类型(在 Pandas 1.0 之前),或者混合类型。 注意:尽量避免使用 object 类型,因为它会消耗大量的内存,并且计算速度很慢。尽量将其转换为更具体的数据类型,例如 stringcategory
string 字符串类型(Pandas 1.0 之后引入)。
category 分类类型,适用于取值范围有限的列。可以显著减少内存占用。
datetime64 时间日期类型。

举个栗子:

假设你的 CSV 文件中有一列 age,它的取值范围是 0-120。如果你不指定 dtype,Pandas 可能会把它识别成 int64,占用 8 个字节。但是,如果你指定 dtype='int8',那么只需要占用 1 个字节,可以节省大量的内存空间。

使用 dtype 的技巧:

  • 分析数据: 在读取数据之前,先分析一下数据的内容,了解每一列的取值范围和数据类型。
  • 选择合适的类型: 根据数据的取值范围和精度要求,选择最合适的数据类型。
  • 使用 category 类型: 对于取值范围有限的列,尽量使用 category 类型,可以显著减少内存占用。
  • 避免 object 类型: 尽量避免使用 object 类型,因为它会消耗大量的内存,并且计算速度很慢。尽量将其转换为更具体的数据类型,例如 stringcategory

总结:

dtype 就像一把精密的尺子,可以精确地测量数据的尺寸。掌握了这把尺子,你就可以根据数据的特性选择最合适的数据类型,优化内存占用,提高计算性能。 📏

第三剑:usecols – 庖丁解牛,只取所需的数据列

在现实世界中,我们经常会遇到这样的情况:一份数据包含了很多列,但是我们只需要其中的几列。如果把所有列都读取进来,不仅浪费内存,还会增加计算的负担。

为什么要使用 usecols

  • 节省内存: 只读取需要的列,可以减少内存占用。
  • 提高性能: 只处理需要的列,可以减少计算的负担。
  • 简化代码: 只保留需要的列,可以简化后续的代码逻辑。

usecols 怎么用?

read_csv 函数中使用 usecols 参数,传入一个列表,指定需要读取的列名或者列索引。

import pandas as pd

# 指定需要读取的列名
df = pd.read_csv('data.csv', usecols=['id', 'name', 'age'])

# 指定需要读取的列索引
df = pd.read_csv('data.csv', usecols=[0, 1, 2])

# 查看 DataFrame 的列名
print(df.columns)

举个栗子:

假设你的 CSV 文件包含 100 列,但是你只需要其中的 3 列。如果你不使用 usecols,那么 Pandas 会读取所有 100 列,浪费大量的内存和时间。但是,如果你使用 usecols,那么 Pandas 只会读取你需要的 3 列,可以显著提高性能。

使用 usecols 的技巧:

  • 明确需求: 在读取数据之前,明确你的分析需求,确定需要哪些列。
  • 使用列名: 尽量使用列名来指定需要读取的列,因为列名更易于理解和维护。
  • 注意列索引: 如果使用列索引,需要注意列索引是从 0 开始的。
  • 结合 dtype 可以将 usecolsdtype 结合使用,进一步优化性能。

总结:

usecols 就像一把锋利的手术刀,可以精确地切除不需要的数据列。掌握了这把刀,你就可以只保留你需要的数据,减少内存占用,提高计算性能。 🔪

三剑合璧,天下无敌!

chunksizedtypeusecols,这三把剑各有千秋,但是如果能够将它们结合起来使用,就可以发挥出更大的威力!

例如:

import pandas as pd

# 指定需要读取的列名和数据类型
dtype_dict = {
    'id': 'int32',
    'age': 'int8',
    'salary': 'float32'
}

# 使用 chunksize 分块读取数据
chunk_iterator = pd.read_csv(
    'large_file.csv',
    usecols=['id', 'age', 'salary'],
    dtype=dtype_dict,
    chunksize=10000
)

# 遍历每个 chunk
for chunk in chunk_iterator:
    # 在这里对每个 chunk 进行处理
    print(f"Chunk shape: {chunk.shape}")
    print(f"Chunk memory usage: {chunk.memory_usage(deep=True).sum() / 1024**2:.2f} MB")

在这个例子中,我们同时使用了 chunksizedtypeusecols,将大文件切分成小块,只读取需要的列,并指定每一列的数据类型,从而最大程度地优化了性能。

总结

今天,我们一起学习了 Pandas read_csv 函数的三个性能优化技巧:chunksizedtypeusecols。希望这些技巧能够帮助你更好地处理大数据,让你的数据分析工作更加高效和愉快。

记住,数据分析不仅仅是一门技术,更是一门艺术。你需要不断地学习和实践,才能掌握其中的精髓,成为真正的数据魔法师! 🧙‍♂️

最后,祝大家数据分析之路一帆风顺,早日升职加薪,迎娶白富美,走上人生巅峰!再见! 👋

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注