根据他们的标签进行子集

Subset according to their label

假设我有两个列表:letters = [a, b, c, d, e, f, g, h, i]digits = [0, 1, 1, 2, 1, 0, 2, 2, 1, 0]。我希望最终结果是 output = [[a, f, i], [b, c, e, i], [d, g, h]].

这里012只是class不同而已。例如,a 来自 class 0,而 bc 来自 class 1。我只需要根据字母 class.

将字母放在子列表中

我想我可以 zip() 在这里和列表理解,但我不确定该怎么做。我怎样才能使用 numpy 做到这一点?

您可以使用 zip() 和临时字典:

letters = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i']
digits = [0, 1, 1, 2, 1, 0, 2, 2, 1, 0]

tmp = {}
for d, l in zip(digits, letters):
    tmp.setdefault(d, []).append(l)

out = []
for k in sorted(tmp):
    out.append(tmp[k])

print(out)

打印:

[['a', 'f'], ['b', 'c', 'e', 'i'], ['d', 'g', 'h']]

或者:另一个版本(使用itertools.groupby):

from itertools import groupby

out = []
for _, g in groupby(sorted(zip(digits, letters)), lambda k: k[0]):
    out.append([l for _, l in g])

print(out)

答案的另一个变体(这里有 groupbyitemgetter):

from itertools import groupby
from operator import itemgetter

letters = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i']
digits = [0, 1, 1, 2, 1, 0, 2, 2, 1, 0]

combined_letters_digits = sorted(zip(letters, digits), key=itemgetter(1))
letter_groups = groupby(combined_letters_digits, itemgetter(1))
out = [[item[0] for item in group_data] for (key, group_data) in letter_groups]

print(out)

更简洁,没有 pandas

的循环
import pandas as pd

s = pd.Series(
    ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i'],
    index=[0, 1, 1, 2, 1, 0, 2, 2, 1],
    name='letters'
)

[*s.groupby(level=0).agg(list)]


[['a', 'f'], ['b', 'c', 'e', 'i'], ['d', 'g', 'h']]

numpy 解决方案也是可以的:

digits = np.array([0, 1, 1, 2, 1, 0, 2, 2, 0])
letters = np.array(['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i'])
argidx = np.argsort(digits)
digits, letters = digits[argidx], letters[argidx]
markers = np.diff(digits, prepend=digits[0])
marker_idx, = np.nonzero(markers)
np.split(letters, marker_idx)

输出:

[array(['a', 'f', 'i'], dtype='<U1'), array(['b', 'c', 'e'], dtype='<U1'), array(['d', 'g', 'h'], dtype='<U1')]

因为你标记了 numpy(我个人更喜欢 pandas groupby,因为它很干净并且适合这个目的):

d,l = list(zip(*(sorted(zip(digits,letters)))))
d = np.array(d)
idx = np.flatnonzero(np.r_[True, d[:-1] != d[1:], True])
output = [list(l[i:j]) for i,j in zip(idx[:-1],idx[1:])]
#[['a', 'f'], ['b', 'c', 'e', 'i'], ['d', 'g', 'h']]