Python 根据其标签的子集

Python 根据其标签的子集,python,numpy,zip,list-comprehension,Python,Numpy,Zip,List Comprehension,假设我有两个列表:字母=[a,b,c,d,e,f,g,h,I]和数字=[0,1,1,2,1,1,0,2,1,0]。我希望最终结果是output=[[a,f,I],[b,c,e,I],[d,g,h] 这里的0、1和2是不同的类。例如,a来自class0,而b和c来自class1。我只需要根据字母的类别将其放入子列表中 我想我可以在这里给你zip()和一个列表,但我不知道怎么做。如何使用numpy实现这一点?您可以使用zip()和临时字典: letters = ['a', 'b', 'c', 'd'

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


这里的
0
1
2
是不同的类。例如,
a
来自class
0
,而
b
c
来自class
1
。我只需要根据字母的类别将其放入子列表中

我想我可以在这里给你
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
):


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

从itertools导入groupby
从运算符导入itemgetter
字母=['a','b','c','d','e','f','g','h','i']
数字=[0,1,1,2,1,0,2,2,1,0]
组合字母数字=排序(zip(字母,数字),键=itemgetter(1))
字母\组=分组依据(组合字母\数字,itemgetter(1))
out=[[group_数据中的项的项[0]对于字母组中的(键,group_数据)]
打印(输出)

更加简洁,没有带
熊猫的循环

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')]
[array(['a',f',i',dtype=',因为您标记了numpy(我个人更喜欢pandas groupby,因为它是干净的,用于此目的):


你能解释一下你是如何得到所需的
输出的吗?
0
1
2
只是不同的类。例如,
a
来自类
0
,而
b
c
来自类
1
。我只需要根据它们的类将字母放入子列表中。我不知道由于类的数量可能会有所不同,您可能需要使用
tmp.values()
此处取而代之,而不是
diff
中预先添加
以重新分配内存,您可能希望在
marker\u idx
中添加1。此外,
flatnonzero
此处的非零
更简单。+1是正确的numpy解决方案。忽略nitpicking@Mad我见过的物理学家不受欢迎,但并没有I don’我不认为它在内存方面效率低下。这些都是很好的提示。
prepend
调用
np。在纯python代码部分连接
。这很难看。
[array(['a', 'f', 'i'], dtype='<U1'), array(['b', 'c', 'e'], dtype='<U1'), array(['d', 'g', 'h'], dtype='<U1')]
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']]