首页 > 解决方案 > 用唯一列表中的后续值替换列值

问题描述

我有一个约 1000 个独特项目的列表

np.random.seed(0)
unique1 = sorted(list(np.random.choice(np.arange(2000), 1000, False)))

pandas df.column大约 1200 万行,其中仅包含此列表中的整数。

df = pd.DataFrame({'a': np.sort(np.random.choice(unique1[1:], 12000000))})

我需要做的是创建一个新列,其中始终包含唯一列表中的前一个元素,而不是原始列中的元素。

我试过这样做,apply但效率是可笑的,而且有一个普通的循环还不错(在我的系统上大约 2 分钟),但我想知道我是否可以更有效地到达那里(用于说明目的的较小数字) :

np.random.seed(0)
unique1 = sorted(list((np.random.choice(np.arange(20), 10, False))))
df = pd.DataFrame({'a': np.sort(np.random.choice(unique1[1:], 15))})

unique2 = unique1[1:]
df['b'] = df.a.apply(lambda x: unique1[unique2.index(x)])

newCol = []
for item in list(df.a):
    newCol.append(unique1[unique2.index(item)])
df['c'] = newCol
print(df, unique1)
     a   b   c
0    2   1   1
1    2   1   1
2    4   2   2
3    6   4   4
4    8   6   6
5    8   6   6
6    8   6   6
7   10   8   8
8   13  10  10
9   13  10  10
10  17  13  13
11  18  17  17
12  18  17  17
13  19  18  18
14  19  18  18 [1, 2, 4, 6, 8, 10, 13, 17, 18, 19]

标签: pythonpandas

解决方案


这里的问题是您正在使用list.index,它对所有唯一值进行线性搜索。

如果你能负担得起构建字典的空间,你可以把它变成一个恒定时间的查找:

unique2 = {value: index for index, value in enumerate(unique1[1:])}
df['b'] = df.a.apply(lambda x: unique1[unique2[x]])

如果你不能(在这种情况下,你应该首先将值保存在数组或切片中而不是列表中......),只要你保持它们排序,你至少可以以对数而不是线性时间搜索使用bisectnp.searchsorted

df['b'] = df.a.apply(lambda x: unique1[np.searchsorted(unique2, x)])

(如果是一个数组而不是一个列表,这会更快unique2,但只有一个常数因子;它仍然是一个列表的对数时间。)


推荐阅读