在 pandas 中将 lambda 函数应用于列失败

Posted

技术标签:

【中文标题】在 pandas 中将 lambda 函数应用于列失败【英文标题】:Applying a lambda function to a column got failed in pandas 【发布时间】:2013-11-15 22:46:36 【问题描述】:

我不知道为什么索引方法在执行按列应用功能时会出现不一致的行为。

数据框为:

df = pd.DataFrame( [(1, 'Hello'), (2, "World")])
df.columns=['A', 'B']

我想将 lambda 应用到第二列,它说不能应用 Series 对象?

print df.iloc[:, 1:2].apply(lambda x: x.upper()).head()
 **AttributeError**:("'Series' object has no attribute 'upper'", u'occurred at index B')
print df.loc[:, ['B']].apply(lambda x: x.upper()).head()
 **AttributeError**:("'Series' object has no attribute 'upper'", u'occurred at index B')

但是下面的索引方法效果很好。

print df.loc[:, 'B'].apply(lambda x: x.upper()).head()

为什么?我认为这三种索引方法是等价的吗? 以上三种索引方法打印出来的结果几乎是一样的 那就是:

   B
0  Hello
1  World

并打印 df.loc[:, 'B'] 得到

0  Hello
1  World
Name: B, dtype: object

这些差异是什么意思?

【问题讨论】:

【参考方案1】:

正如@BrenBarn 所提到的,不同之处在于df.iloc[:, 1:2] 的DataFrame 是一列,而df.loc[:, 'B'] 的情况是Series。只是一点点补充,要将一列的 DataFrame 转换为系列,您可以使用 pandas.squeeze() 方法:

>>> df.iloc[:, 1:2]
       B
0  Hello
1  World
>>> df.iloc[:, 1:2].squeeze()
0    Hello
1    World
Name: B, dtype: object

然后你可以使用apply(你不必使用lambda,顺便说一句):

>>> df.iloc[:, 1:2].squeeze().apply(str.upper)
0    HELLO
1    WORLD
Name: B, dtype: object

如果要将upper应用于DataFrame,可以使用pandas.applymap():

>>> df.iloc[:, 1:2].applymap(str.upper)
       B
0  HELLO
1  WORLD

【讨论】:

【参考方案2】:

当您使用'B' 编制索引时,您会得到一个系列。当您使用1:2['B'] 进行索引时,您会得到一个包含一列的DataFrame。当您在系列上使用 apply 时,您的函数会在每个元素上调用。当您在 DataFrame 上使用 apply 时,您的函数会在每个 column 上调用。

所以不,它们不相等。当你有一个系列时,你可以随意使用你的功能。当你有一个单列 DataFrame 时,你不能,因为它通过列作为它的参数,而列是一个没有 upper 方法的系列。

您可以看到它们不一样,因为打印出来的结果不同。是的,它们几乎相同,但不一样。第一个有一个列标题,表示它是一个DataFrame;第二个没有列标题,但底部有“名称”,表示它是一个系列。

【讨论】:

以上是关于在 pandas 中将 lambda 函数应用于列失败的主要内容,如果未能解决你的问题,请参考以下文章

在 Pandas 中使用 group by 时如何将“first”和“last”函数应用于列?

重新采样 MultiIndexed Pandas DataFrame 并将不同的函数应用于列

Pandas:将特定功能应用于列并创建其他列

如何将 lambda 函数正确应用到 pandas 数据框列

Pandas:将 Lambda 应用于多个数据帧

使用 Lambda 函数 Pandas 设置列值