Установить значение первого элемента в slice в Python pandas

поэтому я хотел бы сделать срез фрейма данных, а затем установить значение первого элемента в этом срезе без копирования фрейма данных. Например:

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 работает, если ваш индекс уникален, и метод маски, если нет. В моем случае индекс не уникален, о котором я забыл упомянуть в первоначальном посте.

4 ответов


Я думаю, вы можете использовать idxmax для получения индекса first 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

df.loc[(df[0] == 3).idxmax(), 0] = 200
print (df)
     0
0    1
1  200
2    0
3    0
4    3

EDIT:

решение с не уникальным индексом:

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

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

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

Рассмотрим таблицу данных 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

доступ к первой строке slc внутри df С помощью index[0] и loc

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

   A
0  1
1  2
2  0
3  4
4  5

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

изменить любой N-й элемент-фрагмент

df

          a  
1  0.111089  
2  0.255633  
2  0.332682  
3  0.434527  
3  0.730548  
3  0.844724  

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

          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

по сути, это использование маски, встроенной с cumsum.