# Python으로 CSV 파일에서 국가 데이터를 불러와서 객체로 관리하기

Yeeun·2025년 4월 25일

Python

목록 보기
17/31

이번 포스트에서는 Python의 csv 모듈과 dataclass를 사용하여 CSV 파일에서 국가 데이터를 불러와 Country 객체로 관리하는 방법을 다룰 것입니다. 하지만 진행하면서 몇 가지 실수와 오류를 만나게 되었고, 그에 대한 해결 과정도 함께 공유하려고 합니다.

프로젝트 목표

CSV 파일에서 국가 정보(예: GDP, 생명 기대치, 밀도, 위도, 경도 등)를 읽어 Country 객체를 만들고, 이를 관리하는 클래스를 구현하는 것이 목표였습니다.

1. 데이터 구조 설계

먼저, 국가의 정보를 담을 Country 클래스를 만들었습니다. 이 클래스는 국가의 이름, GDP, 생명 기대치, 밀도, 위도, 경도를 저장합니다. Python의 dataclass를 사용하여 간편하게 데이터를 저장할 수 있도록 했습니다.

from dataclasses import dataclass

@dataclass
class Country:
    name: str
    gdp: float
    life_expectancy: float
    density: float
    lat: float
    lon: float

2. 데이터 클린징 및 숫자 변환

CSV에서 가져오는 데이터에는 불필요한 기호가 포함되어 있을 수 있습니다. 예를 들어, GDP 값에는 쉼표(,)나 달러 기호($)가 포함될 수 있습니다. 이를 처리하기 위해 __clean_numeric_data라는 메서드를 만들었습니다.

def __clean_numeric_data(self, value: str) -> float:
    try:
        cleaned = value.strip().replace(',', '').replace('$', '').replace('%', '')
        if cleaned == '':
            return 0.0
        return float(cleaned)
    except (ValueError, AttributeError):
        return 0.0

이 함수는 데이터를 클린징한 후 숫자로 변환합니다. 데이터에 오류가 있을 경우, 0.0을 반환하여 예외를 처리합니다.

3. CSV 파일 로딩 및 데이터 객체화

CountryStastic 클래스에서는 __load_data 메서드를 사용하여 CSV 파일을 읽고, 각 행을 Country 객체로 변환하여 리스트에 추가합니다. CSV 파일에서 각 국가의 정보가 잘 들어오도록 하였습니다.

import csv

class CountryStastic:
    def __init__(self):
        self.countries = []

    def __clean_numeric_data(self, value: str) -> float:
        # 위에서 정의한 __clean_numeric_data 함수

    def __load_data(self, filename: str):
        with open(filename, 'r', encoding='utf-8') as f:
            reader = csv.DictReader(f)
            header_row = next(reader)

            for line in reader:
                try:
                    gdp = self.__clean_numeric_data(line['GDP'])
                    life_expectancy = self.__clean_numeric_data(line['Life expectancy'])
                    density = self.__clean_numeric_data(line['Density (P/Km2)'])
                    lat = self.__clean_numeric_data(line['Latitude'])
                    lon = self.__clean_numeric_data(line['Longitude'])
                except Exception as e:
                    print(e, line)
                else:
                    country = Country(line['Country'], gdp, life_expectancy, density, lat, lon)
                    self.countries.append(country)

여기서 중요한 점은, 각 국가의 데이터를 Country 객체로 변환할 때 모든 필드가 필요하다는 점입니다. 특히 GDP 외에도 생명 기대치, 밀도, 위도, 경도를 포함해야 했습니다.


4. 실수 1: 생성자에서 매개변수 누락

처음에 Country 객체를 만들 때, 생성자에 namegdp만 넣고 나머지 값들을 빼먹는 실수를 했습니다. Country 클래스의 생성자는 name, gdp, life_expectancy, density, lat, lon을 모두 필요로 하기 때문에, 이를 제대로 전달하지 않으면 TypeError가 발생합니다.

에러 메시지:

TypeError: __init__() missing 4 required positional arguments: 'life_expectancy', 'density', 'lat', and 'lon'

해결 방법:

Country 객체를 생성할 때, 모든 필드를 제공해야 한다는 점을 놓친 것을 깨닫고, life_expectancy, density, lat, lon 값을 추가해주었습니다.

country = Country(line['Country'], gdp, life_expectancy, density, lat, lon)

5. 실수 2: 메서드 호출 시 self 누락

__load_data 메서드에서 __clean_numeric_data 메서드를 호출할 때 self를 누락하는 실수가 있었습니다. self.__clean_numeric_data로 호출해야 하는데, __clean_numeric_data만 호출하였기 때문에 NameError가 발생했습니다.

에러 메시지:

NameError: name '__clean_numeric_data' is not defined

해결 방법:

__clean_numeric_data를 클래스 내부의 메서드로 사용하려면 반드시 self를 붙여야 한다는 점을 확인하고, 이를 수정했습니다.

gdp = self.__clean_numeric_data(line['GDP'])

6. 실수 3: 변수명 오타 (lambda)

top_5_dap 메서드를 작성할 때, lambda 함수의 이름을 lamda로 잘못 작성하는 실수가 있었습니다. 이는 Python에서 lambda 키워드가 잘못 사용된 예입니다.

에러 메시지:

NameError: name 'lamda' is not defined

해결 방법:

lambda로 수정하여 정상적으로 작동하도록 했습니다.

return sorted(self.countries, key=lambda x: x.gdp, reverse=True)[:5]

전체 코드

import csv
from dataclasses import dataclass

@dataclass
class Country:
    name: str
    gdp: float
    life_expectancy: float
    density: float
    lat: float
    lon: float

class CountryStastic:
    def __init__(self):
        self.countries = []

    def __clean_numeric_data(self, value: str) -> float:
        try:
            cleaned = value.strip().replace(',', '').replace('$', '').replace('%', '')
            if cleaned == '':
                return 0.0
            return float(cleaned)
        except (ValueError, AttributeError):
            return 0.0

    def __load_data(self, filename: str):
        with open(filename, 'r', encoding='utf-8') as f:
            reader = csv.DictReader(f)
            header_row = next(reader)

            for line in reader:
                try:
                    gdp = self.__clean_numeric_data(line['GDP'])
                    life_expectancy = self.__clean_numeric_data(line['Life expectancy'])
                    density = self.__clean_numeric_data(line['Density (P/Km2)'])
                    lat = self.__clean_numeric_data(line['Latitude'])
                    lon = self.__clean_numeric_data(line['Longitude'])
                except Exception as e:
                    print(e, line)
                else:
                    country = Country(line['Country'], gdp, life_expectancy, density, lat, lon)
                    self.countries.append(country)

    def top_5_dap(self):
        return sorted(self.countries, key=lambda x: x.gdp, reverse=True)[:5]

# 사용 예시
c = CountryStastic()
c.__load_data('world-data-2023.csv')
print(c.top_5_dap())

결론

이 포스트에서는 CSV 파일에서 국가 정보를 불러오고, 이를 Python 클래스 객체로 관리하는 방법을 소개했습니다. 또한, 코드에서 발생한 여러 실수들을 해결하는 과정을 자세히 다뤘습니다. 처음에는 매개변수 누락, 메서드 호출 오류, 오타 등 여러 가지 문제들이 있었지만, 이를 해결하면서 코드의 안정성을 높일 수 있었습니다.

다음 단계로는 plotly를 사용하여 데이터를 시각화하거나, 데이터를 분석하는 기능을 추가할 수 있습니다.

0개의 댓글