Pandas: 如何将函数应用于不同的列

3

假设这是我的函数:

def function(x):
    return x.str.lower()

这是我的数据框(df)

   A         B     C       D 
0  1.67430   BAR  0.34380  FOO 
1  2.16323   FOO -2.04643  BAR
2  0.19911   BAR -0.45805  FOO
3  0.91864   BAR -0.00718  BAR
4  1.33683   FOO  0.53429  FOO
5  0.97684   BAR -0.77363  BAR

我想将这个函数应用于列BD。 (将其应用于整个数据帧不是答案,因为这会在数字列中产生NaN值)。
我的基本想法是:df.apply(function, axis=1) 但我无法理解如何选择不同的列以应用该函数。 我已经尝试了各种按数值位置,名称等进行索引的方法。
我花了很多时间阅读相关内容。 这不是以下任何一个的直接重复: 如何将函数应用于Pandas数据框的两个列 Pandas:如何将apply函数应用于多个列 Pandas:将不同的函数应用于不同的列 Python Pandas:使用“apply”将1个函数应用于多个列

尽可能避免使用apply。如果你不确定是否需要使用它,那么你可能不需要。我建议看一下《何时应该在代码中使用pandas apply()函数?》 - cs95
4个回答

9

只需从df中选择列,通过忽略axis参数,我们是按列而不是按行进行操作,这将显着提高效率,因为这里有更多的行而不是列:

df[['B','D']].apply(function)

这将对每一列运行您的函数。
In [186]:
df[['B','D']].apply(function)

Out[186]:
     B    D
0  bar  foo
1  foo  bar
2  bar  foo
3  bar  bar
4  foo  foo
5  bar  bar

你也可以过滤 df 以仅获取字符串 dtype 列:

In [189]:
df.select_dtypes(include=['object']).apply(function)

Out[189]:
     B    D
0  bar  foo
1  foo  bar
2  bar  foo
3  bar  bar
4  foo  foo
5  bar  bar

时间

按列还是按行:

In [194]:    
%timeit df.select_dtypes(include=['object']).apply(function, axis=1)
%timeit df.select_dtypes(include=['object']).apply(function)

100 loops, best of 3: 3.42 ms per loop
100 loops, best of 3: 2.37 ms per loop

但是对于更大的行向数据框,第一种方法会更好地扩展。


1
这太棒了。理想情况下,我希望可以“就地”完成而不用子集。现在使用您的答案很简单:df [['B','D']] = df [['B','D']] .apply(function) - RDJ

3

逐列应用函数以进行原地编辑:

In [194]: df = pd.DataFrame({"A": ["FOO","BAAR","FOO"], "B": ["FOO","BAR" , "FOO"]})

In [195]: df.loc[:,["A","B"]].apply(lambda col : col.str.lower(), axis = 0) # axis= 0, Default in pandas 
Out[195]: 
      A    B
0   foo  foo
1  baar  bar
2   foo  foo

逐行应用函数以进行必要的原地编辑:

In [201]: df.loc[:,["A","B"]].apply(lambda row : row.str.lower(), axis = 1)
Out[201]: 
      A    B
0   foo  foo
1  baar  bar
2   foo  foo

使用按列和按行应用函数的其他有用操作:

# For column-wise operation using apply function:
In [224]: df = pd.DataFrame({"A": ["FOO","BAAR","FOO"], "B": ["FOO","BAR" , "FOO"]})

In [225]: df.loc[:,["A","B"]].apply(lambda col : col.str.lower() + "_" + "cool" + "_" + df["B"])
Out[225]: 
               A             B
0   foo_cool_FOO  foo_cool_FOO
1  baar_cool_BAR  bar_cool_BAR
2   foo_cool_FOO  foo_cool_FOO

#Note only second element from each column is taken as an argument for lambda function, so NaN for others:
In [226]: df.loc[:,["A","B"]].apply(lambda col : col[1:2].str.lower() + "_"+ "cool" + "_" + df["B"])
Out[226]: 
               A             B
0            NaN           NaN
1  baar_cool_BAR  bar_cool_BAR
2            NaN           NaN


#For Row-wise operation (row[0] & row[1] points to first and second element of each row, 
#or can be called as row["A"] $ row["B"] respectively ):
In [207]: df.loc[:,["A","B"]].apply(lambda row : row["B"].lower() + "_" + row["A"].lower() , axis = 1)
Out[207]: 
0     foo_foo
1    bar_baar
2     foo_foo
dtype: object

In [208]: df.loc[:,["A","B"]].apply(lambda row : row[1].lower() + "_" + row[0].lower() , axis = 1)
Out[208]: 
0     foo_foo
1    bar_baar
2     foo_foo
dtype: object

#Here, row[1] indicates second element of each row, i.e row["B"] :
In [235]: df.loc[:,["A","B"]].apply(lambda row : row.str.lower() + "_"+ row[1], axis = 1)
Out[235]: 
          A        B
0   foo_FOO  foo_FOO
1  baar_BAR  bar_BAR
2   foo_FOO  foo_FOO

3

apply方法不是就地(inplace)操作,它返回一个新的数据框(dataframe),所以问题是能否一次性返回完整的数据框。
可以做到,但这很丑陋(可能会稍微快一点):

df.apply(lambda x: x.str.lower() if x.name in ['B', 'D'] else x)

如果您希望对所有字符串列进行操作,可以检查数据类型。


好的信息。对于我的实际数据,我正在对列应用7种不同的“str”方法,因此最好使用函数。不过以后会记住这一点。 - RDJ
1
你可以使用function(x)来代替x.str.lower() - AChampion

2
清晰简洁的语法,可以原地编辑原始列:
df[["A", "B"]] = df[["A","B"]].apply(lambda x: x.str.lower())

此外,要向原始数据框中添加新列:
df[["new_col1", "new_col2"]] = df[["A","B"]].apply(lambda x: x.str.lower())

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接