J'ai créé un DataFrame Pandas
df=DataFrame(index=['A','B','C'], columns=['x','y'])
et obtenu ceci
x y A NaN NaN B NaN NaN C NaN NaN
Ensuite, je souhaite attribuer une valeur à une cellule particulière, par exemple pour la ligne 'C' et la colonne 'x'
x y A NaN NaN B NaN NaN C 10 NaN
avec ce code:
df.xs('C')['x']=10
mais le contenu de df n'ont pas changé. Encore une fois, il n'y a que Nan dans le cadre de données.
Aucune suggestion?
La réponse de RukTech , df.set_value('C', 'x', 10)
, est bien plus rapide que les options que j'ai suggérées ci-dessous. Cependant, il a été prévu pour dépréciation .
À l’avenir, la méthode recommandée par est .iat/.at
.
Pourquoi df.xs('C')['x']=10
ne fonctionne pas:
df.xs('C')
par défaut, retourne une nouvelle image avec une copie des données, donc
df.xs('C')['x']=10
modifie uniquement ce nouveau cadre de données.
df['x']
renvoie une vue du df
dataframe, donc
df['x']['C'] = 10
modifie df
lui-même.
Avertissement: Il est parfois difficile de prédire si une opération renvoie une copie ou une vue. Pour cette raison, les docs recommandent d'éviter les affectations avec "indexation en chaîne" .
Donc, l'alternative recommandée est
df.at['C', 'x'] = 10
quel fait modifier 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
Vous pouvez également utiliser une recherche conditionnelle à l'aide de .loc
, comme indiqué ici:
df.loc[df[<some_column_name>] == <condition>, [<another_column_name>]] = <value_to_add>
où <some_column_name
est la colonne sur laquelle vous souhaitez vérifier la variable <condition>
et <another_column_name>
est la colonne à laquelle vous souhaitez ajouter (peut être une nouvelle colonne ou une colonne existante). <value_to_add>
est la valeur que vous souhaitez ajouter à cette colonne/ligne.
Cet exemple ne fonctionne pas précisément avec la question en question, mais il peut être utile si quelqu'un souhaite ajouter une valeur spécifique en fonction d'une condition.
La méthode recommandée (selon les responsables) pour définir une valeur est la suivante:
df.ix['x','C']=10
L'utilisation de l'indexation chaînée (df['x']['C']
) peut entraîner des problèmes.
Voir:
Essayez d'utiliser df.loc[row_index,col_indexer] = value
vous pouvez utiliser .iloc
.
df.iloc[[2], [0]] = 10
Dans mon exemple, je viens de le changer dans la cellule sélectionnée
for index, row in result.iterrows():
if np.isnan(row['weight']):
result.at[index, 'weight'] = 0.0
'result' est un champ de données avec la colonne 'weight'
.iat/.at
est la bonne solution. En supposant que vous ayez ce simple data_frame:
A B C
0 1 8 4
1 3 9 6
2 22 33 52
si nous voulons modifier la valeur de la cellule [0,"A"]
, vous pouvez utiliser l'une de ces solutions:
df.iat[0,0] = 2
df.at[0,'A'] = 2
Et voici un exemple complet sur l'utilisation de iat
pour obtenir et définir une valeur de cellule:
def prepossessing(df):
for index in range(0,len(df)):
df.iat[index,0] = df.iat[index,0] * 2
return df
y_train avant:
0
0 54
1 15
2 15
3 8
4 31
5 63
6 11
y_train après l'appel de la fonction de pré-acquisition que iat
doit modifier pour multiplier la valeur de chaque cellule par 2
0
0 108
1 30
2 30
3 16
4 62
5 126
6 22
df.loc['c','x']=10
Cela changera la valeur de c th rangée et x ème colonne.
Pour définir des valeurs, utilisez:
df.at[0, 'clm1'] = 0
set_value
, ix
sont obsolètes.iloc
et loc
Voici un résumé des solutions valides fournies par tous les utilisateurs, pour les trames de données indexées par un entier et une chaîne.
df.iloc, df.loc et df.at fonctionnent pour les deux types de trames de données, df.iloc ne fonctionne qu'avec des index entiers de ligne/colonne, df.loc et df.at prennent en charge le paramétrage de valeurs à l'aide de noms de colonne et/ou d'indices d'entiers .
Lorsque l'index spécifié n'existe pas, df.loc et df.at ajouteraient les lignes/colonnes récemment insérées au cadre de données existant, mais df.iloc déclencherait "IndexError: les indexeurs de position sont en dehors des limites". Voici un exemple de travail testé en Python 2.7 et 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
set_value()
est obsolète.
À partir de la version 0.23.4, Pandas "annonce le futur} _" ...
>>> 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
Compte tenu de ces conseils, voici une démonstration de leur utilisation:
>>> 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
Références:
Outre les réponses ci-dessus, voici un point de repère comparant différentes manières d’ajouter des lignes de données à une trame de données existante. Il montre que l'utilisation de ou de la valeur définie est le moyen le plus efficace pour les grandes trames de données (au moins pour ces conditions de test).
Pour le test, une base de données existante comprenant 100 000 lignes et 1 000 colonnes et des valeurs numériques aléatoires a été utilisée. À cette base de données, 100 nouvelles lignes ont été ajoutées.
Code voir ci-dessous:
#!/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))
Si vous souhaitez modifier les valeurs non pour la ligne entière, mais uniquement pour certaines colonnes:
x = pd.DataFrame({'A': [1, 2, 3], 'B': [4, 5, 6]})
x.iloc[1] = dict(A=10, B=-10)
J'ai testé et la sortie est df.set_value
est un peu plus rapide, mais la méthode officielle df.at
ressemble à la façon la plus rapide non dépréciée de le faire.
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)
Notez que vous définissez la valeur pour une seule cellule. Pour les vecteurs loc
et iloc
devraient être de meilleures options car ils sont vectorisés.
Depuis la version 0.21.1, vous pouvez également utiliser la méthode .at
. Il y a quelques différences par rapport à .loc
comme mentionné ici - pandas .at versus .loc , mais c'est plus rapide pour le remplacement à valeur unique