programing

파이썬 그룹 기준

powerit 2023. 6. 17. 09:47
반응형

파이썬 그룹 기준

인덱스 0이 값이고 인덱스 1이 유형인 데이터 쌍 집합이 있다고 가정합니다.

input = [
          ('11013331', 'KAT'), 
          ('9085267',  'NOT'), 
          ('5238761',  'ETH'), 
          ('5349618',  'ETH'), 
          ('11788544', 'NOT'), 
          ('962142',   'ETH'), 
          ('7795297',  'ETH'), 
          ('7341464',  'ETH'), 
          ('9843236',  'KAT'), 
          ('5594916',  'ETH'), 
          ('1550003',  'ETH')
        ]

다음과 같이 유형(첫 번째 인덱스 문자열 기준)으로 그룹화합니다.

result = [ 
           { 
             'type': 'KAT', 
             'items': ['11013331', '9843236'] 
           },
           {
             'type': 'NOT', 
             'items': ['9085267', '11788544'] 
           },
           {
             'type': 'ETH', 
             'items': ['5238761', '962142', '7795297', '7341464', '5594916', '1550003'] 
           }
         ] 

효율적인 방법으로 이를 달성하려면 어떻게 해야 합니까?

2단계로 진행합니다.먼저 사전을 만듭니다.

>>> input = [('11013331', 'KAT'), ('9085267', 'NOT'), ('5238761', 'ETH'), ('5349618', 'ETH'), ('11788544', 'NOT'), ('962142', 'ETH'), ('7795297', 'ETH'), ('7341464', 'ETH'), ('9843236', 'KAT'), ('5594916', 'ETH'), ('1550003', 'ETH')]
>>> from collections import defaultdict
>>> res = defaultdict(list)
>>> for v, k in input: res[k].append(v)
...

그런 다음 해당 사전을 필요한 형식으로 변환합니다.

>>> [{'type':k, 'items':v} for k,v in res.items()]
[{'items': ['9085267', '11788544'], 'type': 'NOT'}, {'items': ['5238761', '5349618', '962142', '7795297', '7341464', '5594916', '1550003'], 'type': 'ETH'}, {'items': ['11013331', '9843236'], 'type': 'KAT'}]

itertools.groupby로도 가능하지만 입력을 먼저 정렬해야 합니다.

>>> sorted_input = sorted(input, key=itemgetter(1))
>>> groups = groupby(sorted_input, key=itemgetter(1))
>>> [{'type':k, 'items':[x[0] for x in v]} for k, v in groups]
[{'items': ['5238761', '5349618', '962142', '7795297', '7341464', '5594916', '1550003'], 'type': 'ETH'}, {'items': ['11013331', '9843236'], 'type': 'KAT'}, {'items': ['9085267', '11788544'], 'type': 'NOT'}]

이 두 가지 모두 키의 원래 순서를 따르지 않습니다.질서를 유지하려면 질서 있는 칙령이 필요합니다.

>>> from collections import OrderedDict
>>> res = OrderedDict()
>>> for v, k in input:
...   if k in res: res[k].append(v)
...   else: res[k] = [v]
... 
>>> [{'type':k, 'items':v} for k,v in res.items()]
[{'items': ['11013331', '9843236'], 'type': 'KAT'}, {'items': ['9085267', '11788544'], 'type': 'NOT'}, {'items': ['5238761', '5349618', '962142', '7795297', '7341464', '5594916', '1550003'], 'type': 'ETH'}]

의 내장 Pythonitertools모듈에는 실제로 기능이 있지만, 이를 위해서는 먼저 그룹화할 요소가 목록에서 인접하도록 정렬되어야 합니다.

from operator import itemgetter
sortkeyfn = itemgetter(1)
input = [('11013331', 'KAT'), ('9085267', 'NOT'), ('5238761', 'ETH'), 
 ('5349618', 'ETH'), ('11788544', 'NOT'), ('962142', 'ETH'), ('7795297', 'ETH'), 
 ('7341464', 'ETH'), ('9843236', 'KAT'), ('5594916', 'ETH'), ('1550003', 'ETH')] 
input.sort(key=sortkeyfn)

