在不使用索引的情况下替换pandas DataFrame中所选单元格的值

62

这是一个与此问题非常相似的问题,但有一个关键区别:我选择要更改的数据不是通过其索引而是通过一些条件。

如果我应用的条件返回单行数据,则我希望能够以简单的方式设置该行中某个列的值,但我的第一次尝试并没有成功:

>>> d = pd.DataFrame({'year':[2008,2008,2008,2008,2009,2009,2009,2009], 
...                   'flavour':['strawberry','strawberry','banana','banana',
...                   'strawberry','strawberry','banana','banana'],
...                   'day':['sat','sun','sat','sun','sat','sun','sat','sun'],
...                   'sales':[10,12,22,23,11,13,23,24]})

>>> d
   day     flavour  sales  year
0  sat  strawberry     10  2008
1  sun  strawberry     12  2008
2  sat      banana     22  2008
3  sun      banana     23  2008
4  sat  strawberry     11  2009
5  sun  strawberry     13  2009
6  sat      banana     23  2009
7  sun      banana     24  2009

>>> d[d.sales==24]
   day flavour  sales  year
7  sun  banana     24  2009

>>> d[d.sales==24].sales = 100
>>> d
   day     flavour  sales  year
0  sat  strawberry     10  2008
1  sun  strawberry     12  2008
2  sat      banana     22  2008
3  sun      banana     23  2008
4  sat  strawberry     11  2009
5  sun  strawberry     13  2009
6  sat      banana     23  2009
7  sun      banana     24  2009

那么,与其将2009年星期天的香蕉销售额设置为100,不如什么都不做!最好的解决方案是使用行号,因为通常事先不知道行号!

3个回答

92

有许多方法可以做到这一点

1

In [7]: d.sales[d.sales==24] = 100

In [8]: d
Out[8]: 
   day     flavour  sales  year
0  sat  strawberry     10  2008
1  sun  strawberry     12  2008
2  sat      banana     22  2008
3  sun      banana     23  2008
4  sat  strawberry     11  2009
5  sun  strawberry     13  2009
6  sat      banana     23  2009
7  sun      banana    100  2009

2

In [26]: d.loc[d.sales == 12, 'sales'] = 99

In [27]: d
Out[27]: 
   day     flavour  sales  year
0  sat  strawberry     10  2008
1  sun  strawberry     99  2008
2  sat      banana     22  2008
3  sun      banana     23  2008
4  sat  strawberry     11  2009
5  sun  strawberry     13  2009
6  sat      banana     23  2009
7  sun      banana    100  2009

3

In [28]: d.sales = d.sales.replace(23, 24)

In [29]: d
Out[29]: 
   day     flavour  sales  year
0  sat  strawberry     10  2008
1  sun  strawberry     99  2008
2  sat      banana     22  2008
3  sun      banana     24  2008
4  sat  strawberry     11  2009
5  sun  strawberry     13  2009
6  sat      banana     24  2009
7  sun      banana    100  2009

3
是的!解决方案1有效。这种方法有些违反直觉:d.sales[d.sales==24] = 100是可行的,但d[d.sales==24].sales=100却不行。在我看来,它们(在功能上)看起来是相同的。啊,算了。感谢@waitingkuo。 - LondonRob
1
d[d.sales==24] 生成一个新对象。 - waitingkuo
1
关于@waitingkuo的评论:这是期望的行为吗,Pandas开发者们?选择d[d.sales==24]生成原始DataFrame的副本显然不直观。实际上,我认为每个对象都应该是对原始对象的引用(包括选择单个行,正确地“折叠”为Pandas Series),除非用户通过某种方式明确请求(通过copy=True)。你有什么想法? - LondonRob
2
请注意:这些内容现在将在0.13版本中引发/警告,请参见(此处)[http://pandas.pydata.org/pandas-docs/dev/indexing.html#indexing-view-versus-copy)。 - Jeff
有没有不使用 d.sales 的方法?我更喜欢不使用这种语法,因为有时列名中有空格。 - cryanbhu
显示剩余3条评论

15

我不确定pandas的旧版本是否支持,但在0.16版本中,可以基于多个列值设置特定单元格的值。

扩展@waitingkuo提供的答案,也可以基于多个列的值进行相同的操作。

d.loc[(d.day== 'sun') & (d.flavour== 'banana') & (d.year== 2009),'sales'] = 100

7

虽然这个问题比较老,但我很惊讶没有人提到numpy的.where()功能(可以直接从pandas模块调用)。

在这种情况下,代码应为:

d.sales = pd.np.where(d.sales == 24, 100, d.sales)

据我所知,这是跨系列有条件地更改数据的最快方法之一。

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