4 분 소요


image

이 포스팅에서는 일관성 없는 텍스트 항목을 정리하는 방법을 배워 보겠습니다.


Get our environment set up

가장 먼저 해야 할 일은 사용할 라이브러리와 데이터 세트를 로드하는 것입니다.

# modules we'll use
import pandas as pd
import numpy as np

# helpful modules
import fuzzywuzzy
from fuzzywuzzy import process
import charset_normalizer

# read in all our data
professors = pd.read_csv("../input/pakistan-intellectual-capital/pakistan_intellectual_capital.csv")

# set seed for reproducibility
np.random.seed(0)


Do some preliminary text pre-processing

데이터의 처음 몇 행을 간단히 살펴보는 것으로 시작하겠습니다.

professors.head()
  Unnamed: 0 S# Teacher Name University Currently Teaching Department Province University Located Designation Terminal Degree Graduated from Country Year Area of Specialization/Research Interests Other Information
0 2 3 Dr. Abdul Basit University of Balochistan Computer Science & IT Balochistan Assistant Professor PhD Asian Institute of Technology Thailand NaN Software Engineering & DBMS NaN
1 4 5 Dr. Waheed Noor University of Balochistan Computer Science & IT Balochistan Assistant Professor PhD Asian Institute of Technology Thailand NaN DBMS NaN
2 5 6 Dr. Junaid Baber University of Balochistan Computer Science & IT Balochistan Assistant Professor PhD Asian Institute of Technology Thailand NaN Information processing, Multimedia mining NaN
3 6 7 Dr. Maheen Bakhtyar University of Balochistan Computer Science & IT Balochistan Assistant Professor PhD Asian Institute of Technology Thailand NaN NLP, Information Retrieval, Question Answering… NaN
4 24 25 Samina Azim Sardar Bahadur Khan Women’s University Computer Science Balochistan Lecturer BS Balochistan University of Information Technolo… Pakistan 2005.0 VLSI Electronics DLD Database NaN

‘Country’ 열에 데이터 입력 불일치가 없는지 확인하기 위해 정리하고 싶다고 가정해 보겠습니다. 물론 각 행을 일일이 손으로 확인하고 불일치를 발견하면 수작업으로 수정할 수도 있습니다. 하지만 이보다 더 효율적인 방법이 있습니다!

# get all the unique values in the 'Country' column
countries = professors['Country'].unique()

# sort them alphabetically and then take a closer look
countries.sort()
countries
array([' Germany', ' New Zealand', ' Sweden', ' USA', 'Australia',
       'Austria', 'Canada', 'China', 'Finland', 'France', 'Greece',
       'HongKong', 'Ireland', 'Italy', 'Japan', 'Macau', 'Malaysia',
       'Mauritius', 'Netherland', 'New Zealand', 'Norway', 'Pakistan',
       'Portugal', 'Russian Federation', 'Saudi Arabia', 'Scotland',
       'Singapore', 'South Korea', 'SouthKorea', 'Spain', 'Sweden',
       'Thailand', 'Turkey', 'UK', 'USA', 'USofA', 'Urbana', 'germany'],
      dtype=object)

예를 들어 ‘Germany’과 ‘germany’ 또는 ‘New Zealand’와 ‘New Zealand’와 같이 데이터 입력이 일치하지 않아서 문제가 발생하는 것을 볼 수 있습니다.

가장 먼저 할 일은 모든 것을 소문자로 만들고(원한다면 마지막에 다시 변경할 수 있습니다) 셀의 시작과 끝에 있는 공백을 모두 제거하는 것입니다. 텍스트 데이터에서 대문자와 뒤따르는 공백의 불일치는 매우 흔한 문제이며, 이렇게 하면 텍스트 데이터 입력 불일치의 80% 정도를 해결할 수 있습니다.

# convert to lower case
professors['Country'] = professors['Country'].str.lower()
# remove trailing white spaces
professors['Country'] = professors['Country'].str.strip()

다음으로 좀 더 어려운 불일치 문제를 해결해 보겠습니다.


Use fuzzy matching to correct inconsistent dfata entry

이제 ‘Country’ 열을 다시 한 번 살펴보고 더 정리해야 할 데이터가 있는지 확인해 보겠습니다.

# get all the unique values in the 'Country' column
countries = professors['Country'].unique()

# sort them alphabetically and then take a closer look
countries.sort()
countries
array(['australia', 'austria', 'canada', 'china', 'finland', 'france',
       'germany', 'greece', 'hongkong', 'ireland', 'italy', 'japan',
       'macau', 'malaysia', 'mauritius', 'netherland', 'new zealand',
       'norway', 'pakistan', 'portugal', 'russian federation',
       'saudi arabia', 'scotland', 'singapore', 'south korea',
       'southkorea', 'spain', 'sweden', 'thailand', 'turkey', 'uk',
       'urbana', 'usa', 'usofa'], dtype=object)

