这是这个问题的后续。
How to map a unique number to each unique string in a column of lists
它询问如何将一个唯一的数字映射到包含列表的多个pandas列中的项。
当项目数量(A列和B列的项目总数)在大约4000万项的范围内时,所给出的解决方案似乎非常慢。我已经找到了一些方法,可以更快地为大约4000万项的数据集分配唯一的数字,但对于多列的情况,没有一种方法是很好的,其中一列包含一个列表。
下面是上面链接中的最小示例和解决方案:
设置数据帧
df = pd.DataFrame(data={'A': ['2f4', '1k1', 'nmk'], 'B': ['x', 'y', 'z']})
df.at[0, 'B'] = ['jki', 'gg4', 'k6k']
df.at[1, 'B'] = ['2f4', 'gg4', 'g24']
df.at[2, 'B'] = ['1k1', 'g24', '1k1', 'pir']
df
A B
0 2f4 [jki, gg4, k6k]
1 1k1 [2f4, gg4, g24]
2 nmk [1k1, g24, 1k1, pir]
解决方案
i, u = pd.factorize([*df.A, *np.concatenate(df.B)])
l = df.B.str.len()[:-1].cumsum()
n = len(df)
df.assign(MappedA=i[:n], MappedB=np.split(i[n:], l))
A B MappedA MappedB
0 2f4 [jki, gg4, k6k] 0 [3, 4, 5]
1 1k1 [2f4, gg4, g24] 1 [0, 4, 6]
2 nmk [1k1, g24, 1k1, pir] 2 [1, 6, 1, 7]
我在试着看看是否有更高效的解决方案。我怀疑这是因为有一些方法可以在几分钟内为大约4000万个项目分配唯一的编号(上面的解决方案似乎永远不会完成)。
这里就有一个这样的解决方案
mapping = {k: v for v, k in enumerate(df.A.unique())}
df['MappedA'] = df.A.map(mapping)
我想知道是否有一种方法可以将其应用于我的情况,即A列和B列中的项被映射到唯一的数字,从0开始,A列中的项获得第一个数字,然后将剩余的唯一项分配到B列中。
编辑:
一位用户提到,pandas不是处理字符串列表的计算效率最高的方法。我可以通过以下方法将其转换为numpy数组
numpyArray = df.values
因此,如果有一种方法可以使用numpy数组来解决这个问题,那么它就可以很容易地实现。
发布于 2018-09-10 09:18:09
效率低下的原因是我在构建各个部分时所采用的纬度。我可以通过一些调整来提高性能。
a = df.A.values
b = np.concatenate(df.B.values)
i, u = pd.factorize(np.append(a, b))
l = np.array([*map(len, df.B)])[:-1].cumsum()
n = len(df)
df.assign(MappedA=i[:n], MappedB=np.split(i[n:], l))
更大的df
df = pd.concat([df] * 10000, ignore_index=True)
%%timeit
i, u = pd.factorize([*df.A, *np.concatenate(df.B)])
l = df.B.str.len()[:-1].cumsum()
n = len(df)
df.assign(MappedA=i[:n], MappedB=np.split(i[n:], l))
# 1 loop, best of 3: 506 ms per loop
%%timeit
a = df.A.values
b = np.concatenate(df.B.values)
i, u = pd.factorize(np.append(a, b))
l = np.array([*map(len, df.B)])[:-1].cumsum()
n = len(df)
df.assign(MappedA=i[:n], MappedB=np.split(i[n:], l))
# 10 loops, best of 3: 95.1 ms per loop
这使我们的性能提高了5倍。
https://stackoverflow.com/questions/52249702
复制相似问题