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

Rex*_*zle 14 python mask slice pandas argmax

所以我想制作一个数据帧片,然后设置该片中第一个项的值而不复制数据帧.例如:

df = pandas.DataFrame(numpy.random.rand(3,1))
df[df[0]>0][0] = 0
Run Code Online (Sandbox Code Playgroud)

这里的切片是无关紧要的,仅用于示例,并将再次返回整个数据帧.重点是,通过这样做,就像在示例中,您获得了带有复制警告的设置(可以理解).我还尝试先切片,然后使用ILOC/IX/LOC并使用ILOC两次,例如:

df.iloc[df[0]>0,:][0] = 0
df[df[0]>0,:].iloc[0] = 0
Run Code Online (Sandbox Code Playgroud)

这些都不起作用.再次 - 我不想复制数据框,即使它只是切片版本.

编辑:似乎有两种方法,使用掩码或IdxMax.如果索引是唯一的,IdxMax方法似乎有效,如果不是,则掩码方法.在我的情况下,索引不是唯一的,我在最初的帖子中忘了提到.

jez*_*ael 13

我认为你可以使用idxmax获取第一个True值的索引然后设置loc:

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

print ((df[0] == 0).idxmax())
2

df.loc[(df[0] == 0).idxmax(), 0] = 100
print (df)
     0
0    1
1    3
2  100
3    0
4    3
Run Code Online (Sandbox Code Playgroud)
df.loc[(df[0] == 3).idxmax(), 0] = 200
print (df)
     0
0    1
1  200
2    0
3    0
4    3
Run Code Online (Sandbox Code Playgroud)

编辑:

解决方案没有唯一索引:

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
Run Code Online (Sandbox Code Playgroud)

EDIT1:

解决方案MultiIndex:

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
Run Code Online (Sandbox Code Playgroud)

EDIT2:

双重解决方案cumsum:

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

mask = (df[0] == 0).cumsum().cumsum()
print (mask)
1    0
2    1
2    2
3    3
4    4
Name: 0, dtype: int32

df.loc[mask == 1, 0] = 200
print (df)
     0
1    4
2  200
2    4
3    7
4    4
Run Code Online (Sandbox Code Playgroud)


Rex*_*zle 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
Run Code Online (Sandbox Code Playgroud)

本质上,这是使用与 cumsum 内联的掩码。