Записать все данные из одного CSV-файла в другой, но включить новые проанализированные данные геокодирования в качестве дополнительных полей - PullRequest
0 голосов
/ 24 мая 2018

Я пытаюсь написать скрипт Python, который будет принимать любой CSV-файл, запускать его через геокодер, а затем записывать полученные атрибуты геокодирования (+ все данные из исходного файла) в новый CSV-файл.

На данный момент мой код следующий, и я должен отметить, что все работает должным образом, за исключением объединения атрибутов геокодирования с данными в необработанном CSV-файле.В настоящее время происходит то, что все значения полей исходного файла CSV для конкретной строки представлены как одно значение в файле CSV (хотя атрибуты геокодирования отображаются правильно).Проблема со скриптом находится ближе к концу.Я упустил код для различных классов для краткости.

Я должен также отметить, что я использую hasattr *, потому что хотя я не знаю, какие поля находятся в исходном файле in_file, я знаю, что где-то ввходной CSV эти поля будут присутствовать, и это поля, необходимые для геокодирования.

Первоначально я попытался изменить "new_file.writerow ([])" на "new_file.writerow ()", на этом этапестрока ввода -r- правильно записала файл CSV, но атрибуты геокодирования больше не могли быть записаны в CSV, поскольку они рассматривались как дополнительные аргументы.

def locate(file=None):
""" locate by geocoding func"""
start_time = time.time()
count = 0

if file != None:

    with open (file) as in_file:
        f_csv = csv.reader(in_file)

        # regex headers and lowercase to standarize for hasattr func.
        headers = [ re.sub('["\s+]', '_', h).lower() for h in next(f_csv)]

        # Used namedtuple for headers
        Row = namedtuple('Row', headers)

        # for row in file
        for r in f_csv:
            count += 1
            # set row values to named tuple values
            row = Row(*r)

            # Try hasattr to find fields names address, city, state, zipcode
            if hasattr(row, 'address'):
                address = row.address
            elif hasattr(row, 'address1'):
                address = row.address1
            if hasattr(row, 'city'):
                city = row.city
            if hasattr(row, 'state'):
                state = row.state
            elif hasattr(row, 'st'):
                state = row.st
            if hasattr(row, 'zipcode'):
                zipCode = row.zipcode
            elif hasattr(row, 'zip'):
                zipCode = row.zipcode

            # Create new address object
            addressObject = Address(address, city, state, zipCode)

            # Get response from api
            data = requests.get(addressObject.__str__()).json()

            try:
                data['geocodeStatusCode'] = int(data['geocodeStatusCode'])
            except:
                data['geocodeStatusCode'] =  None

            if data['geocodeStatusCode'] == 'SomeNumber':

                # geocoded address ideally uses parent class attributes
                geocodedAddressObject =  GeocodedAddress(addressObject.address, addressObject.city, addressObject.state, addressObject.zipCode, data['addressGeo']['latitude'], data['addressGeo']['longitude'], data['addressGeo']['score'])              


            else:

                geocodedAddressObject =  GeocodedAddress(addressObject.address, addressObject.city, addressObject.state, addressObject.zipCode)

            # Problem Area
            geocoded_file = file.replace('.csv', '_geocoded2') + '.csv'
            with open(geocoded_file, 'a', newline='') as geocoded:

                # Problem area -- the r -row- attribute writes all within the same cell even though they are comma separated. The geocoding attributes do write correctly to the csv file 
                new_file = csv.writer(geocoded)
                new_file.writerow([r, geocodedAddressObject.latitude, geocodedAddressObject.longitude, geocodedAddressObject.geocodeScore])

print('The time to geocode {} records: {}'.format(count, (time.time() - start_time)))

Пример входных данных CSV:

"UID", "Occupant", "Address", "City", "State", "ZipCode"
"100001", "Playstation Theater", "New York", "NY", "10036"
"100002", "Ed Sullivan Theater", "New York, "NY", "10019"

Пример вывода CSV (дополнительные поля анализируются во время геокодирования)

"UID", "Occupant", "Address", "City", "State", "ZipCode", "GeoCodingLatitude", "GeoCodingLongitude", "GeoCodingScore"
"100001", "Playstation Theater", "New York", "NY", "10036", "45.1234", "-110.4567", "100"
"100002", "Ed Sullivan Theater", "New York, "NY", "10019", "44.1234", "-111.4567", "100"

1 Ответ

0 голосов
/ 29 мая 2018

Я разобрался с решением, хотя оно, вероятно, не самое элегантное.Я преобразовал namedtuple в словарь, используя namedtuple._asdict (), а затем перебрал значения строки, добавив их в новый список.На этом этапе я добавляю геокодированные переменные, а затем записываю весь список в строку.Вот пример кода, который я изменил!Если вы можете найти лучшее решение, пожалуйста, дайте мне знать.

                    if data['geocodeStatusCode'] == 'SomeNumber':

                        # geocoded address ideally should use parent class address values and not have to be restated 
                        geocodedAddressObject =  GeocodedAddress(addressObject.address, addressObject.city, addressObject.state, addressObject.zipCode,
                                                                data['addressGeo']['latitude'], data['addressGeo']['longitude'], data['addressGeo']['score'])              


                    else:

                        geocodedAddressObject =  GeocodedAddress(addressObject.address, addressObject.city, addressObject.state, addressObject.zipCode)              


                    # This is where I made the change - set new list
                    list_values = []    

                    # Use _asdict for the named tuple
                    row_content = row._asdict()

                    # Loop through and strip white space
                    for key, value in row_content.items():
                        # print(key, value.strip())
                        list_values.append(value.strip())

                    # Extend list rather then append due to multiple values
                    list_values.extend((geocodedAddressObject.latitude, geocodedAddressObject.longitude, geocodedAddressObject.geocodeScore))

                    # Finally write the new list to the csv file - which includes both the row and the geocoded objects 
                    #- and is agnostic as to what data it's passed as long as its utf-8 complaint
                    new_file.writerow(list_values)
...