Условное регулярное выражение, разделенное на python - PullRequest
0 голосов
/ 05 февраля 2020

Я хочу разделить название компании на родительскую и псевдонимную компанию на основании некоторых условий. Мне нужна помощь в этом.

Original_Input

DORO INC ( O/S DORO SAFETY & SECURITY)
MJB SUPPLY (DALIAN) CO., LTD.
Iris Diagnostics, a Division of Iris International Inc
GINGI-PAK a division of The Belport Co., Inc.
H/P/COSMOS SPORTS & MEDICAL GMBH
Arrayent Health LLC d/b/a/ Ambio Healthc
Arrow International, Inc. (subsidiary of Teleflex, Inc.)

Ожидаемый результат:

Parent_Company                                              Alias_Name

1.DORO INC                                                  O/S DORO SAFETY & SECURITY
2.MJB SUPPLY CO., LTD.                                      DALIAN    
3.Iris Diagnostics, 
4.GINGI-PAK                                                 The Belport Co., Inc.
5.H                                                         P/COSMOS SPORTS & MEDICAL GMBH
6.Arrayent Health LLC                                       Ambio Healthc
7.Arrow International, Inc.     

Мой код:

Сплит материнской компании:

def get_parent_company(input):
keywords = ["a division of", "c/o","subsidiary of", "division of","an","dba","d/b/a","o/s","os","\/"]
regex = r"(.*?)(\b{}\b)".format("\\b|\\b".join(keywords))
matches = re.finditer(regex, input, re.IGNORECASE)
for match in matches:
    return match.group(1).strip()

data["Parent_Company"] = data["Original_Input"].apply(get_parent_company).fillna('')

Сплит компании Alias:

pat = r'\((.*?)\)'
pat1 = r'(?:(?=[^\s/]*/(?!\s|[^\s/]*/))|\$|a division of|&|/\s)\s*(.*)'
if pat:
    data['Alias_Name'] = data['Original_Input'].str.extract(r'\((.*?)\)')
 if pat1:
    data['Alias_Name'] = data['Original_Input'].str.extract(r'(?:(?=[^\s/]*/(?!\s|[^\s/]*/))|\$|a 
                                              division of|&|/\s)\s*(.*)',expand= False).fillna('')

Так что здесь есть разные типы ввода. Слова перед ключевыми словами ("подразделение", "с / о", "дочерняя компания", "подразделение", "an", "dba", "d / b / a", "o / s", "" os "," / ") необходимо упомянуть как родительскую компанию, а слова после этого для некоторого ввода в качестве псевдонима.

Также существует другой тип ввода Например. MJB SUPPLY (DALIAN) CO., LTD. где (Далянь) является псевдонимом и остается как MJB SUPPLY CO., LTD. это имя родителя.

Мои усилия:

Поэтому я попытался поместить регулярное выражение (с помощью некоторых друзей здесь в SO) с ключевыми словами для получения имени родителя и псевдонима. Но я не знаю, как поставить одно или два условия для регулярного выражения, я могу сказать, что я не знаю, как разделить входы разных типов во фрейме данных.

Заранее спасибо за помощь.

РЕДАКТИРОВАТЬ

%%time
import pyodbc
import pandas as pd
import string
from string import digits
import sqlalchemy
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy.types import String
from io import StringIO
import re





#Creating engine to connect Py to SQL
engine = create_engine('mssql+pyodbc:// **:***'+server+'/'+database+'? 
driver=SQL+server')

#Reading SQL table and grouping by columns
df=pd.read_sql('select * from [dbo].[TempCompanyName]',engine)

#Creating Dataframe
#data=pd.DataFrame(df)

# removing numbers,duplicated spaces,spaces before or after the string
data['Cleansed_Input'] = data["Original_Input"].str.replace("[0-9]+", 
"").str.replace("[^\w ]+", "").str.replace(" +", " ").str.strip()

#Removing ASCII characters
data['Cleansed_Input'] = data['Cleansed_Input'].apply(lambda x:''.join(['' if 
ord(i) < 32 or ord(i) > 126 else i for i in x]))


#Method 2 in splitting:

class CompanyAlias(object):
    rules = [
        re.compile(r"(?P<PREFIX>[^\(]*)(\((? 
P<SUBSIDIARY>\s+subsidiary\s+.*)\))?(?P<SUFFIX>.*)", re.IGNORECASE),
    re.compile(r"(?P<PREFIX>[^\(]*)(\((?P<ALIAS>[^\)]+)\))?(?P<SUFFIX>.*)", 
re.IGNORECASE),
    re.compile(r"(?P<PREFIX>.*),?\s+a\s+division\s+of\s+(?P<DIVISIONOF>.*)", 
re.IGNORECASE),
    re.compile(r"(?P<PREFIX>.*)\s+d/b/a/\s+(?P<ALIAS>.*)", re.IGNORECASE),
    re.compile(r"(?P<PREFIX>[^/]+)/(?P<ALIAS>.*)", re.IGNORECASE)
]

