Встановіть значення для конкретної комірки в пандах DataFrame, використовуючи індекс


478

Я створив DataFrame Pandas

df = DataFrame(index=['A','B','C'], columns=['x','y'])

і отримав це

    xy
A NaN NaN
Б NaN NaN
C NaN NaN


Тоді я хочу присвоїти значення певній комірці, наприклад для рядка "C" та стовпця "x". Я очікував отримати такий результат:

    xy
A NaN NaN
Б NaN NaN
C 10 NaN

з цим кодом:

df.xs('C')['x'] = 10

але вміст dfне змінився. Знову це лише NaNs у DataFrame.

Будь-які пропозиції?


29
Не використовуйте «ланцюгову індексацію» ( df['x']['C']), використовуйте df.ix['x','C'].
Ярів

3
Порядок доступу до індексу повинен бути таким: dataframe[column (series)] [row (Series index)]тоді як багато людей (включаючи мене) більше звикли до dataframe[row][column]замовлення. Як програміст Matlab і R, останній вважає мене більш інтуїтивно зрозумілим, але
Пандас

1
Я спробував це, але я в кінцевому підсумку додав ще назви рядків x та інші назви стовпців C. Ви повинні зробити рядок спочатку, а потім стовпець. так df.ix ['C', 'x'] = 10
Матвій

5
До коментаря @ Яріва. Попередження: Починаючи з 0.20.0 індексний індекс .ix застарілий, на користь більш суворих індексаторів .iloc та .loc. pandas.pydata.org/pandas-docs/stable/generated/… . df.at виглядає так, ніби він стирчить.
jeffhale

Відповіді:


592

Відповідь RukTech в , df.set_value('C', 'x', 10), далеко і далеко швидше , ніж варіанти я запропонованих нижче. Однак його планують знищити .

Вперед, рекомендований метод.iat/.at .


Чому df.xs('C')['x']=10не працює:

df.xs('C')за замовчуванням повертає новий фрейм даних з копією даних, так

df.xs('C')['x']=10

змінює лише цей новий фрейм даних.

df['x']повертає вигляд dfфрейму даних, так

df['x']['C'] = 10

модифікує dfсебе.

Попередження : Іноді важко передбачити, чи операція поверне копію чи представлення. З цієї причини документи рекомендують уникати завдань із "ланцюговою індексацією" .


Тож рекомендована альтернатива є

df.at['C', 'x'] = 10

що дійсно модифікує df.


In [18]: %timeit df.set_value('C', 'x', 10)
100000 loops, best of 3: 2.9 µs per loop

In [20]: %timeit df['x']['C'] = 10
100000 loops, best of 3: 6.31 µs per loop

In [81]: %timeit df.at['C', 'x'] = 10
100000 loops, best of 3: 9.2 µs per loop

Немає такого, як df.xв API . Що ти мав на увазі?
smci

3
@smci: 'x'назва стовпця в df. df.xповертає Seriesзначення зі значенням у стовпці x. Я зміню його, df['x']оскільки ця нотація працюватиме з будь-якою назвою стовпця (на відміну від позначення крапки), і я думаю, що це зрозуміліше.
unutbu

1
Я знав це, я вважав, що ви говорите df.xпоряд із якимсь невідомим новим методомdf.xs, df.ix
smci

df.xs(..., copy=True)повертає копію, і це поведінка за замовчуванням. df.xs(..., copy=False)повертає оригінал.
smci

7
За словами керівників, це не рекомендований спосіб встановити значення. Дивіться stackoverflow.com/a/21287235/1579844 і мою відповідь.
Ярів

224

Оновлення: .set_valueметод буде застарілим . .iat/.atє гарною заміною, на жаль панди надають мало документації


Найшвидший спосіб зробити це за допомогою set_value . Цей метод ~ в 100 разів швидший, ніж .ixметод. Наприклад:

df.set_value('C', 'x', 10)


