Установить значение для конкретной ячейки в панде DataFrame, используя индекс

Я создал Pandas DataFrame

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

и получил это

    x    y
A  NaN  NaN
B  NaN  NaN
C  NaN  NaN


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

    x    y
A  NaN  NaN
B  NaN  NaN
C  10  NaN

с этим кодом:

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

но содержание df не изменилось. Это опять только NaN в DataFrame.

Какие-либо предложения?

Ответ 1

Ответ RukTech, df.set_value('C', 'x', 10), намного быстрее, чем варианты, которые я предложил ниже. Тем не менее, назначено для устаревания.

В будущем рекомендуемый метод .iat/.at.


Почему df.xs('C')['x']=10 не работает:

df.xs('C') по умолчанию возвращает новый dataframe с копией данных, поэтому

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

изменяет только этот новый фрейм.

df['x'] возвращает вид фрейма df, поэтому

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

изменяет сам df.

Предупреждение. Иногда бывает трудно предсказать, возвращает ли операция копию или представление. По этой причине docs рекомендуют избегать присвоений с "цепной индексацией" .


Поэтому рекомендуемая альтернатива

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

Ответ 2

Обновление: метод .set_value будет устарел. .iat/.at - хорошая замена, к сожалению, pandas предоставляет мало документации


Самый быстрый способ сделать это - использовать set_value. Этот метод в ~ 100 раз быстрее, чем метод .ix. Например:

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

Ответ 3

Вы также можете использовать условный поиск, используя .loc как показано здесь:

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

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

Этот пример не работает точно с рассматриваемым вопросом, но он может быть полезен для тех, кто хочет добавить определенное значение на основе условия.

Ответ 5

Попробуйте использовать df.loc[row_index,col_indexer] = value

Ответ 6

Это единственное, что сработало для меня!

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

Узнайте больше о .loc здесь.

Ответ 7

.iat/.at - хорошее решение. Предположим, у вас есть этот простой data_frame:

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

если мы хотим изменить значение ячейки [0,"A"] вы можете использовать одно из этих решений:

  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

В моем примере я просто изменить его в выбранной ячейке

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

'result' - это поле данных со столбцом 'weight'

Ответ 9

Вы можете использовать .iloc.

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

Ответ 10

Чтобы установить значения, используйте:

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

Ответ 11

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

Рекомендации:

Ответ 12

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

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

Ответ 13

df.loc['c','x']=10 Это изменит значение df.loc['c','x']=10 строки и x-го столбца.

Ответ 14

В дополнение к ответам, приведенным выше, ниже приведен сравнительный анализ различных способов добавления строк данных в уже существующий фрейм данных. Это показывает, что использование at или set-value является наиболее эффективным способом для больших фреймов данных (по крайней мере, для этих условий тестирования).

  • Создайте новый фрейм данных для каждой строки и...
    • ... добавить его (13,0 с)
    • ... объединить его (13,1 с)
  • Сначала сохраните все новые строки в другом контейнере, один раз преобразуйте в новый фрейм данных и добавьте...
    • контейнер = списки списков (2,0 с)
    • контейнер = словарь списков (1,9 с)
  • Предварительно распределите весь фрейм данных, переберите новые строки и все столбцы и заполните, используя
    • ... в (0,6 с)
    • ... set_value (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))

Ответ 15

Если вы хотите изменить значения не для всей строки, а только для некоторых столбцов:

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

Ответ 16

С версии 0.21.1 вы также можете использовать метод .at. Есть некоторые различия по сравнению с .loc как упомянуто здесь - pandas.at и.loc, но это быстрее при замене одного значения

Ответ 17

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

Ответ 18

Я тоже искал этот раздел, и я собрал способ итерации через 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'])