我不知道为什么索引方法在执行按列应用函数时有不一致的行为。
数据帧为:
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
这些差异意味着什么?
当你用'B'
索引时,你会得到一个系列。当您使用1:2
或['B']
进行索引时,您会得到一个只有一列的DataFrame。当您对一个系列使用应用
时,您的函数将在每个元素上被调用。当您在DataFrame上使用应用
时,您的函数将在每一列上被调用。
所以不,它们是不等价的。当你有一个系列,你可以使用你想要的功能。当您有一列数据帧时,您不能这样做,因为它将该列作为其参数传递,并且该列是一个没有upper
方法的序列。
你可以看到它们不一样,因为打印出来的结果不同。是的,它们几乎一样,但不一样。第一个有一个列标题,表示它是一个数据帧;第二个没有列标题,但底部有“Name”,表示它是一个系列。
正如@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
然后,您可以使用应用(您不必使用lambda
,BTW):
>>> df.iloc[:, 1:2].squeeze().apply(str.upper)
0 HELLO
1 WORLD
Name: B, dtype: object
如果要对数据帧应用upper
,可以使用pandas。applymap():
>>> df.iloc[:, 1:2].applymap(str.upper)
B
0 HELLO
1 WORLD