5
Це навіть краще, ніж df['x']['C'] = 10 .
ALH

6
1000 петель, найкраще 3: 195 мкс на цикл "df ['x'] ['C'] = 10" 1000 петель, найкраще 3: 310 мкс на цикл "df.ix ['C', 'x'] = 10 "1000 циклів, найкраще 3: 189 мкс на цикл" df.xs ("C", копія = помилково) ['x'] = 10 "1000 циклів, найкраще 3: 7,22 мкс на цикл" df.set_value ('C', 'x', 10) "
propjk007

1
це також працює для додавання нового рядка / колу до кадру даних?
st.ph.n

Так, так (для панд 0.16.2)
RukTech

Чи можна використовувати це для встановлення значення a df=df.append(df.sum(numeric_only=True),ignore_index=True)?
ctrl-alt-delete

94

Ви також можете використовувати умовний пошук, використовуючи, .locяк показано тут:

df.loc[df[<some_column_name>] == <condition>, [<another_column_name>]] = <value_to_add>

де <some_column_nameстовпець, на який потрібно перевірити <condition>змінну, і <another_column_name>стовпець, до якого потрібно додати (це може бути новий стовпець або той, який вже існує). <value_to_add>- це значення, яке ви хочете додати до цього стовпця / рядка.

Цей приклад не працює саме з відповідним питанням, але може бути корисним для того, хто хоче додати певне значення на основі умови.


8
другий стовпчик повинен бути у дужках, інакше всі стовпці будуть перезаписані значенням. df.loc[df['age']==3, ['age-group']] = 'toddler'
Ось так

Я не можу змусити це працювати, коли <some_column_name> є моїм індексом (індекс одночасного скажу), і я намагаюся додати часову позначку, яка ще не виходить (тобто читання нової часової позначки). Будь-які думки?
yeliabsalohcin

Чи можливо змінити значення на основі значень індексу та комірок?
BND

@BND Я не впевнений, але ви могли б обійти цей очевидний підводний камінь, але просто дублюючи стовпець індексу з іншим стовпцем з тим же значенням? Коротка відповідь - я не знаю.
Blairg23

@yeliabsalohcin див. вище відповідь.
Blairg23

40

Рекомендований спосіб (на думку обслуговуючого персоналу) встановити значення:

df.ix['x','C']=10

Використання "ланцюгової індексації" ( df['x']['C']) може призвести до проблем.

Подивитися:



працює ідеально! хоча це колись буде застарілим!
Павлос Понос

35

Спробуйте використовувати df.loc[row_index,col_indexer] = value


6
Ласкаво просимо до переповнення стека! Будь ласка, подумайте про редагування своєї публікації, щоб додати більше пояснень про те, що робить ваш код і чому це вирішить проблему. Відповідь, що здебільшого просто містить код (навіть якщо він працює), зазвичай не допомагає ОП зрозуміти свою проблему. Також рекомендується не публікувати відповідь, якщо це лише здогадки. Хороша відповідь буде правдоподібною причиною того, чому вона могла б вирішити питання ОП.
SuperBiasedMan

22

Це єдине, що працювало на мене!

df.loc['C', 'x'] = 10

Докладніше про .loc тут .


чи .locзамінили .iat/.at?
Ярмарок Габріеля

1
atАналогічно тому loc, що обидва надають підказки на основі міток. Використовуйте, atякщо вам потрібно отримати або встановити одне значення в DataFrame або Series. Із padas doc
Рутрус

Приємно, що це працювало для мене, коли мої елементи індексу були числовими.
Крістофер Джон

Це не працює для поєднання числових та рядкових індексів.
Seanny123

12

.iat/.atє хорошим рішенням. Припустимо, у вас є такий простий кадр даних:

   A   B   C
0  1   8   4 
1  3   9   6
2  22 33  52

якщо ми хочемо змінити значення комірки [0,"A"]u, можемо використовувати одне з таких рішень:

  1. df.iat[0,0] = 2
  2. df.at[0,'A'] = 2

