3

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

数据框为:

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

这些差异意味着什么?

4

2 回答 2

4

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

所以不,它们不相等。当你有一个系列时,你可以随意使用你的功能。当您有一个单列 DataFrame 时,您不能,因为它将列作为其参数传递,并且该列是一个没有upper方法的系列。

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

于 2013-11-05T05:45:44.783 回答
1

正如@BrenBarn 所提到的,不同之处在于,如果df.iloc[:, 1:2]您有一个包含一列的 DataFrame,而如果df.loc[:, 'B']您有一个系列。只需添加一点,要将具有一列的 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
于 2013-11-05T06:39:37.883 回答