@classmethod
def process_rules(cls, name, biz_rules=None):
    if biz_rules is None:
        biz_rules = cls.rules

    # process all the rules for the given name
    results = [r.match(name) for r in biz_rules]
    # keep only results that successfully matched a rule
    retval = [r.groupdict() for r in results if r]
    return retval

@classmethod
def process_results(cls, results):
    """Process results applies the desired business logic
    to the results obtained via regular expression processing
    1. Alias rules are priority 1
    2. division of rules are priority 2

    rankings element 0 is a list of all alias results in order of
    precedence. element 1 is a list of all division of rules in 
    order of precedence.

    Note: company names are always composed of SUFFIX + PREFIX
    """
    rankings = [[], []]
    retval = ("", "", "")
    for r in results:
        alias = r.get("ALIAS", "")
        divisionof = r.get("DIVISIONOF", None)
        company = "{0}{1}".format(r.get("PREFIX",""), r.get("SUFFIX",""))
        if alias:
            if re.search("subsidiary", alias, re.IGNORECASE):
                alias = ""
            rankings[0].append((company, alias.strip(), divisionof))
        if divisionof:
            rankings[1].append((company, alias, divisionof))

    # if there is at least 1 alias business rule applied
    # then return the first result from the alias rules
    # otherwise if there is at least 1 division of rule return
    # that.
    if len(rankings[0]) > 0:
        retval = rankings[0][0]
    elif len(rankings[1]) > 0:
        retval = rankings[1][0]

    return retval


if __name__ == "__main__":
    names = df["Original_Input"]

#print("{0:40s} Alias_Name".format("Parent_Company"))
#print()
for name in names:
    results = CompanyAlias.process_rules(name)
    result = CompanyAlias.process_results(results)
    #print("{0:40s} {1}".format(result[0], result[1]))
    df['Parent_company'] = result[0] 
    df['Alias_Name'] = result[1]
data=pd.DataFrame(df) 
#Writing to SQL
data.to_sql('TempCompanyName', con=engine, if_exists='replace',index= False)

#Splitting Company type and Extension.

engine.execute('''update A 
set A.Type_input = B.Company_Type 
from [TempCompanyName] A (nolock), [company_Extension]B  where  
A.Cleansed_Input like '%'+B.Name_Extension

update A 
set A.Core_Input =replace(A.[Cleansed_Input],B.Name_Extension,'')
from [TempCompanyName] A (nolock), [company_Extension]B  where  
A.Cleansed_Input like '%'+B.Name_Extension''')

engine.execution_options(autocommit=True)

В целях безопасности скрыть данные сервера

1 Ответ

0 голосов
/ 05 февраля 2020

Примечание: в этом ответе много предостережений

К сожалению, вы наткнулись на кроличью нору. Очистка и разбор имен - это отрасль сама по себе. В зависимости от того, в каком бизнесе вы находитесь, вы можете исследовать компании, предоставляющие этот тип услуг. Я желаю вам всего 1026 * удачи в мире, поскольку мне неоднократно поручалось это усилие.

Методология

Создайте серию приоритетных бизнес-правил для определения случаев, которые вы видите на на регулярной основе. По мере появления новых пограничных случаев просто добавьте больше правил в соответствующем приоритете.

Приоритизация важна, поскольку одно правило может создать ложный положительный результат. Правила ложного позитива должны иметь более низкие приоритеты, чем правила истинного позитива.

Чтобы проиллюстрировать этот момент, вы представили в своих примерах имена с H / P / Cosmos и d / b / a, которые требуют различных правил для идентификации. Однако если правило, определяющее H / P / Cosmos, применяется до правила working-busines-as , вы получите False Positive для имени, содержащего d / b / a.

