2017-11-30 11 views
0

계정 연결 구조를 지정하는 두 개의 열이있는 CSV 파일이 있습니다. 내가 가지고있는 문제는 각각의 링크에 대해 역방향 역방향 항목이 있다는 것입니다.Python - 고유 한 값을 기반으로 찾기, 일치, 정렬 및 추가

Column1 Column2 
12513 52188 
52188 12513 

나는 또한과 같은 계좌 번호에서 다른 연결을 지정하는 항목을 더 이상있을 수 있다는 것입니다이 다른 문제

Column1 Column2 
12513 52188 
52188 12513 
52188 19922 
19922 52188 
19922 12812 
12812 19922 
18216 59888 
59888 18216 
3856 59888 
59888 3856 

당신은 모두를 볼 수있는 계정이 어떻게 든간에 서로 연결되어 있다면, 찾고있는 출력은 종속 계정에 연결된 하나의 마스터 계정 (아마도 가장 가치가 낮은 계정)을 만들고 두 개의 역방향 항목을 제거해야합니다. 위의 데이터에서

예 출력 :

Column1 Column2 
12513 52188 
12513 19922 
12513 12812 
3856 59888 
3856 18216 

파일은, 하나 개의 마스터 계정뿐만 아니라이 유의하시기 바랍니다과 주변에 20,000 선이 포함되어 있습니다.

+0

는 불분명하다 – RomanPerekhrest

+1

'자식 클론 https : //로 github.com/NiallCosgrove/kayboxa' –

+0

그것의 최대 GitHub의에 이제 복사/붙여 넣기 오류를 피하십시오. 나는 20000 쌍의 무작위 수를 테스트하여 한 시간 반 정도 걸렸습니다. 나에게 당신이 어떻게되는지 알려주세요 –

답변

1

그래서 질문은 :
여기

1,2 
1,3 
1,4 
5,6 
5,7 

으로 체인 1 -> 2 -> 3 -> 45 -> 6 -> 7 그리고 출력을 식별 형태

1,2 
1,3 
1,4 
3,1 
6,5 
5,7 

에서 데이터 세트를 부여 파이썬에서 작업 솔루션 .

는 물론, python thisfile.py yourdata.csv > output.csv

당신을 사용하여 실행하려면 (해피 홀리데이는), python3가 설치되어 있어야합니다. 코드에 많은 의견이 있습니다. 효율성을 전혀 고려하지 않았으므로 주전자를 켜십시오. 완료하는 데 약 15 분 정도 걸립니다.

더 빨리하려면 해당 시간이 소요되는 list.append() 호출이 필요합니다. numpy를 사용하면 일이 빨라지 겠지만 여분의 의존성을 추가하고 싶지는 않습니다.

궁금한 점이 있으면 알려주세요. 귀하의 예제 데이터에서

출력은 다음과 같습니다

당신이 출력 예상
3856 , 18216 
3856 , 59888 
12513 , 12812 
12513 , 19922 
12513 , 52188 
import csv 
import sys 


def flatten(l): 
    return list(set([item for subl in l for item in subl])) 

def main(): 
    # read the csv                      
    raw_data = [] 
    with open(sys.argv[1], 'r') as so_data: 
     lst = csv.reader(so_data) 
     for row in lst: 
      raw_data.append(row) 

     data = [] 
     for i in raw_data: 
      data.append([int(i[0].strip()), int(i[1].strip())]) 

     #set keys to uniq elements from col1 and col2             
     keys1 = list(set([i[0] for i in data])) 
     keys2 = list(set([i[1] for i in data])) 
     keys = list(set(keys1 + keys2)) 

     # find the subchains for each key                
     subchains = {} 
     for key in keys: 
      found = [k for k in data if key in k] 
      found = flatten(found) 
      subchains[key] = found 

     # This is the tricky bit                   
     # we need to follow each element of the subchains looking          
     # for new links - we are done for a key when the list doesn't grow        
     chain, links = [], [] 
     chain_dict = {} 
     for key in keys: 
      links.append(subchains[key]) 
      links = flatten(links) 
      done = False 
      size = len(links) 
      while not done: 
       for i in links: 
        # find subchain for i                
        for e in subchains[i]: 
         chain.append(e) 
         chain = list(set(chain)) 
         chain.sort() 
       if len(chain) > size: 
        done = False 
        size = len(chain) 
       else: 
        done = True 
        chain_dict[key] = chain 
        chain, links = [], [] 

     # shorter chains will now be subsets of longer ones            
     # and those can be discarded                  
     remove_list = [] 
     for i in keys: 
      for j in keys: 
       if set(chain_dict[j]) < set(chain_dict[i]): 
        remove_list.append(j) 

     remove_list = list(set(remove_list)) 
     for i in remove_list: 
      del chain_dict[i] 

     # remove duplicate values from dict                
     # it doesn't matter which key we remove               
     # since we only output from value                
     result = {} 
     for key, value in chain_dict.items(): 
      if value not in result.values(): 
       result[key] = value 

     # now output as per OP's request                 
     for k, v in result.items(): 
      v.sort() 
      for i in v[1:]: 
       print(v[0], ",", i) 

if __name__ == '__main__': 
    main()