이제 입력은 다음과 같습니다.

[('5238761', 'ETH'), ('5349618', 'ETH'), ('962142', 'ETH'), ('7795297', 'ETH'),
 ('7341464', 'ETH'), ('5594916', 'ETH'), ('1550003', 'ETH'), ('11013331', 'KAT'),
 ('9843236', 'KAT'), ('9085267', 'NOT'), ('11788544', 'NOT')]

groupby형식의 2-튜플 시퀀스를 반환합니다.(key, values_iterator)우리가 원하는 것은 이것을 dict 목록으로 바꾸는 것입니다. 여기서 'type'은 키이고 'items'는 values_iterator에 의해 반환되는 튜플의 0번째 요소 목록입니다.다음과 같이:

from itertools import groupby
result = []
for key,valuesiter in groupby(input, key=sortkeyfn):
    result.append(dict(type=key, items=list(v[0] for v in valuesiter)))

지금이다result질문에 명시된 대로 원하는 받아쓰기가 포함되어 있습니다.

그러나 유형별로 키를 지정하고 각 값에 값 목록을 포함하는 하나의 딕트를 만드는 것을 고려할 수 있습니다.현재 양식에서 특정 유형의 값을 찾으려면 목록을 반복하여 일치하는 '유형' 키가 포함된 딕트를 찾은 다음 해당 항목 요소를 가져와야 합니다.1개 항목 딕트 목록 대신 단일 딕트를 사용하면 마스터 딕트에 대한 단일 키 검색으로 특정 유형의 항목을 찾을 수 있습니다.용사를 합니다.groupby다음과 같이 표시됩니다.

result = {}
for key,valuesiter in groupby(input, key=sortkeyfn):
    result[key] = list(v[0] for v in valuesiter)

result이 딕트를 와 유사함).res@Kenny 기본령의 기본 TM의 답변):

{'NOT': ['9085267', '11788544'], 
 'ETH': ['5238761', '5349618', '962142', '7795297', '7341464', '5594916', '1550003'], 
 'KAT': ['11013331', '9843236']}

(이 값을 한 줄로 줄이려면 다음 작업을 수행할 수 있습니다.

result = dict((key,list(v[0] for v in valuesiter)
              for key,valuesiter in groupby(input, key=sortkeyfn))

또는 새로운 fangled 딕트 이해 양식을 사용합니다.

result = {key:list(v[0] for v in valuesiter)
              for key,valuesiter in groupby(input, key=sortkeyfn)}

이 답변은 @PaulMcG의 답변과 비슷하지만 입력을 정렬할 필요는 없습니다.

프로그래밍을 은,groupBy로 쓸 수은 포함하지 않음!)는 달리.itertools.groupby입력을 정렬할 필요가 없습니다.

from functools import reduce # import needed for python3; builtin in python2
from collections import defaultdict

def groupBy(key, seq):
 return reduce(lambda grp, val: grp[key(val)].append(val) or grp, seq, defaultdict(list))

:... or grp에 시대에lambda이것을 위한 것입니까?reduce()일을 하기 위해서 ,lambda첫 번째 인수를 반환해야 합니다. 왜냐하면list.append()항상 되돌아옴Noneor항상 돌아올 것입니다.grp즉, 람다는 하나의 표현식만 평가할 수 있다는 파이썬의 제약을 피하기 위한 해킹입니다.)

지정된 함수를 평가하여 키를 찾은 딕트와 값이 원래 순서의 원래 항목 목록인 딕트를 반환합니다.OP의 예로, 이것을 다음과 같이 부릅니다.groupBy(lambda pair: pair[1], input)다음 dict를 반환합니다.

{'KAT': [('11013331', 'KAT'), ('9843236', 'KAT')],
 'NOT': [('9085267', 'NOT'), ('11788544', 'NOT')],
 'ETH': [('5238761', 'ETH'), ('5349618', 'ETH'), ('962142', 'ETH'), ('7795297', 'ETH'), ('7341464', 'ETH'), ('5594916', 'ETH'), ('1550003', 'ETH')]}

