Ich habe einen Pandas-DataFrame erstellt
df=DataFrame(index=['A','B','C'], columns=['x','y'])
und habe das bekommen
x y A NaN NaN __. B NaN NaN __ C NaN NaN __.
Dann möchte ich einer bestimmten Zelle einen Wert zuweisen, zum Beispiel für die Zeile 'C' und die Spalte 'x' .
x y A NaN NaN B NaN NaN C 10 NaN
mit diesem Code:
df.xs('C')['x']=10
aber der Inhalt von df nicht geändert Es ist wieder nur Nans im Dataframe.
Irgendwelche Vorschläge?
Antwort von RukTech , df.set_value('C', 'x', 10)
, ist bei weitem schneller als die von mir vorgeschlagenen Optionen. Es wurde jedoch plated for deprecation .
In der Zukunft wird die empfohlene Methode ist .iat/.at
.
Warum df.xs('C')['x']=10
nicht funktioniert:
df.xs('C')
gibt standardmäßig einen neuen Datenrahmen mit einer Kopie der Daten zurück, also
df.xs('C')['x']=10
modifiziert nur diesen neuen Datenrahmen.
df['x']
gibt eine Ansicht des df
-Datenrahmens zurück
df['x']['C'] = 10
modifiziert df
selbst.
Warning: Es ist manchmal schwierig vorherzusagen, ob eine Operation eine Kopie oder eine Ansicht zurückgibt. Aus diesem Grund wird in docs empfohlen, Zuordnungen mit "verketteter Indizierung" zu vermeiden .
Die empfohlene Alternative ist also
df.at['C', 'x'] = 10
welche ändertdf
.
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
Sie können auch eine bedingte Suche mit .loc
verwenden, wie hier gezeigt:
df.loc[df[<some_column_name>] == <condition>, [<another_column_name>]] = <value_to_add>
dabei ist <some_column_name
die Spalte, gegen die die Variable <condition>
geprüft werden soll, und <another_column_name>
ist die Spalte, zu der Sie hinzufügen möchten (kann eine neue oder bereits vorhandene Spalte sein). <value_to_add>
ist der Wert, den Sie zu dieser Spalte/Zeile hinzufügen möchten.
Dieses Beispiel funktioniert nicht genau mit der vorliegenden Frage, aber es kann nützlich sein, wenn jemand einen bestimmten Wert basierend auf einer Bedingung hinzufügen möchte.
Die empfohlene Methode (gemäß den Betreuern) zum Festlegen eines Werts ist:
df.ix['x','C']=10
Die Verwendung der verketteten Indizierung (df['x']['C']
) kann zu Problemen führen.
Sehen:
Versuchen Sie es mit df.loc[row_index,col_indexer] = value
Dies ist das einzige, was für mich funktioniert hat!
df.loc['C', 'x'] = 10
Erfahren Sie mehr über .loc
hier .
sie können .iloc
verwenden.
df.iloc[[2], [0]] = 10
In meinem Beispiel ändere ich es einfach in der ausgewählten Zelle
for index, row in result.iterrows():
if np.isnan(row['weight']):
result.at[index, 'weight'] = 0.0
'result' ist ein dataField mit Spalte 'weight'
.iat/.at
ist die gute Lösung. Angenommen, Sie haben diesen einfachen Datenrahmen:
A B C
0 1 8 4
1 3 9 6
2 22 33 52
wenn Sie den Wert der Zelle ändern möchten, [0,"A"]
können Sie eine der folgenden Lösungen verwenden:
df.iat[0,0] = 2
df.at[0,'A'] = 2
Und hier ist ein vollständiges Beispiel, wie man iat
verwendet, um einen Wert für cell zu erhalten und festzulegen:
def prepossessing(df):
for index in range(0,len(df)):
df.iat[index,0] = df.iat[index,0] * 2
return df
y_train vorher:
0
0 54
1 15
2 15
3 8
4 31
5 63
6 11
y_train nach Aufruf der Funktion prepossessing, die iat
ändert, um den Wert jeder Zelle mit 2 zu multiplizieren:
0
0 108
1 30
2 30
3 16
4 62
5 126
6 22
df.loc['c','x']=10
Dies ändert den Wert von c th row und x th Spalte.
Verwenden Sie zum Festlegen von Werten Folgendes:
df.at[0, 'clm1'] = 0
set_value
, ix
sind veraltet.iloc
und loc
Hier finden Sie eine Zusammenfassung der gültigen Lösungen aller Benutzer für Datenrahmen, die nach Ganzzahl und Zeichenfolge indiziert sind.
df.iloc, df.loc und df.at funktionieren für beide Arten von Datenrahmen. df.iloc funktioniert nur mit ganzzahligen Zeilen-/Spaltenindizes. df.loc und df.at unterstützen das Festlegen von Werten mithilfe von Spaltennamen und/oder ganzzahligen Indizes .
Wenn der angegebene Index nicht vorhanden ist, hängen sowohl df.loc als auch df.at die neu eingefügten Zeilen/Spalten an den vorhandenen Datenrahmen an, aber df.iloc löst "IndexError: Positionsindizes sind außerhalb der Grenzen" aus. Ein in Python 2.7 und 3.7 getestetes Arbeitsbeispiel lautet wie folgt:
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()
ist veraltet.
Ab Version 0.23.4 wird Pandas "kündigt die Zukunft an" ...
>>> 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
In Anbetracht dieses Hinweises wird hier gezeigt, wie sie verwendet werden:
>>> 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
Verweise:
Zusätzlich zu den obigen Antworten wird hier ein Benchmark-Vergleich durchgeführt, in dem verschiedene Methoden zum Hinzufügen von Datenzeilen zu einem bereits vorhandenen Datenrahmen verglichen werden. Es zeigt, dass die Verwendung eines at- oder set-value der effizienteste Weg für große Datenframes ist (zumindest für diese Testbedingungen).
Für den Test wurde ein vorhandener Datenrahmen mit 100.000 Zeilen und 1.000 Spalten und zufälligen Zahlenwerten verwendet. Zu diesem Datenrahmen wurden 100 neue Zeilen hinzugefügt.
Code siehe unten:
#!/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))
Wenn Sie Werte nicht für die gesamte Zeile ändern möchten, sondern nur für einige Spalten:
x = pd.DataFrame({'A': [1, 2, 3], 'B': [4, 5, 6]})
x.iloc[1] = dict(A=10, B=-10)
Ich habe getestet und die Ausgabe ist df.set_value
ist etwas schneller, aber die offizielle Methode df.at
scheint die schnellste nicht veraltete Methode zu sein, um dies zu tun.
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)
Beachten Sie, dass hierdurch der Wert für eine einzelne Zelle festgelegt wird. Für die Vektoren loc
und iloc
sollten bessere Optionen sein, da sie vektorisiert sind.
Ab Version 0.21.1 können Sie auch die .at
-Methode verwenden. Es gibt einige Unterschiede zu .loc
, wie hier erwähnt - pandas .at im Vergleich zu .loc , aber bei Einzelwertersetzung ist es schneller