Ось повний приклад, як використовувати, iatщоб отримати та встановити значення комірки:

def prepossessing(df):
  for index in range(0,len(df)): 
      df.iat[index,0] = df.iat[index,0] * 2
  return df

y_train раніше:

    0
0   54
1   15
2   15
3   8
4   31
5   63
6   11

y_train після виклику функції попереднього розміщення, яку iatпотрібно змінити, щоб помножити значення кожної комірки на 2:

     0
0   108
1   30
2   30
3   16
4   62
5   126
6   22

8

Щоб встановити значення, використовуйте:

df.at[0, 'clm1'] = 0
  • Найшвидший рекомендований метод встановлення змінних.
  • set_value, ixзастаріли.
  • Немає попередження, на відміну від ilocіloc

1
Я прийшов до точно такого ж висновку .
prosti

6

ви можете використовувати .iloc.

df.iloc[[2], [0]] = 10

Цей метод, здається, не підтримує декілька значень, наприклад, df.iloc[[2:8], [0]] = [2,3,4,5,6,7]який метод df.loc()має оригінально.
strpeter

1
працює ідеально, без попередження про депресію!
Павлос Понос

6

У моєму прикладі я просто змінюю його у вибраній комірці

    for index, row in result.iterrows():
        if np.isnan(row['weight']):
            result.at[index, 'weight'] = 0.0

"результат" - це поле даних із стовпцем "вага"


4

set_value() застаріло.

Починаючи з випуску 0.23.4, Pandas " оголошує про майбутнє " ...

>>> df
                   Cars  Prices (U$)
0               Audi TT        120.0
1 Lamborghini Aventador        245.0
2      Chevrolet Malibu        190.0
>>> df.set_value(2, 'Prices (U$)', 240.0)
__main__:1: FutureWarning: set_value is deprecated and will be removed in a future release.
Please use .at[] or .iat[] accessors instead

                   Cars  Prices (U$)
0               Audi TT        120.0
1 Lamborghini Aventador        245.0
2      Chevrolet Malibu        240.0

Враховуючи цю пораду, ось демонстрація способів їх використання:

  • за цілими позиціями рядка / стовпця

>>> df.iat[1, 1] = 260.0
>>> df
                   Cars  Prices (U$)
0               Audi TT        120.0
1 Lamborghini Aventador        260.0
2      Chevrolet Malibu        240.0
  • за мітками рядків / стовпців

>>> df.at[2, "Cars"] = "Chevrolet Corvette"
>>> df
                  Cars  Prices (U$)
0               Audi TT        120.0
1 Lamborghini Aventador        260.0
2    Chevrolet Corvette        240.0

Список літератури:


3

Ось підсумок дійсних рішень, наданих усіма користувачами, для кадрів даних, індексованих цілим числом та рядком.

df.iloc, df.loc і df.at працюють для обох типів кадрів даних, df.iloc працює лише з цілими індексами рядків / стовпців, df.loc та df.at підтримує встановлення значень, використовуючи назви стовпців та / або цілочисельні індекси .

Коли вказаного індексу не існує, і df.loc, і df.at додавали б знову вставлені рядки / стовпці до існуючого кадру даних, але df.iloc підніме "IndexError: позиційні індексери не виходять за межі". Робочий приклад, протестований на Python 2.7 та 3.7, такий:

import numpy as np, pandas as pd

df1 = pd.DataFrame(index=np.arange(3), columns=['x','y','z'])
df1['x'] = ['A','B','C']
df1.at[2,'y'] = 400

# rows/columns specified does not exist, appends new rows/columns to existing data frame
df1.at['D','w'] = 9000
df1.loc['E','q'] = 499

# using df[<some_column_name>] == <condition> to retrieve target rows
df1.at[df1['x']=='B', 'y'] = 10000
df1.loc[df1['x']=='B', ['z','w']] = 10000

