如何在熊猫中使用apply函数实现这种迭代情况?

时间:2018-09-26 14:06:30

标签: python pandas loops apply swifter

我有以下代码用于获取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")

但是,由于迭代非常缓慢并且我需要更高的性能,因此我想使用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 :(“系列”对象没有属性“ rstrip”,“出现在索引0”)

我该如何解决?

1 个答案:

答案 0 :(得分:1)

rstrip是字符串操作。为了将字符串操作应用于序列Series,您必须首先调用序列上的str函数,该函数允许在Series上执行向量化的字符串操作。

具体来说,在您的代码中,将ip.rstrip()更改为ip.str.rstrip()应该可以解决您的AttributeError

经过一番挖掘,发现您尝试执行的requests.get操作无法在pandas中进行向量化(请参见Using Python Requests for several URLS in a dataframe)。我修改了以下内容,该内容应该比使用iterrows更有效率。以下内容是利用np.vectorize运行该函数来获取每个IP地址的信息。位置输入将另存为新的DataFrame中的新列。

首先,我更改了get_ip函数以返回location字典,而不是(location)

接下来,我使用np.vectorize创建了矢量化函数:

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

最后,将vec_func应用于df以创建一个新的DataFrame,该数据帧将dfvec_func输出的位置合并,其中df[0]是具有以下内容的列您的网址:

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

上面的代码以字典的形式检索DataFrame中每一行的API响应,然后将字典映射到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()好。