如何将变量从for循环传递到pandas.df.apply中的kwargs?

时间:2019-04-03 15:39:14

标签: python pandas

我很难使用df.apply将变量传递给参数。我有一个函数,它拆分一个字符串,然后计算有多少子字符串匹配列表中的项目。我将其应用到pandas数据框,使用apply传递要分割的字符串并查找要匹配的列表。如果直接应用虽然可以成功,但如果我尝试在for循环中传递此信息失败,则该方法似乎有效矮人不接受该变量。

这是示例函数

def classification_counter(original, class_lists):
          ...:     count=0
          ...:     for y in original.split():
          ...:         if y in class_lists:
          ...:             count= count+1
          ...:     return count

例如,这是我的列表,其中包含稍后将要查找的关键字:

bikes = ['raleigh', 'trek', 'cannondale']
cars = ['ford', 'bmw', 'vw']

我将遍历的列表:

class_set = ['cars', 'bikes']

这是我的数据框:

In [116]: df
Out[116]: 
   bikes  cars                               texts
0      0     0              I like to drive my bmw
1      0     0        I like to ride my cannondale
2      0     0   I keep my trek on a rack on my vw
0      0     0  my wifes car is a vw mine is a bmw

如果我将Apply应用于一列,它将按预期工作:

In [119]:  df['cars']=df['texts'].apply(classification_counter, class_lists=cars)   

In [121]:  df['bikes']=df['texts'].apply(classification_counter, class_lists=bikes)    

In [122]: df
Out[122]: 
   bikes  cars                               texts
0      0     1              I like to drive my bmw
1      1     0        I like to ride my cannondale
2      1     1   I keep my trek on a rack on my vw
0      0     2  my wifes car is a vw mine is a bmw

但是,如果我尝试遍历列表,则会中断:

In [117]: for x in class_set:
      ...:     df[x]=df['texts'].apply(classification_counter, class_lists=x)
     ...:     

In [118]: df
Out[118]: 
   bikes  cars                               texts
0      0     0              I like to drive my bmw
1      0     0        I like to ride my cannondale
2      0     1   I keep my trek on a rack on my vw
0      0     3  my wifes car is a vw mine is a bmw

我是否缺少有关将变量传递给关键字参数的正确方法的某些信息?

3 个答案:

答案 0 :(得分:3)

您不需要为此编写自己的“复杂”函数。为此,请使用熊猫Series.str.count

for col in class_set:
    df[col] = df.texts.str.count('|'.join(eval(col)))

print(df)
   bikes  cars                               texts
0      0     1              I like to drive my bmw
1      1     0        I like to ride my cannondale
2      1     1   I keep my trek on a rack on my vw
3      0     2  my wifes car is a vw mine is a bmw

要使自己的代码正常工作,请使用以下命令:

for x in class_set:
    df[x]=df['texts'].apply(classification_counter, class_lists=eval(x))

但是在熊猫中,您总是想使用向量化解决方案,因为与自己定义的函数和for循环相比,它可以大大提高代码的速度。

编辑以获取解释
我们使用'|'.join来创建列表的字符串表示形式:

bikes = ['raleigh', 'trek', 'cannondale']

print('|'.join(bikes))
raleigh|trek|cannondale

我们使用eval,因为您不能将变量作为字符串调用,因此我们必须使用eval,因为您的class_set列出了字符串后缀。但是我们要调用列表bikescar而不是字符串。

text = 'hello'

x = 'text'

print(eval(x))
hello

答案 1 :(得分:1)

如果这是您需要的,则无需构建自己的函数,请查看get_dummies

bikesdict=dict.fromkeys(bikes,'bikes')
carsdict=dict.fromkeys(cars,'cars')
d={}
d.update(bikesdict)
d.update(carsdict)
df.texts.str.get_dummies(' ').groupby(by=d,axis=1).sum()
Out[344]: 
   bikes  cars
0      0     1
1      1     0
2      1     1
3      0     2

答案 2 :(得分:1)

我认为您的问题是您的for循环中的x是一个字符串。当您确实分别申请每列时,您将列表carsbikes作为关键字class_lists进行了传递。但是,在for循环中,您将字符串'cars''bikes'作为关键字class_lists传递。

如果您制作了一个类的字典,它将起作用。也就是说,

class_dict = {'cars':['ford', 'bmw', 'vw'], 
             'bikes':['raleigh', 'trek', 'cannondale']}

,并将for循环更改为:

>>> for k, v in class_dict.items():
...     df[k]=df['texts'].apply(classification_counter, class_lists=v)

>>> df

   bikes  cars                               texts
0      0     1              I like to drive my bmw
1      1     0        I like to ride my cannondale
2      1     1   I keep my trek on a rack on my vw
3      0     2  my wifes car is a vw mine is a bmw