그리고 @PaulMcG의 답변에 따르면 OP가 요청한 형식은 목록 이해로 포장하여 찾을 수 있습니다.이렇게 하면 됩니다.

result = {key: [pair[0] for pair in values],
          for key, values in groupBy(lambda pair: pair[1], input).items()}

저는 또한 판다들이 단순한 그룹을 이루는 것을 좋아했습니다.강력하고 단순하며 대용량 데이터 세트에 가장 적합합니다.

result = pandas.DataFrame(input).groupby(1).groups

다음 함수는 임의의 길이의 튜플을 인덱스가 있는 키로 빠르게(정렬할 필요가 없음) 그룹화합니다.

# given a sequence of tuples like [(3,'c',6),(7,'a',2),(88,'c',4),(45,'a',0)],
# returns a dict grouping tuples by idx-th element - with idx=1 we have:
# if merge is True {'c':(3,6,88,4),     'a':(7,2,45,0)}
# if merge is False {'c':((3,6),(88,4)), 'a':((7,2),(45,0))}
def group_by(seqs,idx=0,merge=True):
    d = dict()
    for seq in seqs:
        k = seq[idx]
        v = d.get(k,tuple()) + (seq[:idx]+seq[idx+1:] if merge else (seq[:idx]+seq[idx+1:],))
        d.update({k:v})
    return d

질문의 경우 그룹화할 키의 인덱스는 1이므로 다음과 같습니다.

group_by(input,1)

기브즈

{'ETH': ('5238761','5349618','962142','7795297','7341464','5594916','1550003'),
 'KAT': ('11013331', '9843236'),
 'NOT': ('9085267', '11788544')}

당신이 요청한 출력은 정확하지 않지만, 당신의 필요에 맞는 것일 수도 있습니다.

result = []
# Make a set of your "types":
input_set = set([tpl[1] for tpl in input])
>>> set(['ETH', 'KAT', 'NOT'])
# Iterate over the input_set
for type_ in input_set:
    # a dict to gather things:
    D = {}
    # filter all tuples from your input with the same type as type_
    tuples = filter(lambda tpl: tpl[1] == type_, input)
    # write them in the D:
    D["type"] = type_
    D["itmes"] = [tpl[0] for tpl in tuples]
    # append D to results:
    result.append(D)

result
>>> [{'itmes': ['9085267', '11788544'], 'type': 'NOT'}, {'itmes': ['5238761', '5349618', '962142', '7795297', '7341464', '5594916', '1550003'], 'type': 'ETH'}, {'itmes': ['11013331', '9843236'], 'type': 'KAT'}]

정확한 작업에 대한 애드혹 코드를 생성하고 동적 코드 생성을 허용하는 convtools 라이브러리를 사용할 수 있습니다.

from convtools import conversion as c

# grouping by second elements of tuples;
# aggregate defines the schema of the expected output elements
converter = c.group_by(c.item(1)).aggregate({
    "type": c.item(1),
    "items": c.ReduceFuncs.Array(c.item(0)),
}).gen_converter()

# now you have a function which does what you asked,
# store it somewhere for further reuse
converter(input_data)

다음 스니펫을 따르는 것도 원하는 결과를 얻을 수 있는 방법입니다.

res = []
dict1 = {}
for item in input:
  if item[1] not in dict1:
    dict1[item[1]] = [item[0]]
  elif item[1] in dict1:
    dict1[item[1]].append(item[0])
for k, v in dict1.items():
  res.append({"type": k, "items": v})


# res = [ { type:'KAT', items: ['11013331', '9843236'] },{ type:'NOT',  items: ['9085267', '11788544'] },{ type:'ETH',  items: ['5238761', '962142', '7795297', '7341464', '5594916', '1550003'] }] 

이것은 매우 효율적이지는 않지만, 파이썬적입니다.기본적으로 그룹 값 집합을 가져와서 개별 그룹을 계산한 다음 각 그룹에 대해 해당 그룹에 있는 항목을 가져옵니다.

[
    {
        "type": group,
        "items": [item[0] for item in input if item[1] == group]
    }
    for group in {item[1] for item in input}
]

언급URL : https://stackoverflow.com/questions/3749512/python-group-by

반응형