web-dev-qa-db-de.com

Legen Sie den Wert für eine bestimmte Zelle in Pandas DataFrame mithilfe des Index fest


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?

289
Mitkp

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

Update: Die Methode .set_value Lautet veraltet . .iat/.at Sind gute Ersetzungen, leider liefert pandas) wenig Dokumentation


Am schnellsten geht das mit set_value . Diese Methode ist ca. 100-mal schneller als die Methode .ix. Zum Beispiel:

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

206
RukTech

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.

65
Blairg23

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:

29
Yariv

Versuchen Sie es mit df.loc[row_index,col_indexer] = value

16
Yash

Dies ist das einzige, was für mich funktioniert hat!

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

Erfahren Sie mehr über .lochier .

15
Alon Galor

sie können .iloc verwenden.

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

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:

  1. df.iat[0,0] = 2
  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
3
DINA TAKLIT

df.loc['c','x']=10 Dies ändert den Wert von c th row und x th Spalte.

1
Sujit Singh

Verwenden Sie zum Festlegen von Werten Folgendes:

df.at[0, 'clm1'] = 0
  • Die am schnellsten empfohlene Methode zum Festlegen von Variablen.
  • set_value, ix sind veraltet.
  • Keine Warnung, im Gegensatz zu iloc und loc
1
Miladiouss

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

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:

  • nach ganzzahligen Zeilen-/Spaltenpositionen

>>> 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
  • nach Zeilen-/Spaltenbeschriftungen

>>> 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:

0
ivanleoncz

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).

  • Erstellen Sie für jede Zeile einen neuen Datenrahmen und ...
    • ... anhängen (13,0 s)
    • ... verketten (13.1 s)
  • Speichern Sie alle neuen Zeilen zuerst in einem anderen Container, konvertieren Sie sie einmal in einen neuen Datenrahmen und hängen Sie ....__ an.
    • container = Listenlisten (2.0 s)
    • container = Wörterbuch der Listen (1,9 s)
  • Ordnen Sie den gesamten Datenrahmen vorab zu, wiederholen Sie die neuen Zeilen und alle Spalten und füllen Sie ihn mit .__ aus.
    • ... um (0,6 s)
    • ... set_value (0,4 s)

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))
0
gebbissimo

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)
0
Kirill Dolmatov

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.

0
prosti

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

0