You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用替代方法加载Pandas DataFrame时性能下降的原因排查

问题:拆分大型CSV为日期字典后模拟性能下降

我需要处理约8GB的大型CSV文件,将其转为DataFrame后拆分为字典——以日期为键,每日数据为小型DataFrame,以此提升后续模拟的查询速度。

为了优化拆分速度,我重写了处理流程:不再先合并所有块为单个大DataFrame再拆分,而是将CSV分块存储在列表中,记录每个块的最小/最大日期,直接从包含目标日期的块中提取数据合并到字典。结果拆分时间从40分钟骤降到15秒,但模拟单周期耗时从2.5秒升至3.5秒。

这不是第一次出现类似问题:数月前我从原CSV中提取最近两年数据生成800MB的小型CSV,加载速度更快,但模拟耗时从12秒涨到20秒。两张表的列类型、数量完全一致,但小型表的模拟速度始终慢于原完整CSV的处理速度,且该现象早于拆分字典的操作。

新旧流程对比

旧流程

  • 分块(20000行/块)加载CSV
  • 合并所有块为单个DataFrame
  • 拆分每日数据到字典
  • 执行模拟

新流程

  • 分块(20000行/块)加载CSV
  • 直接从含目标日期的块中拆分数据到字典
  • 执行模拟

关键差异

新流程生成的字典占用内存10.5GB,旧流程为12.2GB——内存占用更小,但模拟速度反而更慢。

旧方法代码

chunkList = [chunk for chunk in pandas.read_csv(f'{SOURCE}_candles.csv', chunksize=20000, low_memory=False)]
candles = pandas.concat(chunkList)
del chunkList

print("Got candles")

# Data type insurance...

candles['tm_uuid'] = candles['tm_uuid'].astype("string")
candles['ticker'] = candles['ticker'].astype("string")
candles['price_date'] = pandas.to_datetime(candles['price_date']).dt.date

# Specify the start date; don't want to waste time looking at days we don't care about

candles = candles.loc[(candles['price_date'] >= simul_date), :]

# Now get the active dates to use as keys for the dictionary.

activeDates = candles[CandleColumn.PRICE_DATE.value].unique().tolist()

print("Got active dates")

timerTest = time.time()
candlesDict = {}

# Now breakout into the dictionary

for date in activeDates:
    candlesDict[date] = candles.loc[(candles[CandleColumn.PRICE_DATE.value] == date), :]
    candlesDict[date].set_index(CandleColumn.TM_UUID.value, drop=False, inplace=True)
    print(f"Finished {date}")

print(f"Done in {time.time() - timerTest}")
print(f"Candles dictionary uses {sum([sys.getsizeof(candlesDict[date]) for date in activeDates]) / 1024}kb")

# We no longer need the candles table, so clear it from memory!
del candles

新方法代码

candles = [chunk for chunk in pandas.read_csv(f'{SOURCE}_candles.csv', chunksize=20000, low_memory=False)]

# Data type insurance...

for table in candles:
    table['tm_uuid'] = table['tm_uuid'].astype("string")
    table['ticker'] = table['ticker'].astype("string")
    table['price_date'] = pandas.to_datetime(table['price_date']).dt.date

# Specify the start date; don't want to waste time looking at days we don't care about

# todo this method is bad practice, create new list and copy. Maybe inplace drop of specified rows?
# Removing this does not improve processing speed...
for index, table in enumerate(candles):
    candles[index] = table.loc[(table['price_date'] >= simul_date), :]

# Now get the active dates to use as keys for the dictionary.

activeDatesUnflattened = [table[CandleColumn.PRICE_DATE.value].unique().tolist() for table in candles]
# Not much point to the .unique() call anymore eh?
activeDates = list(set(list(chain.from_iterable(activeDatesUnflattened))))
activeDates.sort()
del activeDatesUnflattened

timerTest = time.time()
candlesDict = {}
tableDates = []

# Capture the min and max dates for each table in the list

for table in candles:
    tableDates.append((table[CandleColumn.PRICE_DATE.value].min(), table[CandleColumn.PRICE_DATE.value].max()))

# Now breakout into the dictionary

for date in activeDates:
    for index, table in enumerate(candles):
        if date >= tableDates[index][0] and date <= tableDates[index][1]:
            # The date is within the bounds of the table
            if date in candlesDict.keys():
                # If there is a table there, we need to concat the two and make sure the index
                candlesDict[date] = pandas.concat([(table.loc[(table[CandleColumn.PRICE_DATE.value] == date), :]).set_index(CandleColumn.TM_UUID.value, drop=False, inplace=True), candlesDict[date]])
                # todo Faster way to preserve index?
            else:
                candlesDict[date] = table.loc[(table[CandleColumn.PRICE_DATE.value] == date), :]
                candlesDict[date].set_index(CandleColumn.TM_UUID.value, drop=False, inplace=True)
        else:
            continue
    print(f"Finished {date}")

print(f"Done in {time.time() - timerTest}")
print(f"Candles dictionary uses {sum([sys.getsizeof(candlesDict[date]) for date in activeDates]) / 1024}kb")

# We no longer need the candles table, so clear it from memory!
del candles

内容的提问来源于stack exchange,提问作者Allergic

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 04:01:05