我怎样才能加快这个迭代?
How can I speed up this iteration?
我有一个包含 2 列 'left_index'
和 'right_index'
的超过一千万行的数据框。
'left_index'
是值的索引,'right_index'
包含可能匹配的行的索引。
问题是这包含重复的匹配项(例如:0,1 和 1,0)。
我想过滤这个数据框,只保留每个匹配项的一个组合。
我在这里使用列表作为示例。
在:[(0,1), (1,0), (3,567)]
输出:[(0,1), (3, 567)]
下面的代码生成了我想要的结果,但是速度很慢。有没有更快的方法来解决这个问题?
lst2 = []
for i in lst1:
if(i in lst2):
lst1.remove(i)
else:
lst2.append((i[1],i[0]))
我相信 Pandas 可以避免使用循环。
import pandas as pd
df = pd.DataFrame([
[(0, 0), (0, 0), 123],
[(0, 0), (0, 1), 234],
[(1, 0), (0, 1), 345],
[(1, 1), (0, 1), 456],
], columns=['left_index', 'right_index', 'value'])
print(df)
left_index right_index value
0 (0, 0) (0, 0) 123
1 (0, 0) (0, 1) 234
2 (1, 0) (0, 1) 345
3 (1, 1) (0, 1) 456
df['left_index_set'] = df['left_index'].apply(set)
df['right_index_set'] = df['right_index'].apply(set)
我不确定您在此之后需要什么。如果要过滤重复项,请执行以下操作。
df = df[df['left_index_set'] != df['right_index_set']]
df_final1= df[['left_index', 'right_index', 'value']]
print(df_final1)
left_index right_index value
1 (0, 0) (0, 1) 234
3 (1, 1) (0, 1) 456
但是,如果您不想过滤数据框而是想修改它:
df.loc[df['left_index_set'] != df['right_index_set'], 'right_index'] = None # None, '' or what you want. It's up to you
df_final2 = df[['left_index', 'right_index', 'value']]
print(df_final2)
left_index right_index value
0 (0, 0) (0, 0) 123
1 (0, 0) None 234
2 (1, 0) (0, 1) 345
3 (1, 1) None 456
您提到数据位于数据帧中并标记为 pandas
,因此我们可以使用 numpy
使用矢量化为我们完成这项工作。
首先,由于您没有提供创建数据的方法,我根据您的描述生成了一个数据框:
import numpy as np
import pandas
def build_dataframe():
def rand_series():
"""Create series of 1 million random integers in range [0, 9999]."""
return (np.random.rand(1000000) * 10000).astype('int')
data = pandas.DataFrame({
'left_index': rand_series(),
'right_index': rand_series()
})
return data.set_index('left_index')
data = build_dataframe()
由于 (0,1)
与 (1,0)
相同,根据您的要求,让我们创建一个为我们排序的值的索引。先新建两列,左右索引的最小值和最大值:
data['min_index'] = np.minimum(data.index, data.right_index)
data['max_index'] = np.maximum(data.index, data.right_index)
print(data)
right_index min_index max_index
left_index
4270 438 438 4270
1277 9378 1277 9378
20 7080 20 7080
4646 6623 4646 6623
3280 4481 3280 4481
... ... ... ...
3656 2492 2492 3656
2345 210 210 2345
9241 1934 1934 9241
369 8362 369 8362
5251 6047 5251 6047
[1000000 rows x 2 columns]
然后我们可以将索引重置为这两个新列(实际上我们只想要一个多索引,这是我们获得它的一种方法)。
data = data.reset_index().set_index(keys=['min_index', 'max_index'])
print(data)
left_index right_index
min_index max_index
438 4270 4270 438
1277 9378 1277 9378
20 7080 20 7080
4646 6623 4646 6623
3280 4481 3280 4481
... ... ...
2492 3656 3656 2492
210 2345 2345 210
1934 9241 9241 1934
369 8362 369 8362
5251 6047 5251 6047
[1000000 rows x 2 columns]
然后我们只需要索引的唯一值。这是最耗时的操作,但仍然比使用列表的简单实现快得多。
unique = data.index.unique()
print (unique)
MultiIndex([( 438, 4270),
(1277, 9378),
( 20, 7080),
(4646, 6623),
(3280, 4481),
(4410, 9367),
(1864, 7881),
( 516, 3287),
(1678, 6946),
(1253, 7890),
...
(6669, 9527),
(1095, 8866),
( 455, 7800),
(2862, 8587),
(8221, 9808),
(2492, 3656),
( 210, 2345),
(1934, 9241),
( 369, 8362),
(5251, 6047)],
names=['min_index', 'max_index'], length=990197)
使用 numpy 保留非唯一数组的第一次出现:
import numpy as np
lst1 = [(1,0), (0,1), (2, 5), (3,567), (5,2)]
arr = np.array(lst1)
result = arr[np.unique(np.sort(arr), 1, axis=0)[1]]
>>> result
array([[ 1, 0],
[ 2, 5],
[ 3, 567]])
我有一个包含 2 列 'left_index'
和 'right_index'
的超过一千万行的数据框。
'left_index'
是值的索引,'right_index'
包含可能匹配的行的索引。
问题是这包含重复的匹配项(例如:0,1 和 1,0)。
我想过滤这个数据框,只保留每个匹配项的一个组合。
我在这里使用列表作为示例。
在:[(0,1), (1,0), (3,567)]
输出:[(0,1), (3, 567)]
下面的代码生成了我想要的结果,但是速度很慢。有没有更快的方法来解决这个问题?
lst2 = []
for i in lst1:
if(i in lst2):
lst1.remove(i)
else:
lst2.append((i[1],i[0]))
我相信 Pandas 可以避免使用循环。
import pandas as pd
df = pd.DataFrame([
[(0, 0), (0, 0), 123],
[(0, 0), (0, 1), 234],
[(1, 0), (0, 1), 345],
[(1, 1), (0, 1), 456],
], columns=['left_index', 'right_index', 'value'])
print(df)
left_index right_index value
0 (0, 0) (0, 0) 123
1 (0, 0) (0, 1) 234
2 (1, 0) (0, 1) 345
3 (1, 1) (0, 1) 456
df['left_index_set'] = df['left_index'].apply(set)
df['right_index_set'] = df['right_index'].apply(set)
我不确定您在此之后需要什么。如果要过滤重复项,请执行以下操作。
df = df[df['left_index_set'] != df['right_index_set']]
df_final1= df[['left_index', 'right_index', 'value']]
print(df_final1)
left_index right_index value
1 (0, 0) (0, 1) 234
3 (1, 1) (0, 1) 456
但是,如果您不想过滤数据框而是想修改它:
df.loc[df['left_index_set'] != df['right_index_set'], 'right_index'] = None # None, '' or what you want. It's up to you
df_final2 = df[['left_index', 'right_index', 'value']]
print(df_final2)
left_index right_index value
0 (0, 0) (0, 0) 123
1 (0, 0) None 234
2 (1, 0) (0, 1) 345
3 (1, 1) None 456
您提到数据位于数据帧中并标记为 pandas
,因此我们可以使用 numpy
使用矢量化为我们完成这项工作。
首先,由于您没有提供创建数据的方法,我根据您的描述生成了一个数据框:
import numpy as np
import pandas
def build_dataframe():
def rand_series():
"""Create series of 1 million random integers in range [0, 9999]."""
return (np.random.rand(1000000) * 10000).astype('int')
data = pandas.DataFrame({
'left_index': rand_series(),
'right_index': rand_series()
})
return data.set_index('left_index')
data = build_dataframe()
由于 (0,1)
与 (1,0)
相同,根据您的要求,让我们创建一个为我们排序的值的索引。先新建两列,左右索引的最小值和最大值:
data['min_index'] = np.minimum(data.index, data.right_index)
data['max_index'] = np.maximum(data.index, data.right_index)
print(data)
right_index min_index max_index left_index 4270 438 438 4270 1277 9378 1277 9378 20 7080 20 7080 4646 6623 4646 6623 3280 4481 3280 4481 ... ... ... ... 3656 2492 2492 3656 2345 210 210 2345 9241 1934 1934 9241 369 8362 369 8362 5251 6047 5251 6047 [1000000 rows x 2 columns]
然后我们可以将索引重置为这两个新列(实际上我们只想要一个多索引,这是我们获得它的一种方法)。
data = data.reset_index().set_index(keys=['min_index', 'max_index'])
print(data)
left_index right_index min_index max_index 438 4270 4270 438 1277 9378 1277 9378 20 7080 20 7080 4646 6623 4646 6623 3280 4481 3280 4481 ... ... ... 2492 3656 3656 2492 210 2345 2345 210 1934 9241 9241 1934 369 8362 369 8362 5251 6047 5251 6047 [1000000 rows x 2 columns]
然后我们只需要索引的唯一值。这是最耗时的操作,但仍然比使用列表的简单实现快得多。
unique = data.index.unique()
print (unique)
MultiIndex([( 438, 4270), (1277, 9378), ( 20, 7080), (4646, 6623), (3280, 4481), (4410, 9367), (1864, 7881), ( 516, 3287), (1678, 6946), (1253, 7890), ... (6669, 9527), (1095, 8866), ( 455, 7800), (2862, 8587), (8221, 9808), (2492, 3656), ( 210, 2345), (1934, 9241), ( 369, 8362), (5251, 6047)], names=['min_index', 'max_index'], length=990197)
使用 numpy 保留非唯一数组的第一次出现:
import numpy as np
lst1 = [(1,0), (0,1), (2, 5), (3,567), (5,2)]
arr = np.array(lst1)
result = arr[np.unique(np.sort(arr), 1, axis=0)[1]]
>>> result
array([[ 1, 0],
[ 2, 5],
[ 3, 567]])