快速python算法(numpy或pandas?),用于查找与另一个数组中的元素匹配的数组元素索引
我正在寻找一种快速方法来确定两个数组的交叉匹配索引,定义如下 我有两个非常大(>1e7个元素)的结构化数组,一个称为成员,另一个称为组。两个数组都有一个groupID列。groups数组的groupID项是唯一的,members数组的groupID项不是唯一的 “组”数组有一个名为“质量”的列。members数组有一个名为groupmass的列(当前为空)。我希望将正确的groupmass分配给groupID与其中一个组匹配的成员元素。这将通过以下方式实现:快速python算法(numpy或pandas?),用于查找与另一个数组中的元素匹配的数组元素索引,python,performance,algorithm,numpy,pandas,Python,Performance,Algorithm,Numpy,Pandas,我正在寻找一种快速方法来确定两个数组的交叉匹配索引,定义如下 我有两个非常大(>1e7个元素)的结构化数组,一个称为成员,另一个称为组。两个数组都有一个groupID列。groups数组的groupID项是唯一的,members数组的groupID项不是唯一的 “组”数组有一个名为“质量”的列。members数组有一个名为groupmass的列(当前为空)。我希望将正确的groupmass分配给groupID与其中一个组匹配的成员元素。这将通过以下方式实现: members['groupmass
members['groupmass'][idx_matched_members] = groups['mass'][idx_matched_groups]
所以我需要一个快速的例程来计算两个索引数组idx_匹配的成员和idx_匹配的组。这类任务似乎非常常见,以至于像numpy或pandas这样的包很可能会有一个优化的解决方案。有人知道专业开发、自制或其他解决方案吗?这可以通过
pandas
使用map
来完成,以使用一列的数据映射另一列的数据。下面是一个示例数据:
members = pandas.DataFrame({
'id': np.arange(10),
'groupID': np.arange(10) % 3,
'groupmass': np.zeros(10)
})
groups = pandas.DataFrame({
'groupID': np.arange(3),
'mass': np.random.randint(1, 10, 3)
})
这将为您提供以下数据:
>>> members
groupID groupmass id
0 0 0 0
1 1 0 1
2 2 0 2
3 0 0 3
4 1 0 4
5 2 0 5
6 0 0 6
7 1 0 7
8 2 0 8
9 0 0 9
>>> groups
groupID mass
0 0 3
1 1 7
2 2 4
然后:
如果您经常想使用groupID作为
组的索引,您可以永久地将其设置为这样,这样您就不必每次都使用设置索引。这可以通过熊猫
使用映射
使用另一列的数据从一列映射数据来完成。下面是一个示例数据:
members = pandas.DataFrame({
'id': np.arange(10),
'groupID': np.arange(10) % 3,
'groupmass': np.zeros(10)
})
groups = pandas.DataFrame({
'groupID': np.arange(3),
'mass': np.random.randint(1, 10, 3)
})
这将为您提供以下数据:
>>> members
groupID groupmass id
0 0 0 0
1 1 0 1
2 2 0 2
3 0 0 3
4 1 0 4
5 2 0 5
6 0 0 6
7 1 0 7
8 2 0 8
9 0 0 9
>>> groups
groupID mass
0 0 3
1 1 7
2 2 4
然后:
如果您经常想使用groupID作为组的索引,您可以永久地将其设置为这样,这样您就不必每次都使用设置索引。这可以通过熊猫
使用映射
使用另一列的数据从一列映射数据来完成。下面是一个示例数据:
members = pandas.DataFrame({
'id': np.arange(10),
'groupID': np.arange(10) % 3,
'groupmass': np.zeros(10)
})
groups = pandas.DataFrame({
'groupID': np.arange(3),
'mass': np.random.randint(1, 10, 3)
})
这将为您提供以下数据:
>>> members
groupID groupmass id
0 0 0 0
1 1 0 1
2 2 0 2
3 0 0 3
4 1 0 4
5 2 0 5
6 0 0 6
7 1 0 7
8 2 0 8
9 0 0 9
>>> groups
groupID mass
0 0 3
1 1 7
2 2 4
然后:
如果您经常想使用groupID作为组的索引,您可以永久地将其设置为这样,这样您就不必每次都使用设置索引。这可以通过熊猫
使用映射
使用另一列的数据从一列映射数据来完成。下面是一个示例数据:
members = pandas.DataFrame({
'id': np.arange(10),
'groupID': np.arange(10) % 3,
'groupmass': np.zeros(10)
})
groups = pandas.DataFrame({
'groupID': np.arange(3),
'mass': np.random.randint(1, 10, 3)
})
这将为您提供以下数据:
>>> members
groupID groupmass id
0 0 0 0
1 1 0 1
2 2 0 2
3 0 0 3
4 1 0 4
5 2 0 5
6 0 0 6
7 1 0 7
8 2 0 8
9 0 0 9
>>> groups
groupID mass
0 0 3
1 1 7
2 2 4
然后:
如果您经常想使用groupID作为组的索引,您可以将其永久设置,这样您就不必每次都使用set\u index
。下面是一个仅使用numpy
设置质量的示例。它确实使用迭代,所以对于大型阵列,它不会很快
对于仅10行,这比同等的pandas
要快得多。但随着数据集变得越来越大(例如M=10000),pandas
要好得多。pandas
的设置时间较大,但每行迭代时间较低
生成测试阵列:
dt_members = np.dtype({'names':['groupID','groupmass'], 'formats': [int, float]})
dt_groups = np.dtype({'names':['groupID', 'mass'], 'formats': [int, float]})
N, M = 5, 10
members = np.zeros((M,), dtype=dt_members)
groups = np.zeros((N,), dtype=dt_groups)
members['groupID'] = np.random.randint(101, 101+N, M)
groups['groupID'] = np.arange(101, 101+N)
groups['mass'] = np.arange(1,N+1)
def getgroup(id):
idx = id==groups['groupID']
return groups[idx]
members['groupmass'][:] = [getgroup(id)['mass'] for id in members['groupID']]
在python2
中,迭代可以使用map
:
members['groupmass'] = map(lambda x: getgroup(x)['mass'], members['groupID'])
通过最小化重复订阅,我可以将速度提高约2倍,例如
def setmass(members, groups):
gmass = groups['mass']
gid = groups['groupID']
mass = [gmass[id==gid] for id in members['groupID']]
members['groupmass'][:] = mass
但是如果groups['groupID']
可以映射到arange(N)
,那么我们可以在速度上有一个很大的飞跃。通过将相同的映射应用于成员['groupID']
,它变成了一个简单的数组索引问题
在我的示例数组中,groups['groupID']
只是arange(N)+101
。所以映射只是减去最小值
def setmass1(members, groups):
members['groupmass'][:] = groups['mass'][members['groupID']-groups['groupID'].min()]
这比我以前的代码快300倍,比pandas
解决方案(对于10000500阵列)好8倍
我怀疑熊猫是这样做的pgroups.set_index('groupID')。mass
是mass
系列,添加了.index
属性。(我可以用更通用的数组来测试)
在更一般的情况下,它可能有助于对组进行排序
,并在必要时填补一些索引空白
这是一个“矢量化”的解决方案——没有迭代。但它必须计算一个非常大的矩阵(组的长度乘以成员的长度),因此速度不快(np,其中
是最慢的一步)
下面是一个仅使用numpy
设置mass
的示例。它确实使用迭代,所以对于大型阵列,它不会很快
对于仅10行,这比同等的pandas
要快得多。但随着数据集变得越来越大(例如M=10000),pandas
要好得多。pandas
的设置时间较大,但每行迭代时间较低
生成测试阵列:
dt_members = np.dtype({'names':['groupID','groupmass'], 'formats': [int, float]})
dt_groups = np.dtype({'names':['groupID', 'mass'], 'formats': [int, float]})
N, M = 5, 10
members = np.zeros((M,), dtype=dt_members)
groups = np.zeros((N,), dtype=dt_groups)
members['groupID'] = np.random.randint(101, 101+N, M)
groups['groupID'] = np.arange(101, 101+N)
groups['mass'] = np.arange(1,N+1)
def getgroup(id):
idx = id==groups['groupID']
return groups[idx]
members['groupmass'][:] = [getgroup(id)['mass'] for id in members['groupID']]
在python2
中,迭代可以使用map
:
members['groupmass'] = map(lambda x: getgroup(x)['mass'], members['groupID'])
通过最小化重复订阅,我可以将速度提高约2倍,例如
def setmass(members, groups):
gmass = groups['mass']
gid = groups['groupID']
mass = [gmass[id==gid] for id in members['groupID']]
members['groupmass'][:] = mass
但是如果groups['groupID']
可以映射到arange(N)
,那么我们可以在速度上有一个很大的飞跃。通过将相同的映射应用于成员['groupID']
,它变成了一个简单的数组索引问题
在我的示例数组中,groups['groupID']
只是arange(N)+101
。所以映射只是减去最小值
def setmass1(members, groups):
members['groupmass'][:] = groups['mass'][members['groupID']-groups['groupID'].min()]
这比我以前的代码快300倍,比pandas
解决方案(对于10000500阵列)好8倍
我怀疑熊猫是这样做的pgroups.set_index('groupID')。mass
是mass
系列,添加了.index
属性。(我可以用更通用的数组来测试)
在更一般的情况下,它可能有助于对组进行排序
,并在必要时填补一些索引空白
这是一个“矢量化”的解决方案——没有迭代。但它必须计算一个非常大的矩阵(组的长度乘以长度o)