# using a list of index to setup values
df1.iloc[[1,2,4], 2] = 9999
df1.loc[[0,'D','E'],'w'] = 7500
df1.at[[0,2,"D"],'x'] = 10
df1.at[:, ['y', 'w']] = 8000

df1
>>> df1
     x     y     z     w      q
0   10  8000   NaN  8000    NaN
1    B  8000  9999  8000    NaN
2   10  8000  9999  8000    NaN
D   10  8000   NaN  8000    NaN
E  NaN  8000  9999  8000  499.0

3

Я протестував, і вихід df.set_valueтрохи швидший, але офіційний метод df.atвиглядає як найшвидший непридатний спосіб зробити це.

import numpy as np
import pandas as pd

df = pd.DataFrame(np.random.rand(100, 100))

%timeit df.iat[50,50]=50 # ✓
%timeit df.at[50,50]=50 #  ✔
%timeit df.set_value(50,50,50) # will deprecate
%timeit df.iloc[50,50]=50
%timeit df.loc[50,50]=50

7.06 µs ± 118 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
5.52 µs ± 64.2 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
3.68 µs ± 80.8 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
98.7 µs ± 1.07 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
109 µs ± 1.42 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

Зверніть увагу: це встановлення значення для однієї комірки. Для векторів locі ilocповинні бути кращі варіанти, оскільки вони векторизовані.


3

Один із способів використання індексу з умовою - спочатку отримати індекс усіх рядків, які задовольняють вашій умові, а потім просто використовувати ці індекси рядків декількома способами

conditional_index = df.loc[ df['col name'] <condition> ].index

Приклад умови такий

==5, >10 , =="Any string", >= DateTime

Тоді ви можете використовувати ці індекси рядків різними способами

  1. Замініть значення одного стовпця для conditional_index
df.loc[conditional_index , [col name]]= <new value>
  1. Замініть значення декількох стовпців для conditional_index
df.loc[conditional_index, [col1,col2]]= <new value>
  1. Одна перевага при збереженні conditional_index полягає в тому, що ви можете призначити значення одного стовпця іншому стовпцю з тим самим індексом рядків
df.loc[conditional_index, [col1,col2]]= df.loc[conditional_index,'col name']

Це все можливо, тому що .index повертає масив індексу, який .loc може використовувати при прямій адресації, щоб уникнути траверсів знову і знову.


як щодо зміни рядків?
FabioSpaghetti

просто використовуйте, df.loc [conditional_index,] = <нове значення> Він замінить нове значення у всіх стовпцях рядків, які відповідають умові
Atta Jutt


1

Окрім наведених вище відповідей, тут є орієнтир, який порівнює різні способи додавання рядків даних до вже існуючого фрейму даних. Це показує, що використання at або set-value є найбільш ефективним способом для великих фреймів даних (принаймні, для цих тестових умов).

  • Створіть новий кадр даних для кожного рядка та ...
    • ... додати (13,0 с)
    • ... об'єднати його (13,1 с)
  • Зберігайте спочатку всі нові рядки в іншому контейнері, конвертуйте один раз у новий фрейм даних та додайте ...
    • контейнер = списки списків (2,0 с)
    • контейнер = словник списків (1,9 с)
  • Попередньо виділіть цілий фрейм даних, повторіть нові рядки та всі стовпці та заповніть
    • ... при (0,6 с)
    • ... встановити значення (0,4 с)

Для тестування було використано існуючий кадр даних, що містить 100 000 рядків і 1000 стовпців та випадкові значення нумеру. До цього фрейму даних додано 100 нових рядків.

Код див. Нижче:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Wed Nov 21 16:38:46 2018

