Как реализовать этот случай с помощью функции apply в пандах? - PullRequest
0 голосов
/ 26 сентября 2018

У меня есть следующий код для получения информации об IP:

import requests
import json
import pandas as pd
import swifter  

def get_ip(ip):
    response = requests.get ("http://ip-api.com/json/" + ip.rstrip())
    geo = response.json()
    location = {'lat': geo.get('lat', ''),
                'lon': geo.get('lon', ''),
                'region': geo.get('regionName', ''),
                'city': geo.get('city', ''),
                'org': geo.get('org', ''),
                'country': geo.get('countryCode', ''),
                'query': geo.get('query', '')
                }
    return(location)

Для применения его ко всему фрейму данных IP (df) я использую следующее:

df=pd.DataFrame(['85.56.19.4','188.85.165.103','81.61.223.131'])

for lab,row in df.iterrows():
    dip = get_ip(df.iloc[lab][0])
    try:
        ip.append(dip["query"])
        private.append('no')
        country.append(dip["country"])
        city.append(dip["city"])
        region.append(dip["region"])
        organization.append(dip["org"])
        latitude.append(dip["lat"])
        longitude.append(dip["lon"])
    except:
        ip.append(df.iloc[lab][0])
        private.append("yes")

ОднакоТак как iterrows очень медленные и мне нужно больше производительности, я хочу использовать swiftapply, который является расширением функции apply.Я использовал это:

def ip(x):
    dip = get_ip(x)
    if (dip['ip']=='private')==True:
        ip.append(x)
        private.append("yes")
    else:
        ip.append(dip["ip"])
        private.append('no')
        country.append(dip["country"])
        city.append(dip["city"])
        region.append(dip["region"])
        organization.append(dip["org"])
        latitude.append(dip["lat"])
        longitude.append(dip["lon"])

df.swifter.apply(ip)

И я получаю следующую ошибку: AttributeError: («Объект« Series »не имеет атрибута« rstrip »,« произошел с индексом 0 »)

Как я мог это исправить?

1 Ответ

0 голосов
/ 26 сентября 2018

rstrip - строковая операция.Чтобы применить строковую операцию к серии Series, сначала необходимо вызвать функцию str для серии, которая позволяет выполнять векторизованные строковые операции с Series.

В частности, вваш код, изменяющий ip.rstrip() на ip.str.rstrip(), должен разрешить ваш AttributeError.

. Немного покопавшись, получается, что requests.get операция, которую вы пытаетесь выполнить, не может быть векторизована в pandas (см. Использование запросов Python для нескольких URL-адресов в кадре данных ).Я взломал следующее, что должно быть немного более эффективным, чем использование iterrowsДалее используется np.vectorize для запуска функции для получения информации для каждого IP-адреса.Входные данные о местоположении сохраняются как новые столбцы в новом DataFrame.

Сначала я изменил вашу функцию get_ip, чтобы она возвращала словарь location, а не (location).

Далее ясоздал функцию векторизации, используя np.vectorize:

vec_func = np.vectorize(lambda url: get_ip(url))

Наконец, vec_func применяется к df, чтобы создать новый DataFrame, который объединяет df с выводом местоположения из vec_func, где df[0] это столбец с вашими URL:

new_df = pd.concat([df, pd.DataFrame(vec_func(df[0]), columns=["response"])["response"].apply(pd.Series)], axis=1)

Приведенный выше код извлекает ответ API в виде словаря для каждой строки в вашем DataFrame, а затем отображает словарь в столбцы в DataFrame.В конце ваш новый DataFrame будет выглядеть так:

                0      lat     lon     region      city             org country           query
0      85.56.19.4  37.3824 -5.9761  Andalusia   Seville   Orange Espana      ES      85.56.19.4
1  188.85.165.103  41.6561 -0.8773     Aragon  Zaragoza  Vodafone Spain      ES  188.85.165.103
2   81.61.223.131  40.3272 -3.7635     Madrid   Leganés    Vodafone Ono      ES   81.61.223.131

Надеюсь, это устранит ошибку InvalidSchema и даст вам немного лучшую производительность, чем iterrows().

...