‘southkorea’와 ‘south korea’가 동일해야 하는 또 다른 불일치가 있는 것 같습니다.

fuzzywuzzy 패키지를 사용해 어떤 문자열이 서로 가장 가까운지 식별할 수 있도록 하겠습니다. 이 데이터 세트는 충분히 작아서 수작업으로 오류를 수정할 수 있지만, 이러한 접근 방식은 확장성이 좋지 않습니다. (수천 개의 오류를 수작업으로 수정하고 싶으신가요? 만 개는 어떨까요? 가능한 한 빨리 자동화하는 것이 일반적으로 좋은 생각입니다. 게다가 재미도 있죠!)

퍼지 매칭(fuzzy matching): 대상 문자열과 매우 유사한 텍스트 문자열을 자동으로 찾는 프로세스입니다. 일반적으로 한 문자열을 다른 문자열로 변환할 때 변경해야 하는 문자가 적을수록 다른 문자열에 “가까운” 문자열로 간주됩니다. 따라서 “apple”과 “snapple”은 서로 두 개(“s”와 “n”을 추가)만 변경하면 되고, “in”과 “on”은 한 개(“i”를 “o”로 대체)만 변경하면 됩니다. 퍼지 매칭에 항상 100% 의존할 수는 없지만 일반적으로 최소한 시간을 조금이라도 절약할 수 있습니다.

fuzzywuzzy는 두 문자열이 주어지면 비율을 반환합니다. 비율이 100에 가까울수록 두 문자열 사이의 편집 거리가 작아집니다. 여기서는 도시 목록에서 “south korea”와 가장 가까운 거리에 있는 10개의 문자열을 가져옵니다.

# get the top 10 closest matches to "south korea"
matches = fuzzywuzzy.process.extract("south korea", countries, limit=10, scorer=fuzzywuzzy.fuzz.token_sort_ratio)

# take a look at them
matches
[('south korea', 100),
 ('southkorea', 48),
 ('saudi arabia', 43),
 ('norway', 35),
 ('austria', 33),
 ('ireland', 33),
 ('pakistan', 32),
 ('portugal', 32),
 ('scotland', 32),
 ('australia', 30)]

도시 중 두 개의 항목이 “south korea”에 매우 가깝다는 것을 알 수 있습니다: “south korea” 및 “southkorea”입니다. “국가” 열에서 비율이 47을 초과하는 모든 행을 “south korea”로 바꾸겠습니다.

이를 위해 함수를 작성하겠습니다. (특정 작업을 한두 번 이상 수행해야 할 것 같으면 재사용할 수 있는 범용 함수를 작성하는 것이 좋습니다. 이렇게 하면 코드를 너무 자주 복사하여 붙여넣지 않아도 되므로 시간을 절약하고 실수를 방지할 수 있습니다.)

# function to replace rows in the provided column of the provided dataframe
# that match the provided string above the provided ratio with the provided string
def replace_matches_in_column(df, column, string_to_match, min_ratio = 47):
    # get a list of unique strings
    strings = df[column].unique()
    
    # get the top 10 closest matches to our input string
    matches = fuzzywuzzy.process.extract(string_to_match, strings, 
                                         limit=10, scorer=fuzzywuzzy.fuzz.token_sort_ratio)

    # only get matches with a ratio > 90
    close_matches = [matches[0] for matches in matches if matches[1] >= min_ratio]

    # get the rows of all the close matches in our dataframe
    rows_with_matches = df[column].isin(close_matches)

    # replace all rows with close matches with the input matches 
    df.loc[rows_with_matches, column] = string_to_match
    
    # let us know the function's done
    print("All done!")

이제 함수가 생겼으니 테스트해 볼 수 있습니다!

# use the function we just wrote to replace close matches to "south korea" with "south korea"
replace_matches_in_column(df=professors, column='Country', string_to_match="south korea")

이제 ‘Country’ 열의 고유 값을 다시 한 번 확인하고 ‘south korea’를 올바르게 정리했는지 확인해 보겠습니다.

# get all the unique values in the 'Country' column
countries = professors['Country'].unique()

# sort them alphabetically and then take a closer look
countries.sort()
countries

훌륭합니다! 이제 데이터 프레임에 “south korea”만 남게 되었으며 손으로 아무것도 변경할 필요가 없습니다.

댓글남기기