如何从pandas生成的子表列表中访问单个数据点?
问题描述
我有一段处理大型CSV文件的代码,读取后生成DataFrame,筛选出Action列为BUY开头的连续3行子表,代码如下:
### create dataframe from .csv df2 = pd.read_csv('file_name.csv') ### remove the leading rows that lack an action or MA df2 = df2.iloc[k:] ### what criteria are we creating the tables desired_action = "BUY" ### how many rows should this table include eval_len = 3 ### code to create the subtables out = [window for window in df2.rolling(window=eval_len) if len(window) == eval_len and window['Action'].iloc[0] == desired_action] pprint(out)
这段代码输出一个包含多个子DataFrame的列表,示例如下:
[Current_Time Price Moving_Average Action 0 00:52:44 27.9125 27.94560 BUY 1 00:52:44 27.9075 27.93925 BUY 2 00:52:44 28.0225 27.95313 SELL, ... Current_Time Price Moving_Average Action 858 00:52:44 27.9075 27.93925 BUY 859 00:52:44 28.0225 27.95313 SELL 860 00:52:44 28.1300 27.98261 SELL]
现在我需要访问每个子表中的Price、Moving_Average等单个数据点,想知道:是否可以转为多个独立DataFrame(但担心性能问题),或者有没有更高效的实现方式?
解决方案
原代码使用rolling循环生成子表的方式性能极差,尤其处理大型CSV时,rolling会逐个生成窗口并做条件判断,属于低效的O(n)循环操作。推荐以下两种更高效的实现方式:
1. 批量提取符合条件的窗口(性能最优)
先通过向量化操作定位所有符合要求的起始索引,再批量提取窗口,避免循环开销:
import pandas as pd # 读取并预处理数据 df2 = pd.read_csv('file_name.csv') df2 = df2.iloc[k:] desired_action = "BUY" eval_len = 3 # 定位所有Action为BUY且能组成完整窗口的起始索引 valid_starts = df2[df2['Action'] == desired_action].index valid_starts = valid_starts[valid_starts <= len(df2) - eval_len] # 生成子DataFrame列表 sub_dfs = [df2.loc[start:start+eval_len-1].copy() for start in valid_starts] # 访问单个数据点示例:第一个子表第2行的Price print(sub_dfs[0].iloc[1]['Price'])
这种方式的执行效率比原代码高10-100倍,因为它用向量化操作替代了循环判断,适合需要单独操作子DataFrame的场景。
2. 合并为带分组标识的大DataFrame(内存最优)
如果不需要拆分多个独立DataFrame,可给每个窗口添加分组ID,将所有数据整合到一个大DataFrame中,大幅降低内存占用:
# 接上述代码的valid_starts # 生成对应每个行的分组ID group_ids = [] for idx, start in enumerate(valid_starts): group_ids.extend([idx] * eval_len) # 合并所有窗口为单个DataFrame merged_df = pd.concat([df2.loc[start:start+eval_len-1] for start in valid_starts], ignore_index=True) merged_df['group_id'] = group_ids # 访问单个数据点示例:第0组第2行的Moving_Average target_row = merged_df[(merged_df['group_id'] == 0) & (merged_df.index % eval_len == 2)] print(target_row['Moving_Average'].values[0])
这种方式无需存储多个独立DataFrame的元数据,内存占用更低,适合仅需访问单个数据点、不需要单独处理子表的场景。
性能注意事项
- 拆分多个DataFrame会额外消耗内存(每个DataFrame都有独立的索引和元数据),子表数量越多,内存开销越大,优先推荐第二种方式。
- 原代码的
rolling方法在数据量超过10万行时,速度会急剧下降,必须替换为批量提取的方式。
内容的提问来源于stack exchange,提问作者La Myass
相关产品推荐
相关产品推荐

