根据他们的标签进行子集
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]]
.
这里0
、1
和2
只是class不同而已。例如,a
来自 class 0
,而 b
和 c
来自 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)
答案的另一个变体(这里有 groupby
和 itemgetter
):
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']]
假设我有两个列表: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]]
.
这里0
、1
和2
只是class不同而已。例如,a
来自 class 0
,而 b
和 c
来自 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)
答案的另一个变体(这里有 groupby
和 itemgetter
):
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']]