Сопоставление тысяч данных занимает слишком много времени при использовании Pandas

Каждый день я получаю отчет с некоторыми значениями, и мне нужно сопоставить почтовые индексы стран по всему миру, чтобы получить правильный регион. Затем я загружаю результат в мое приложение Django. Вот взгляд на мой отчет:

Order Number Date City Postal code
930276 27/09/2022 Madrid cp: 28033
929670 27/09/2022 Lisboa cp: 1600-812

У меня есть тысячи таких строк. Задача состоит в том, чтобы получить регион в формате ISO 3166-2. Чтобы помочь себе, я обратился к следующей странице Geonames и загрузил информацию обо всех странах (пример: "FR.txt", "ES.txt"...). Поскольку это огромный txt файл, я решил хранить его на сервере S3. Вот что я попробовал:

def access_scaleway(region_name, endpoint_url, access_key, secret_key):
    """ Accessing Scaleway Bucket """

    scaleway = boto3.client('s3', region_name=region_name, endpoint_url=endpoint_url, aws_access_key_id=access_key,
                            aws_secret_access_key=secret_key)

    return scaleway

def get_region_code_accessing_scaleway(countries, regions):
    ''' Retrieves the region code from the region name. '''

    list_countries = countries
    list_regions = regions
    list_regions_codes = []
    scaleway_session = access_scaleway(region_name=settings.SCALEWAY_S3_REGION_NAME,
                                       endpoint_url=settings.SCALEWAY_S3_ENDPOINT_URL,
                                       access_key=settings.SCALEWAY_ACCESS_KEY_ID,
                                       secret_key=settings.SCALEWAY_SECRET_ACCESS_KEY)

    for country, region in zip(list_countries, list_regions):
        try:
            obj = scaleway_session.get_object(Bucket=settings.SCALEWAY_STORAGE_BUCKET_NAME, Key=f'countries/{country}.txt')
            df = pd.read_csv(io.BytesIO(obj['Body'].read()), sep='\t', header=None)
            df.columns = ['country code', 'postal code', 'place name', 'admin name1', 'admin code1', 'admin name2', 'admin code2', 'admin name3', 'admin code3', 'latitude', 'longitude', 'accuracy']
            df['postal code'] = df['postal code'].astype(str)
            df['postal code'] = df['postal code'].str.zfill(5)
            # Removing all spaces and special characters
            postal_code = re.sub("[^0-9^-]", '', region).strip()
            region_code = country + "-" + df[df['postal code'] == postal_code]['admin code1'].values[0]
            list_regions_codes.append(region_code)

        except AttributeError:
            list_regions_codes.append(None)
        except ValueError:
            list_regions_codes.append(None)


    return list_regions_codes

Но это слишком долго. Для простого отчета из 1000 строк требуется около 30 минут.

Моя вторая попытка заключалась в использовании публичного API OpenDataSoft. Вот что я попробовал:

def fetch_data(url, params, headers=None):
    response = requests.get(url=url, params=params, headers=headers)
    return response

def get_region_code_accessing_scaleway(countries, regions):
    ''' Retrieves the region code from the region name. '''

    list_countries = countries
    list_regions = regions
    list_regions_codes = []

    for country, region in zip(list_countries, list_regions):
        try:
            #Get response from API
            postal_code = re.sub("[^0-9^-]", '', region).strip()
            response = fetch_data(
                url="https://data.opendatasoft.com/api/v2/catalog/datasets/geonames-postal-code%40public/records?",
                params="select=country_code%2C%20postal_code%2C%20admin_code1&where=country_code%3D%22" + country + "%22%20and%20postal_code%3D%22" + postal_code + "%22")

            if response.status_code == 200:
                data = response.json()
                if len(data['records']) > 0:
                    list_regions_codes.append(country + "-" + data['records'][0]['record']['fields']['admin_code1'])
                else:
                    list_regions_codes.append(None)

            else:
                print('Error:" + response.status_code')
                list_regions_codes.append(None)

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

Order Number Date City Postal code Region code
930276 27/09/2022 Madrid cp: 28033 ES-MD
929670 27/09/2022 Lisboa cp: 1600-812 PT-08

Есть ли у вас идеи, как ускорить процесс?

Вернуться на верх