>source

몇 개의 열에 특정 문자열이 있는지 확인하여 데이터 프레임을 처리하는 변환기가 있습니다.

class GenerateTextFlags(BaseEstimator, TransformerMixin):
    def __init__(self, variables=None):
        if not isinstance(variables, list):
            self.variables = sorted([variables])
        else:
            self.variables = sorted(variables)
        
        self.address_list = ['address', 'adres', 'adress', 'adresse', 'anschrift']
        
        self.contact_list = ['contact information', 'contactgegevens', 'contactinfo']
        
        self.cc_list = ['credit card', 'creditcard', 'bank card']
    def text_cleanup(self, input_str):
        from unidecode import unidecode
        import string
        from bs4 import BeautifulSoup
        from html import unescape
        s = BeautifulSoup(unescape(input_str), 'lxml').text
        cleaner = r'<.*?>|-|#x20;|[ \t]{2,}' # clean html
        s = re.sub(cleaner, '', str(s))
        s = unidecode(s)
        s = s.lower().translate(str.maketrans('', '', string.punctuation))
        return s
    
    def fit(self, X, y=None):
        return self
    def transform(self, X):
        import time
        print("Processing GenerateTextFlags")
        X = X[self.variables].fillna(" ").replace('nan', " ").copy()
        
        for col in self.variables:
            print('Processing: '+col+'; started at', round(time.time()/60)%1000, 'minutes')
            
            X[col] = X[col].apply(self.text_cleanup)
            X[col+'_CONTAINS_ADDRESS'] = X[col].str.contains('|'.join(self.address_list))*1
            X[col+'_CONTAINS_CONTACTINFO'] = X[col].str.contains('|'.join(self.contact_list))*1
            X[col+'_CONTAINS_BANKINGINFO'] = X[col].str.contains('|'.join(self.cc_list))*1
            
        
        X = X.drop(self.variables, axis=1)
        print('Finished processing at:', round(time.time()/60)%1000, 'minutes')
        
        return X

내가 위에있는 것은 톤 다운 된 샘플입니다. 실제 코드에는 각각 ~ 25 개의 요소가있는 ~ 10 개의 목록이 포함되어 있으며 ~ 5 개의 텍스트 열을 확인하여 해당 목록의 요소가 포함되어 있는지 확인하고 플래그에 저장합니다.

보시다시피 각 개별 열을 처리하는 것은 독립적이며 병렬로 실행할 수 있습니다. 나는 그것을하는 방법을 잘 모르겠습니다. 이 변환기를 백만 개가 넘는 행에서 실행 중이며 완료하는 데 매우 오랜 시간이 걸립니다 (16 코어와 64GB RAM이있는 M5 EC2 인스턴스를 사용하고 있으므로 리소스 측면에서 괜찮다고 생각합니다. 모든 리소스를 효율적으로 활용하기 위해 코드를 최적화하기 위해).

제안?


  • 답변 # 1

    열을 그룹화하고 사용하십시오. applymap 그들에 :

    cols = self.variables
    contains_address = [y + '_CONTAINS_ADDRESS' for y in cols]
    X[cols] = X[cols].applymap(self.text_cleanup)
    X[contains_address] = X[self.variables].apply(lambda y: y.str.contains('|'.join(self.address_list))*1)
    
    

  • 답변 # 2

    당신은 정말로 당신의 코드를 프로파일 링 할 필요가 있지만, 가장 많은 시간이 걸리는 부분은 사실상 이것 인 것 같습니다 (코드를 확장하여 text_cleanup() 호출 사이트에서) :

       for col in self.variables:
            for input_str in X[col]:
                from unidecode import unidecode
                import string
                from bs4 import BeautifulSoup
                from html import unescape
                s = BeautifulSoup(unescape(input_str), 'lxml').text
                cleaner = r'<.*?>|-|#x20;|[ \t]{2,}' # clean html
                s = re.sub(cleaner, '', str(s))
                s = unidecode(s)
                s = s.lower().translate(str.maketrans('', '', string.punctuation))
    
    

    이것은 DataFrame의 모든 셀에서 작동하는 중첩 된 for 루프입니다. 물론 속도가 느리지 만 그 이상은 왜 전화합니까? import 모든 세포에? 그것은 순수한 오버 헤드입니다. 그 진술을 파일의 맨 위로 올려주세요!

    다음으로 정규식을 사용하여 일부 문자를 제거하고 마지막에 모든 구두점을 제거합니다. 구두점 제거를 내가 생각하는 정규식으로 이동할 수 있습니다. 그리고 물론 당신은 전화해서는 안됩니다 maketrans() 루프를 통과 할 때마다하지만 맨 위에 한 번만

    이러한 기본 사항을 먼저 파악한 다음 프로필을 작성하십시오. 많은 문자열 변환 함수 중 어느 것이 가장 많은 시간이 걸리는지 확인하십시오.

    100 배 정도의 속도로이 속도를 높이려면 C, C ++, Numba 또는 기타 컴파일 된 언어로 변환을 작성하고 전체 배열에서 한 번에 실행해야합니다 (예 : 컴파일 된 코드). 그것은 문제에 스레드를 던지는 것보다 더 효과적 일 것입니다.

  • 이전 local storage - 자바 스크립트의 localStorage에서 중첩 항목 제거
  • 다음 php - WooCommerce 체크 아웃에서 사용자 정의 확인란 필드 상태를 저장하는 방법은 무엇입니까?