设置python中切片中第一项的值

设置python中切片中第一项的值,python,pandas,slice,mask,argmax,Python,Pandas,Slice,Mask,Argmax,因此,我想创建一个数据帧片段,然后设置该片段中第一个项目的值,而不复制数据帧。例如: df = pandas.DataFrame(numpy.random.rand(3,1)) df[df[0]>0][0] = 0 这里的切片是不相关的,仅用于示例,它将再次返回整个数据帧。重点是,通过像示例中那样操作,您可以获得一个带有复制警告的设置(可以理解)。我还尝试过先进行切片,然后使用ILOC/IX/LOC,再使用ILOC两次,例如: df.iloc[df[0]>0,:][0] = 0 d

因此,我想创建一个数据帧片段,然后设置该片段中第一个项目的值,而不复制数据帧。例如:

df = pandas.DataFrame(numpy.random.rand(3,1))
df[df[0]>0][0] = 0
这里的切片是不相关的,仅用于示例,它将再次返回整个数据帧。重点是,通过像示例中那样操作,您可以获得一个带有复制警告的设置(可以理解)。我还尝试过先进行切片,然后使用ILOC/IX/LOC,再使用ILOC两次,例如:

df.iloc[df[0]>0,:][0] = 0
df[df[0]>0,:].iloc[0] = 0
这两种方法都不管用。再一次-我不想复制数据帧,即使它只是切片版本

编辑: 似乎有两种方法,使用掩码或IdxMax。如果索引是唯一的,则IdxMax方法似乎有效,如果不是唯一的,则掩码方法有效。在我的例子中,索引不是唯一的,我在最初的文章中忘记提到了这一点。

我认为您可以使用get index of first
True
值,然后通过以下方式设置:


编辑:

非唯一索引的解决方案:

np.random.seed(1)
df = pd.DataFrame(np.random.randint(4, size=(5,1)), index=[1,2,2,3,4])
print (df)
   0
1  1
2  3
2  0
3  0
4  3

df = df.reset_index()
df.loc[(df[0] == 3).idxmax(), 0] = 200
df = df.set_index('index')
df.index.name = None
print (df)
     0
1    1
2  200
2    0
3    0
4    3
编辑1:

使用
多索引的解决方案

np.random.seed(1)
df = pd.DataFrame(np.random.randint(4, size=(5,1)), index=[1,2,2,3,4])
print (df)
   0
1  1
2  3
2  0
3  0
4  3

df.index = [np.arange(len(df.index)), df.index]
print (df)
     0
0 1  1
1 2  3
2 2  0
3 3  0
4 4  3

df.loc[(df[0] == 3).idxmax(), 0] = 200
df = df.reset_index(level=0, drop=True)

print (df)
     0
1    1
2  200
2    0
3    0
4    3
编辑2:

解决方案具有双重功能:


考虑数据帧
df

df = pd.DataFrame(dict(A=[1, 2, 3, 4, 5]))

print(df)

   A
0  1
1  2
2  3
3  4
4  5

创建一些任意切片
slc

slc = df[df.A > 2]

print(slc)

   A
2  3
3  4
4  5

使用
索引[0]
loc

df.loc[slc.index[0]] = 0
print(df)

   A
0  1
1  2
2  0
3  4
4  5
在此方法中,不会创建数据帧的额外副本,但会引入一个额外列,该列可以在处理后删除。要选择任何索引而不是第一个索引,可以按如下方式更改最后一行

df.loc[df[df['b']==0].index.tolist()[n],'a']=0
更改切片中任何第n项的步骤

df

切片和贴标签后的df

          a  b
1  0.111089  0
2  0.255633  0
2  0.332682  0
3  0.434527  0
3  0.730548  1
3  0.844724  1
将切片中第一项的值(标记为0)更改为0后


因此,使用一些答案,我设法找到了一种简单的方法:

np.random.seed(1)
df = pd.DataFrame(np.random.randint(4, size=(5,1)))
print df
   0
0  1
1  3
2  0
3  0
4  3
df.loc[(df[0] == 0).cumsum()==1,0] = 1
   0
0  1
1  3
2  1
3  0
4  3

本质上,这是使用与累积数内联的掩码。

如果第二个7不直接位于第一个7之后,也就是说,如果布尔数组上的
cumsum
的结果将有几个
1
s?@juanpa.arrivillaga-谢谢,你是对的。给我一秒钟,我认为最可靠的方法,而且只有在索引唯一的情况下才可靠,就是从切片中获取索引,然后从索引中获取第一个值,并在原始帧上使用该值进行设置。啊,
idxmax
,非常非常聪明@RexFuzzle-是的,如果不是连续值,它也可以工作,请参阅第二个不同条件的解决方案。我希望不要复制df的任何部分,因为它很大,甚至切片可能相当大。@RexFuzzle您说切片是任意的,我假设已经存在。从该片中,我获取第一个索引值并使用它修改原始的
df
。我认为类似
df.loc[slice,另一个\u片]
的内容应该比
df.loc[slice].loc[:,另一个\u片]
更少占用内存。这可以同时对行和列进行切片,但在不同的条件下似乎不可能按行进行切片。实际上我不确定,也许我心里想的没有道理。
import pandas as pd
import numpy as np
df = pd.DataFrame(np.random.rand(6,1),index=[1,2,2,3,3,3])
df[1] = 0
df.columns=['a','b']
df['b'][df['a']>=0.5]=1
df=df.sort(['b','a'],ascending=[0,1])
df.loc[df[df['b']==0].index.tolist()[0],'a']=0
df.loc[df[df['b']==0].index.tolist()[n],'a']=0
          a  
1  0.111089  
2  0.255633  
2  0.332682  
3  0.434527  
3  0.730548  
3  0.844724  
          a  b
1  0.111089  0
2  0.255633  0
2  0.332682  0
3  0.434527  0
3  0.730548  1
3  0.844724  1
          a  b
3  0.730548  1
3  0.844724  1
1  0.000000  0
2  0.255633  0
2  0.332682  0
3  0.434527  0
np.random.seed(1)
df = pd.DataFrame(np.random.randint(4, size=(5,1)))
print df
   0
0  1
1  3
2  0
3  0
4  3
df.loc[(df[0] == 0).cumsum()==1,0] = 1
   0
0  1
1  3
2  1
3  0
4  3