it-swarm.com.ru

Установите значение для конкретной ячейки в pandas 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 не изменилось. Это снова только NaNs в DataFrame.

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

340
Mitkp

Ответ 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.

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


Таким образом, рекомендуемая альтернатива

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
359
unutbu

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


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

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

194
RukTech

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

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

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

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

65
Blairg23

Рекомендованный способ (по словам сопровождающих) установить значение:

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

Использование цепной индексации (df['x']['C']) может привести к проблемам.

Увидеть:

29
Yariv

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

16
Yash

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

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

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

15
Alon Galor

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

df.iloc[[2], [0]] = 10
4
Muge Cevik

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

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

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

4

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

   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 после вызова функции prepossessing, которую iat нужно изменить, чтобы умножить значение каждой ячейки на 2:

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

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

1
Sujit Singh

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

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

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

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
1
Good Will

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

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

0
ivanleoncz

В дополнение к ответам, приведенным выше, ниже приведен сравнительный анализ различных способов добавления строк данных в уже существующий фрейм данных. Это показывает, что использование 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))
0
gebbissimo

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

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

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

0
prosti

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

0
andrei deusteanu