@author: gebbissimo
"""

import pandas as pd
import numpy as np
import time

NUM_ROWS = 100000
NUM_COLS = 1000
data = np.random.rand(NUM_ROWS,NUM_COLS)
df = pd.DataFrame(data)

NUM_ROWS_NEW = 100
data_tot = np.random.rand(NUM_ROWS + NUM_ROWS_NEW,NUM_COLS)
df_tot = pd.DataFrame(data_tot)

DATA_NEW = np.random.rand(1,NUM_COLS)


#%% FUNCTIONS

# create and append
def create_and_append(df):
    for i in range(NUM_ROWS_NEW):
        df_new = pd.DataFrame(DATA_NEW)
        df = df.append(df_new)
    return df

# create and concatenate
def create_and_concat(df):
    for i in range(NUM_ROWS_NEW):
        df_new = pd.DataFrame(DATA_NEW)
        df = pd.concat((df, df_new))
    return df


# store as dict and 
def store_as_list(df):
    lst = [[] for i in range(NUM_ROWS_NEW)]
    for i in range(NUM_ROWS_NEW):
        for j in range(NUM_COLS):
            lst[i].append(DATA_NEW[0,j])
    df_new = pd.DataFrame(lst)
    df_tot = df.append(df_new)
    return df_tot

# store as dict and 
def store_as_dict(df):
    dct = {}
    for j in range(NUM_COLS):
        dct[j] = []
        for i in range(NUM_ROWS_NEW):
            dct[j].append(DATA_NEW[0,j])
    df_new = pd.DataFrame(dct)
    df_tot = df.append(df_new)
    return df_tot




# preallocate and fill using .at
def fill_using_at(df):
    for i in range(NUM_ROWS_NEW):
        for j in range(NUM_COLS):
            #print("i,j={},{}".format(i,j))
            df.at[NUM_ROWS+i,j] = DATA_NEW[0,j]
    return df


# preallocate and fill using .at
def fill_using_set(df):
    for i in range(NUM_ROWS_NEW):
        for j in range(NUM_COLS):
            #print("i,j={},{}".format(i,j))
            df.set_value(NUM_ROWS+i,j,DATA_NEW[0,j])
    return df


#%% TESTS
t0 = time.time()    
create_and_append(df)
t1 = time.time()
print('Needed {} seconds'.format(t1-t0))

t0 = time.time()    
create_and_concat(df)
t1 = time.time()
print('Needed {} seconds'.format(t1-t0))

t0 = time.time()    
store_as_list(df)
t1 = time.time()
print('Needed {} seconds'.format(t1-t0))

t0 = time.time()    
store_as_dict(df)
t1 = time.time()
print('Needed {} seconds'.format(t1-t0))

t0 = time.time()    
fill_using_at(df_tot)
t1 = time.time()
print('Needed {} seconds'.format(t1-t0))

t0 = time.time()    
fill_using_set(df_tot)
t1 = time.time()
print('Needed {} seconds'.format(t1-t0))

0

Якщо ви хочете змінити значення не для всього рядка, а лише для деяких стовпців:

x = pd.DataFrame({'A': [1, 2, 3], 'B': [4, 5, 6]})
x.iloc[1] = dict(A=10, B=-10)

0

З версії 0.21.1 ви також можете використовувати .atметод. Є деякі відмінності порівняно з .locвищезазначеними тут - pandas .at vers .loc , але це швидше при заміні одного значення


0

Отже, ваше запитання перетворити NaN у ['x', C] у значення 10

відповідь ..

df['x'].loc['C':]=10
df

альтернативний код є

df.loc['C':'x']=10
df

-4

Я теж шукав цю тему, і зібрав спосіб ітерації через DataFrame та оновлення її значень пошуку з другої DataFrame. Ось мій код.

src_df = pd.read_sql_query(src_sql,src_connection)
for index1, row1 in src_df.iterrows():
    for index, row in vertical_df.iterrows():
        src_df.set_value(index=index1,col=u'etl_load_key',value=etl_load_key)
        if (row1[u'src_id'] == row['SRC_ID']) is True:
            src_df.set_value(index=index1,col=u'vertical',value=row['VERTICAL'])
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.