Ошибка типа: объект «Zipcode» не может быть подписан - PullRequest
0 голосов
/ 06 марта 2019

Я использую Python3 и у меня есть pandas df, который выглядит как

    zip
0   07105
1   00000
2   07030
3   07032
4   07032

Я хотел бы добавить штат и город, используя пакет uszipcode, который я использую

import uszipcode
search = SearchEngine(simple_zipcode=False)
def zco(x):
    print(search.by_zipcode(x)['City'])

df['City'] = df[['zip']].fillna(0).astype(int).apply(zco)

Однако я получаю следующую ошибку

TypeError: 'Zipcode' object is not subscriptable

Может кто-нибудь помочь с ошибкой?

1 Ответ

0 голосов
/ 06 марта 2019

Вызов search.by_zipcode(x) возвращает ZipCode() экземпляр , а не словарь, поэтому применение ['City'] к этому объекту завершается неудачей.

Вместо этого используйте атрибут .major_city с более коротким псевдонимом, атрибут .city ; Вы хотите вернуть это значение, а не распечатать его:

def zco(x):
    return search.by_zipcode(x).city

Если все, что вы собираетесь использовать для проекта uszipcode, - это сопоставление почтовых индексов с названиями штатов и городов, вам не нужно использовать полную базу данных (загрузка 450 МБ). Просто придерживайтесь «простой» версии, которая составляет всего 9 МБ, оставив аргумент simple_zipcode=False в SearchEngine().

Далее, это будет действительно очень медленно . .apply() использует простой цикл под капотом, и для каждой строки метод .by_zipcode() будет запрашивать базу данных SQLite с помощью SQLAlchemy, создавать один объект результата со всеми столбцами из соответствующей строки, а затем возвращать этот объект, просто чтобы вы может получить от них один атрибут.

Вы бы лучше обращались к базе данных напрямую, используя методы Pandas SQL . Пакет uszipcode все еще полезен здесь, так как он обрабатывает загрузку базы данных для вас и создание сеанса SQLAlchemy, атрибут SearchEngine.ses дает вам прямой доступ к нему, но оттуда я бы просто сделал:

from uszipcode import SearchEngine, SimpleZipcode

search = SearchEngine()
query = (
    search.ses.query(
        SimpleZipcode.zipcode.label('zip'),
        SimpleZipcode.major_city.label('city'),
        SimpleZipcode.state.label('state'),
    ).filter(
        SimpleZipcode.zipcode.in_(df['zip'].dropna().unique())
    )
).selectable
zipcode_df = pd.read_sql_query(query, search.ses.connection(), index_col='zip')

чтобы создать Dataframe Pandas со всеми вашими уникальными почтовыми индексами, сопоставленными со столбцами города и штата. Затем вы можете присоединить ваш фрейм данных к фрейму данных почтового индекса :

df = pd.merge(df, zipcode_df, how='left', left_on='zip', right_index=True)

Это добавляет столбцы city и state к исходному кадру данных. Если вам нужно добавить больше столбцов, добавьте их в часть search.ses.query(...), используя .label(), чтобы дать им подходящее имя столбца в выходном фрейме данных (без .label(), они получат префикс simple_zipcode_ или zipcode_, в зависимости от класса, который вы используете). Выберите из атрибутов модели, задокументированных , но учтите, что если вам нужен доступ к full Zipcode атрибутам модели , вам нужно использовать SearchEngine(simple_zipcode=False), чтобы получить полные 450 МБ набор данных в вашем распоряжении, затем используйте Zipcode.<column>.label(...) вместо SimpleZipcode.<column>.label(...) в запросе.

С почтовыми индексами в качестве индекса в кадре данных zipcode_df это будет намного быстрее ( zippier :-)), чем использование SQLAlchemy для каждой строки в отдельности.

...