Это достаточно хорошо?

Наборы данных в отдельных источниках, как правило, имеют индивидуальность. Существуют сходства, которые проявляются на высоких частотах и ​​позволяют создавать бизнес-правила, которые обеспечивают вам 90% пути к вашей цели.

Советы

Старайтесь избегать потери информации при разборе ваших имен. Определите префиксы, суффиксы, псевдонимы, дочерние компании и подразделения и сохраните их для последующего разрешения. Отметить подозрительные записи для просмотра. Это позволит вам определить новые правила и предотвратить переход мусора на следующую фазу обработки.

import re

class CompanyAlias(object):
    rules = [
        re.compile(r"(?P<PREFIX>[^\(]*)(\((?P<SUBSIDIARY>\s+subsidiary\s+.*)\))?(?P<SUFFIX>.*)", re.IGNORECASE),
        re.compile(r"(?P<PREFIX>[^\(]*)(\((?P<ALIAS>[^\)]+)\))?(?P<SUFFIX>.*)", re.IGNORECASE),
        re.compile(r"(?P<PREFIX>.*),?\s+a\s+division\s+of\s+(?P<DIVISIONOF>.*)", re.IGNORECASE),
        re.compile(r"(?P<PREFIX>.*)\s+d/b/a/\s+(?P<ALIAS>.*)", re.IGNORECASE),
        re.compile(r"(?P<PREFIX>[^/]+)/(?P<ALIAS>.*)", re.IGNORECASE)
    ]

    @classmethod
    def process_rules(cls, name, biz_rules=None):
        if biz_rules is None:
            biz_rules = cls.rules

        # process all the rules for the given name
        results = [r.match(name) for r in biz_rules]
        # keep only results that successfully matched a rule
        retval = [r.groupdict() for r in results if r]
        return retval

    @classmethod
    def process_results(cls, results):
        """Process results applies the desired business logic
        to the results obtained via regular expression processing
        1. Alias rules are priority 1
        2. division of rules are priority 2

        rankings element 0 is a list of all alias results in order of
        precedence. element 1 is a list of all division of rules in 
        order of precedence.

        Note: company names are always composed of SUFFIX + PREFIX
        """
        rankings = [[], []]
        retval = ("", "", "")
        for r in results:
            alias = r.get("ALIAS", "")
            divisionof = r.get("DIVISIONOF", None)
            company = "{0}{1}".format(r.get("PREFIX",""), r.get("SUFFIX",""))
            if alias:
                if re.search("subsidiary", alias, re.IGNORECASE):
                    alias = ""
                rankings[0].append((company, alias.strip(), divisionof))
            if divisionof:
                rankings[1].append((company, alias, divisionof))

        # if there is at least 1 alias business rule applied
        # then return the first result from the alias rules
        # otherwise if there is at least 1 division of rule return
        # that.
        if len(rankings[0]) > 0:
            retval = rankings[0][0]
        elif len(rankings[1]) > 0:
            retval = rankings[1][0]

        return retval


if __name__ == "__main__":
    names = [
        "DORO INC ( O/S DORO SAFETY & SECURITY)",
        "MJB SUPPLY (DALIAN) CO., LTD.",
        "Iris Diagnostics, a Division of Iris International Inc",
        "GINGI-PAK a division of The Belport Co., Inc.",
        "H/P/COSMOS SPORTS & MEDICAL GMBH",
        "Arrayent Health LLC d/b/a/ Ambio Healthc",
        "Arrow International, Inc. (subsidiary of Teleflex, Inc.)",
    ]
    print("{0:40s} Alias_Name".format("Parent_Company"))
    print()
    for name in names:
        results = CompanyAlias.process_rules(name)
        result = CompanyAlias.process_results(results)
        print("{0:40s} {1}".format(result[0], result[1]))

Вывод

Parent_Company                           Alias_Name

DORO INC                                 O/S DORO SAFETY & SECURITY
MJB SUPPLY  CO., LTD.                    DALIAN
Iris Diagnostics,                        
GINGI-PAK                                
H                                        P/COSMOS SPORTS & MEDICAL GMBH
Arrayent Health LLC                      Ambio Healthc
Arrow International, Inc.                
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...