python - 能不能用pandas过滤亿万行数据
问题描述
最近我一直在处理一个包含近 1 亿行的大型数据集。
完全加载到内存中的文件超过 15GB。将所有数据加载到内存中没有问题,因为我有一个 96GB 内存的服务器。
这是 info() 的输出:
<class 'modin.pandas.dataframe.DataFrame'>
Int64Index: 97915924 entries, 0 to 117814626
Data columns (total 20 columns):
# Column Non-Null Count Dtype
--- ----------------- ----------------- -----
0 50p_width 97915924 non-null float64
1 80p_width 97915924 non-null float64
2 area 97915924 non-null float64
3 area_fraction_top 97915924 non-null float64
4 center_time 97915924 non-null float64
5 event_number 97915924 non-null int64
6 event_start_time 97915924 non-null int64
7 goodness_of_fit 8205122 non-null float64
8 left 97915924 non-null int64
9 max_PMT 97915924 non-null int64
10 max_PMT_area 97915924 non-null float64
11 max_hit_PMT 97915924 non-null int64
12 max_hit_area 97915924 non-null float64
13 n_PMTS 97915924 non-null int64
14 n_hits 97915924 non-null int64
15 right 97915924 non-null int64
16 run_number 97915924 non-null int64
17 type 97915924 non-null int64
18 x 8205122 non-null float64
19 y 8205122 non-null float64
dtypes: float64(10), int64(10)
memory usage: 15.3 GB
data['exact_time'] = data['center_time'] + data['event_start_time']
我的目标不是直接分析数据,而是过滤它,以便我可以做一些进一步的研究。类型只能是 0、1 和 2。data['exact_time']
是 ns 中的 unix 时间戳。我想找出在类型 2 事件之前 1 ms (1e6 ns) 发生的所有类型 0/类型 1 事件,并找出最大面积对应于所有类型 2 的事件。\
我想出了两种可能的方法,但都需要遍历每一行。
方法一:这只过滤时间范围内的所有事件。
s2_data = data[data['type'] == 2]
s2_time_list = s2_data['exact_time'].tolist()
s2_time_list
for t in tqdm(s2_time_list):
new_data = new_data.append(data.loc[(data['exact_time'] >= t-1e6) & (data['exact_time'] <= t)])
方法 2:这将遍历整个数据帧一次,并获得具有最大面积的 t0/t1 事件以及相应的 t2。
#eventlist = pd.DataFrame().reindex(columns=data.columns)
s2_time = 0
for i, row in tqdm(data.iterrows()):
if row['type'] == 2:
s2_time = row['exact_time']
eventlist = eventlist.loc[eventlist['exact_time'] >= s2_time - 1e6]
ind = eventlist["area"].idxmax()
max_row = eventlist.iloc[ind,:]
new_data = new_data.append(max_row)
new_data = new_data.append(row)
else:
eventlist = eventlist.append(row)
我已经在 exact_time 上创建了索引,并尽可能使用 modin 库并行处理数据,但两者似乎都非常慢并且需要永远完成。我不认为 apply() 或 pd/np 矢量化会起作用,因为这需要来自多行的数据,所以我想知道是否有更好的方法可以做到这一点。
解决方案
重做您的方法 1 以获取数据帧列表,然后连接。从我看到的情况来看,您在每次迭代中都附加了一个数据框。
我把这个例子放在一起来说明。在具有 12 GB 内存的 PC 上创建了一个包含 500,000 行的数据帧(用于比较)。将时间从 46 秒减少到 25 秒(所以至少你可以在那里获得一半的时间)。
tt = 1605067706567342
n=500000
exact_time = []
for i in range(n):
tt = tt + 99999
# print(t)
exact_time.append(tt)
type = [0,0,0,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,0,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1,1,1,0,1,1,1,1]*10000
data = pd.DataFrame({'exact_time':exact_time,'type':type}, columns=['exact_time', 'type'])
print(data)
s2_data = data[data['type'] == 2]
s2_time_list = s2_data['exact_time'].tolist()
len(s2_time_list)
####Your method 1 - # 500,000 rows; 20,000 type 2 --- **46.63247585296631 seconds**
starttime = time.time()
new_data = pd.DataFrame()
for t in s2_time_list:
# print(t)
# print(data.loc[(data['exact_time'] >= t-1e6) & (data['exact_time'] <= t)])
new_data = new_data.append(data.loc[(data['exact_time'] >= t-1e6) & (data['exact_time'] <= t)])
print(time.time()-starttime)
#### Reworked to create list of dfs then concatenate
### # 500,000 rows; 20,000 type 2 --- **25.308656930923462 seconds**
starttime = time.time()
new_data_list = []
for t in s2_time_list:
# print(t)
# print(data.loc[(data['exact_time'] >= t-1e6) & (data['exact_time'] <= t)])
new_data_list.append(data.loc[(data['exact_time'] >= t-1e6) & (data['exact_time'] <= t)])
new_df = pd.concat(new_data_list, axis=0)
print(time.time()-starttime)
推荐阅读
- html - 数据 uri 中的多字节 unicode 解码不正确
- python - Python:修改和编辑函数内的数据框
- node.js - 如何付款 意图在 Stripe 中向已连接的帐户收费
- mysql - 有没有办法在 SQL 的左连接之后获取变量并将它们添加为列?
- javascript - 在 DOM 中搜索大于“x”的数字,然后附加带有差异的数字
- c# - 为什么我不能用这种模式删除“[restr=戸]”
- javascript - 无法在 Javascript async/await try/catch 客户端代码中访问 res.statusMessage 以读取从快速后端抛出的异常
- c# - .NET CORE 串行类在使用 tty 端口发布到 Linux 机器时未读取 BaseStream 或 ReadBuffer 中超过 4KBytes 的数据
- php - Jquery Ajax Post 再次返回数据
- ios - 为什么 WKWebView 不打开 target="_blank" 的链接?