Установить значение для конкретной ячейки в панде 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>
- это значение, которое вы хотите добавить в этот столбец/строку.
Этот пример не работает точно с рассматриваемым вопросом, но он может быть полезен для тех, кто хочет добавить определенное значение на основе условия.
Ответ 4
Рекомендуемый способ (по словам сопровождающих) установить значение:
df.ix['x','C']=10
Использование "цепной индексации" (df['x']['C']
) может привести к проблемам.
См:
Ответ 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"]
вы можете использовать одно из этих решений:
-
df.iat[0,0] = 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'])