根据另一列的值替换列值

8

到目前为止,我的数据框看起来像这样:

ID   Area   Stage
1    P      X
2    Q      X
3    P      X
4    Q      Y

我想在阶段等于'X'的每一行中,将区域'Q'替换为'P'。
结果应该是这样的:
ID   Area   Stage
1    P      X
2    P      X
3    P      X
4    Q      Y

我尝试过:
data.query('Stage in ["X"]')['Area']=data.query('Stage in ["X"]')['Area'].replace('Q','P')

它不能工作。需要帮助!:)


你是否正在寻找一种更动态的答案,它可以检查Area和Stage中的值,然后将Area中的所有值替换为Stage中出现最多的值?我的最初反应是只用P替换Q。但是,我认为您的请求更通用,而不是特定于某个值。您能否澄清一下。 - Joe Ferndz
我的问题涉及到一个特定的值。Quang Hoang的答案做到了我想要的 :) - Michelle
Michelle,我认为@JoeFerndz要求您澄清Area是否只能取值P或Q,因为他和RavinderSingh13在他们的答案中做出了这个假设。 - bruno
啊,好的。实际上,在X阶段,Area只取值P和Q。一般来说,还有其他的Areas。 - Michelle
5个回答

4

您可以使用2个布尔条件并使用loc

df.loc[df['Area'].eq("Q") & df['Stage'].eq('X'),'Area']='P'
print(df)

   ID Area Stage
0   1    P     X
1   2    P     X
2   3    P     X
3   4    Q     Y

或者np.where

df['Area'] = np.where(df['Area'].eq("Q") & df['Stage'].eq('X'),'P',df['Area'])

2
@RavinderSingh13 谢谢,我认为应该添加另一个条件,因为 Stage==XArea==Z 可能也会被替换为 P :-) - anky
1
是的,但我不确定我是否通过保留OP的问题摘要来使它简单 :) OP可以确认一切,祝好 :) - RavinderSingh13

4

请您尝试以下步骤。

import pandas as pd
import numpy as np
df['Area']=np.where(df['Stage']=='X','P',df['Area'])

3
你可以使用loc来指定你想要替换的位置,并将替换后的序列传递给赋值操作:
df.loc[df['Stage']=='X', 'Area'] = df['Area'].replace('Q','P')

输出:

   ID Area Stage
0   1    P     X
1   2    P     X
2   3    P     X
3   4    Q     Y

3

注意:这不是提出一种新方法的答案,而是比较每种方法所需的执行时间

所有回答中的提议都相当“神奇”,都可以通过pandas/numpy的一行代码完成工作。无论如何,能够完成任务就是好的,但能够快速完成就更好了,因此我想比较每种方法的执行时间。

这是我的程序,在循环中,我修改数据框两次,以保持从一个回合到下一个回合不变(如果做法有问题,我不是你们Python程序员,所以提前抱歉):

import pandas as pd
import numpy as np
import time

df=pd.DataFrame({'ID' : [i for i in range(1,1000)],
                 'Area' : ['P' if (i & 1) else 'Q' for i in range(1,1000)],
                 'Stage' : [ 'X' if (i & 2) else 'Y' for i in range(1,1000)]})

t0=time.process_time()
for i in range(1,100):
    df.loc[df['Stage']=='X', 'Area'] = df['Area'].replace('Q','q')
    df.loc[df['Stage']=='X', 'Area'] = df['Area'].replace('q','Q')

print("Quang Hoang", '%.2f' % (time.process_time() - t0))

t0=time.process_time()
for i in range(1,100):
    df.loc[df['Stage'] == 'X', 'Area'] = 'q'
    df.loc[df['Stage'] == 'X', 'Area'] = 'Q'

print("Joe Ferndz", '%.2f' % (time.process_time() - t0))

t0=time.process_time()
for i in range(1,100):
    df.loc[df['Area'].eq("Q") & df['Stage'].eq('X'),'Area']='q'
    df.loc[df['Area'].eq("q") & df['Stage'].eq('X'),'Area']='Q'

print("anky 1", '%.2f' % (time.process_time() - t0))

t0=time.process_time()
for i in range(1,100):
    df['Area'] = np.where(df['Area'].eq("Q") & df['Stage'].eq('X'),'q',df['Area'])
    df['Area'] = np.where(df['Area'].eq("q") & df['Stage'].eq('X'),'Q',df['Area'])

print("anky 2", '%.2f' % (time.process_time() - t0))

t0=time.process_time()
for i in range(1,100):
    df['Area']=np.where(df['Stage']=='X','q',df['Area'])
    df['Area']=np.where(df['Stage']=='X','Q',df['Area'])

print("RavinderSingh13", '%.2f' % (time.process_time() - t0))

在我的树莓派4上,结果是:
Quang Hoang 1.60
Joe Ferndz 1.12
anky 1 1.55
anky 2 0.86
RavinderSingh13 0.38

如果我使用的数据框有10万行而不是1000行,结果会是:

Quang Hoang 10.79
Joe Ferndz 6.61
anky 1 10.91
anky 2 9.64
RavinderSingh13 4.75

请注意,Joe Ferndz和RavinderSingh13的提案假设Area仅为“P”或“Q”。

3
太棒了!这清楚地表明在这种情况下numpy是最佳选择。我原以为.loc也很好,但numpy胜出了。 - Joe Ferndz

1

要使用另一列的值更新列,请使用此选项:

df.loc[df['Stage'] == 'X', 'Area'] = 'P'

这将检查'Stage'的值是否为X。如果为True,则将'Area'的值替换为'P'

1
当。是的。抱歉,没有意识到多余的等号。 - Joe Ferndz

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