Frage Wählen Sie Zeilen aus einem Datenrahmen basierend auf Werten in einer Spalte in Pandas aus


Wie wähle ich Zeilen aus einem Datenrahmen basierend auf Werten in einer Spalte in Pandas?
In SQL würde ich verwenden:

select * from table where colume_name = some_value. 

Ich habe versucht, Pandas Dokumentation zu sehen, fand aber nicht sofort die Antwort.


821
2018-06-12 17:42


Ursprung


Antworten:


Um Zeilen auszuwählen, deren Spaltenwert einem Skalar entspricht, some_value, benutzen ==:

df.loc[df['column_name'] == some_value]

So wählen Sie Zeilen aus, deren Spaltenwert iterierbar ist some_values, benutzen isin:

df.loc[df['column_name'].isin(some_values)]

Kombiniere mehrere Bedingungen mit &:

df.loc[(df['column_name'] == some_value) & df['other_column'].isin(some_values)]

Um Zeilen auszuwählen, deren Spaltenwert ist nicht gleich  some_value, benutzen !=:

df.loc[df['column_name'] != some_value]

isin gibt eine boolesche Reihe zurück, um so Zeilen auszuwählen, deren Wert ist nicht im some_values, negiere die boolesche Reihe mit ~:

df.loc[~df['column_name'].isin(some_values)]

Beispielsweise,

import pandas as pd
import numpy as np
df = pd.DataFrame({'A': 'foo bar foo bar foo bar foo foo'.split(),
                   'B': 'one one two three two two one three'.split(),
                   'C': np.arange(8), 'D': np.arange(8) * 2})
print(df)
#      A      B  C   D
# 0  foo    one  0   0
# 1  bar    one  1   2
# 2  foo    two  2   4
# 3  bar  three  3   6
# 4  foo    two  4   8
# 5  bar    two  5  10
# 6  foo    one  6  12
# 7  foo  three  7  14

print(df.loc[df['A'] == 'foo'])

Erträge

     A      B  C   D
0  foo    one  0   0
2  foo    two  2   4
4  foo    two  4   8
6  foo    one  6  12
7  foo  three  7  14

Wenn Sie mehrere Werte enthalten möchten, fügen Sie sie in a ein Liste (oder allgemeiner, jedes iterable) und verwenden isin:

print(df.loc[df['B'].isin(['one','three'])])

Erträge

     A      B  C   D
0  foo    one  0   0
1  bar    one  1   2
3  bar  three  3   6
6  foo    one  6  12
7  foo  three  7  14

Beachten Sie jedoch, dass es effizienter ist, wenn Sie dies mehrmals tun möchten Machen Sie zuerst einen Index und verwenden Sie ihn dann df.loc:

df = df.set_index(['B'])
print(df.loc['one'])

Erträge

       A  C   D
B              
one  foo  0   0
one  bar  1   2
one  foo  6  12

oder, um mehrere Werte aus dem Index zu verwenden df.index.isin:

df.loc[df.index.isin(['one','two'])]

Erträge

       A  C   D
B              
one  foo  0   0
one  bar  1   2
two  foo  2   4
two  foo  4   8
two  bar  5  10
one  foo  6  12

1646
2018-06-12 17:44



tl; dr

Die Pandas entsprechen

select * from table where column_name = some_value

ist

table[table.column_name == some_value]

Mehrere Bedingungen:

table[(table.column_name == some_value) | (table.column_name2 == some_value2)]

oder

table.query('column_name == some_value | column_name2 == some_value2')

Codebeispiel

import pandas as pd

# Create data set
d = {'foo':[100, 111, 222], 
     'bar':[333, 444, 555]}
df = pd.DataFrame(d)

# Full dataframe:
df

# Shows:
#    bar   foo 
# 0  333   100
# 1  444   111
# 2  555   222

# Output only the row(s) in df where foo is 222:
df[df.foo == 222]

# Shows:
#    bar  foo
# 2  555  222

Im obigen Code ist es die Zeile df[df.foo == 222] das gibt die Zeilen basierend auf dem Spaltenwert, 222 in diesem Fall.

Mehrere Bedingungen sind ebenfalls möglich:

df[(df.foo == 222) | (df.bar == 444)]
#    bar  foo
# 1  444  111
# 2  555  222

Aber an diesem Punkt würde ich empfehlen, die Abfrage Funktion, da es weniger ausführlich ist und das gleiche Ergebnis liefert:

df.query('foo == 222 | bar == 444')

134
2017-07-08 15:17



Es gibt einige grundlegende Möglichkeiten, um Zeilen aus einem Pandas-Dataframe auszuwählen.

  1. Boolesche Indizierung
  2. Positionsindexierung
  3. Indizierung von Etiketten
  4. API

Für jeden Basistyp können wir die Dinge einfach halten, indem wir uns auf die Pandas API beschränken oder wir können uns außerhalb der API bewegen, normalerweise in numpyund beschleunige die Dinge.

Ich werde Ihnen Beispiele von jedem zeigen und Ihnen zeigen, wann Sie bestimmte Techniken anwenden können.


Konfiguration
Das erste, was wir brauchen werden, ist eine Bedingung zu identifizieren, die unser Kriterium für die Auswahl von Zeilen sein wird. Das OP bietet auf column_name == some_value. Wir beginnen dort und fügen einige andere häufige Anwendungsfälle hinzu.

Ausleihen von @unutbu:

import pandas as pd, numpy as np

df = pd.DataFrame({'A': 'foo bar foo bar foo bar foo foo'.split(),
                   'B': 'one one two three two two one three'.split(),
                   'C': np.arange(8), 'D': np.arange(8) * 2})

Angenommen, unser Kriterium ist Spalte 'A' = 'foo'

1.
Boolesch Indizierung erfordert, den Wahrheitswert jeder Zeile zu finden 'A' Spalte ist gleich 'foo'Verwenden Sie dann diese Wahrheitswerte, um zu ermitteln, welche Zeilen beibehalten werden sollen. Normalerweise würden wir diese Serie eine Reihe von Wahrheitswerten nennen, mask. Wir werden es auch hier tun.

mask = df['A'] == 'foo'

Wir können diese Maske dann zum Schneiden oder Indizieren des Datenrahmens verwenden

df[mask]

     A      B  C   D
0  foo    one  0   0
2  foo    two  2   4
4  foo    two  4   8
6  foo    one  6  12
7  foo  three  7  14

Dies ist eine der einfachsten Möglichkeiten, diese Aufgabe zu erfüllen. Wenn Leistung oder Intuitivität kein Problem darstellen, sollte dies die von Ihnen gewählte Methode sein. Wenn jedoch die Leistung ein Problem darstellt, sollten Sie eine alternative Möglichkeit zum Erstellen des mask.


2.
Position Indexierung hat ihre Anwendungsfälle, aber das ist keiner von ihnen. Um zu bestimmen, wo wir schneiden sollen, müssen wir zuerst die gleiche boolsche Analyse durchführen, die wir oben gemacht haben. Dies führt dazu, dass wir einen zusätzlichen Schritt ausführen, um die gleiche Aufgabe zu erfüllen.

mask = df['A'] == 'foo'
pos = np.flatnonzero(mask)
df.iloc[pos]

     A      B  C   D
0  foo    one  0   0
2  foo    two  2   4
4  foo    two  4   8
6  foo    one  6  12
7  foo  three  7  14

3.
Etikette Indexierung kann sehr nützlich sein, aber in diesem Fall machen wir wieder mehr Arbeit ohne Nutzen

df.set_index('A', append=True, drop=False).xs('foo', level=1)

     A      B  C   D
0  foo    one  0   0
2  foo    two  2   4
4  foo    two  4   8
6  foo    one  6  12
7  foo  three  7  14

4.
pd.DataFrame.query ist eine sehr elegante / intuitive Art, diese Aufgabe zu erledigen. Aber ist oft langsamer. jedochWenn Sie bei großen Daten auf die Zeiten achten, ist die Abfrage sehr effizient. Mehr als der Standardansatz und von ähnlicher Größenordnung wie mein bester Vorschlag.

df.query('A == "foo"')

     A      B  C   D
0  foo    one  0   0
2  foo    two  2   4
4  foo    two  4   8
6  foo    one  6  12
7  foo  three  7  14

Ich bevorzuge die Verwendung der Boolean  mask 

Tatsächliche Verbesserungen können vorgenommen werden, indem die Art der Erstellung geändert wird Boolean  mask.

mask Alternative 1
Benutze den Basiswert numpy Array und verzichten Sie auf den Overhead der Erstellung eines anderen pd.Series 

mask = df['A'].values == 'foo'

Ich werde am Ende ausführlichere Zeittests zeigen, aber werfen Sie einen Blick auf die Leistungssteigerungen, die wir mit dem Beispieldatenrahmen erzielen. Zuerst betrachten wir den Unterschied bei der Erstellung des mask

%timeit mask = df['A'].values == 'foo'
%timeit mask = df['A'] == 'foo'

5.84 µs ± 195 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
166 µs ± 4.45 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

Bewertung der mask mit dem numpy Array ist ~ 30 mal schneller. Dies ist teilweise auf numpy Bewertung wird oft schneller. Es ist auch teilweise aufgrund des Mangels an Overhead notwendig, um einen Index und einen entsprechenden zu bauen pd.Series Objekt.

Als nächstes betrachten wir das Timing für das Schneiden mit einem mask gegen den anderen.

mask = df['A'].values == 'foo'
%timeit df[mask]
mask = df['A'] == 'foo'
%timeit df[mask]

219 µs ± 12.3 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
239 µs ± 7.03 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

Die Leistungsgewinne sind nicht so ausgeprägt. Wir werden sehen, ob sich dies gegenüber robusteren Tests hält.


mask Alternative 2
Wir hätten den Datenrahmen auch rekonstruieren können. Es gibt einen großen Vorbehalt bei der Rekonstruktion eines Datenrahmens - Sie müssen auf die Daten achten dtypes dabei!

Anstatt von df[mask] wir machen das

pd.DataFrame(df.values[mask], df.index[mask], df.columns).astype(df.dtypes)

Wenn der Datenrahmen vom gemischten Typ ist, was unser Beispiel ist, dann wenn wir kommen df.values das resultierende Array ist von dtype  object und folglich werden alle Spalten des neuen Datenrahmens von dtype  object. So erfordern die astype(df.dtypes) und alle möglichen Leistungsgewinne zu töten.

%timeit df[m]
%timeit pd.DataFrame(df.values[mask], df.index[mask], df.columns).astype(df.dtypes)

216 µs ± 10.4 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
1.43 ms ± 39.6 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

Wenn der Datenrahmen jedoch nicht vom gemischten Typ ist, ist dies ein sehr nützlicher Weg, dies zu tun.

Gegeben

np.random.seed([3,1415])
d1 = pd.DataFrame(np.random.randint(10, size=(10, 5)), columns=list('ABCDE'))

d1

   A  B  C  D  E
0  0  2  7  3  8
1  7  0  6  8  6
2  0  2  0  4  9
3  7  3  2  4  3
4  3  6  7  7  4
5  5  3  7  5  9
6  8  7  6  4  7
7  6  2  6  6  5
8  2  8  7  5  8
9  4  7  6  1  5    

%%timeit
mask = d1['A'].values == 7
d1[mask]

179 µs ± 8.73 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

Gegen

%%timeit
mask = d1['A'].values == 7
pd.DataFrame(d1.values[mask], d1.index[mask], d1.columns)

87 µs ± 5.12 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

Wir haben die Zeit halbiert.


mask Alternative 3
@unutbu zeigt uns auch, wie man es benutzt pd.Series.isin für jedes Element von df['A'] in einer Menge von Werten sein. Dies ergibt dasselbe, wenn unsere Menge von Werten eine Menge von einem Wert ist, nämlich 'foo'. Aber es verallgemeinert auch, um größere Mengen von Werten aufzunehmen, wenn es benötigt wird. Es stellt sich heraus, dass dies immer noch ziemlich schnell ist, obwohl es eine allgemeinere Lösung ist. Der einzige wirkliche Verlust ist in der Intuitivität für diejenigen, die nicht mit dem Konzept vertraut sind.

mask = df['A'].isin(['foo'])
df[mask]

     A      B  C   D
0  foo    one  0   0
2  foo    two  2   4
4  foo    two  4   8
6  foo    one  6  12
7  foo  three  7  14

Wie auch immer, wir können es nutzen numpy um die Leistung zu verbessern und dabei praktisch nichts zu opfern. Wir werden verwenden np.in1d

mask = np.in1d(df['A'].values, ['foo'])
df[mask]

     A      B  C   D
0  foo    one  0   0
2  foo    two  2   4
4  foo    two  4   8
6  foo    one  6  12
7  foo  three  7  14

Zeitliche Koordinierung
Ich werde andere Konzepte, die in anderen Beiträgen erwähnt werden, als Referenz hinzufügen.
Code unten 

Jede Spalte in dieser Tabelle stellt einen Datenrahmen unterschiedlicher Länge dar, über den wir jede Funktion testen. Jede Spalte zeigt die relative Zeit an, wobei die schnellste Funktion bei einem Basisindex von 1.0.

res.div(res.min())

                         10        30        100       300       1000      3000      10000     30000
mask_standard         2.156872  1.850663  2.034149  2.166312  2.164541  3.090372  2.981326  3.131151
mask_standard_loc     1.879035  1.782366  1.988823  2.338112  2.361391  3.036131  2.998112  2.990103
mask_with_values      1.010166  1.000000  1.005113  1.026363  1.028698  1.293741  1.007824  1.016919
mask_with_values_loc  1.196843  1.300228  1.000000  1.000000  1.038989  1.219233  1.037020  1.000000
query                 4.997304  4.765554  5.934096  4.500559  2.997924  2.397013  1.680447  1.398190
xs_label              4.124597  4.272363  5.596152  4.295331  4.676591  5.710680  6.032809  8.950255
mask_with_isin        1.674055  1.679935  1.847972  1.724183  1.345111  1.405231  1.253554  1.264760
mask_with_in1d        1.000000  1.083807  1.220493  1.101929  1.000000  1.000000  1.000000  1.144175

Sie werden feststellen, dass die schnellsten Zeiten anscheinend geteilt werden mask_with_values und mask_with_in1d

res.T.plot(loglog=True)

enter image description here

Funktionen 

def mask_standard(df):
    mask = df['A'] == 'foo'
    return df[mask]

def mask_standard_loc(df):
    mask = df['A'] == 'foo'
    return df.loc[mask]

def mask_with_values(df):
    mask = df['A'].values == 'foo'
    return df[mask]

def mask_with_values_loc(df):
    mask = df['A'].values == 'foo'
    return df.loc[mask]

def query(df):
    return df.query('A == "foo"')

def xs_label(df):
    return df.set_index('A', append=True, drop=False).xs('foo', level=-1)

def mask_with_isin(df):
    mask = df['A'].isin(['foo'])
    return df[mask]

def mask_with_in1d(df):
    mask = np.in1d(df['A'].values, ['foo'])
    return df[mask]

Testen 

res = pd.DataFrame(
    index=[
        'mask_standard', 'mask_standard_loc', 'mask_with_values', 'mask_with_values_loc',
        'query', 'xs_label', 'mask_with_isin', 'mask_with_in1d'
    ],
    columns=[10, 30, 100, 300, 1000, 3000, 10000, 30000],
    dtype=float
)

for j in res.columns:
    d = pd.concat([df] * j, ignore_index=True)
    for i in res.index:a
        stmt = '{}(d)'.format(i)
        setp = 'from __main__ import d, {}'.format(i)
        res.at[i, j] = timeit(stmt, setp, number=50)

Spezielles Timing
Betrachten wir den Sonderfall, wenn wir ein einzelnes Nicht-Objekt haben dtypefür den gesamten Datenrahmen. Code unten 

spec.div(spec.min())

                     10        30        100       300       1000      3000      10000     30000
mask_with_values  1.009030  1.000000  1.194276  1.000000  1.236892  1.095343  1.000000  1.000000
mask_with_in1d    1.104638  1.094524  1.156930  1.072094  1.000000  1.000000  1.040043  1.027100
reconstruct       1.000000  1.142838  1.000000  1.355440  1.650270  2.222181  2.294913  3.406735

Es stellt sich heraus, dass sich der Wiederaufbau nach ein paar hundert Reihen nicht lohnt.

spec.T.plot(loglog=True)

enter image description here

Funktionen 

np.random.seed([3,1415])
d1 = pd.DataFrame(np.random.randint(10, size=(10, 5)), columns=list('ABCDE'))

def mask_with_values(df):
    mask = df['A'].values == 'foo'
    return df[mask]

def mask_with_in1d(df):
    mask = np.in1d(df['A'].values, ['foo'])
    return df[mask]

def reconstruct(df):
    v = df.values
    mask = np.in1d(df['A'].values, ['foo'])
    return pd.DataFrame(v[mask], df.index[mask], df.columns)

spec = pd.DataFrame(
    index=['mask_with_values', 'mask_with_in1d', 'reconstruct'],
    columns=[10, 30, 100, 300, 1000, 3000, 10000, 30000],
    dtype=float
)

Testen 

for j in spec.columns:
    d = pd.concat([df] * j, ignore_index=True)
    for i in spec.index:
        stmt = '{}(d)'.format(i)
        setp = 'from __main__ import d, {}'.format(i)
        spec.at[i, j] = timeit(stmt, setp, number=50)

76
2017-09-11 22:14



Ich finde die Syntax der vorherigen Antworten redundant und schwer zu merken. Pandas stellte die query() Methode in v0.13 und ich bevorzuge es. Für Ihre Frage könnten Sie tun df.query('col == val')

Reproduziert von http://pandas.pydata.org/pandas-docs/version/0.17.0/indexing.html#indexing-query

In [167]: n = 10

In [168]: df = pd.DataFrame(np.random.rand(n, 3), columns=list('abc'))

In [169]: df
Out[169]: 
          a         b         c
0  0.687704  0.582314  0.281645
1  0.250846  0.610021  0.420121
2  0.624328  0.401816  0.932146
3  0.011763  0.022921  0.244186
4  0.590198  0.325680  0.890392
5  0.598892  0.296424  0.007312
6  0.634625  0.803069  0.123872
7  0.924168  0.325076  0.303746
8  0.116822  0.364564  0.454607
9  0.986142  0.751953  0.561512

# pure python
In [170]: df[(df.a < df.b) & (df.b < df.c)]
Out[170]: 
          a         b         c
3  0.011763  0.022921  0.244186
8  0.116822  0.364564  0.454607

# query
In [171]: df.query('(a < b) & (b < c)')
Out[171]: 
          a         b         c
3  0.011763  0.022921  0.244186
8  0.116822  0.364564  0.454607

Sie können auch auf Variablen in der Umgebung zugreifen, indem Sie eine vorangestellt werden @.

exclude = ('red', 'orange')
df.query('color not in @exclude')

41
2018-02-09 01:36



Schnellere Ergebnisse können mit erzielt werden numpy.where.

Zum Beispiel mit unubtus Setup -

In [76]: df.iloc[np.where(df.A.values=='foo')]
Out[76]: 
     A      B  C   D
0  foo    one  0   0
2  foo    two  2   4
4  foo    two  4   8
6  foo    one  6  12
7  foo  three  7  14

Zeitvergleiche:

In [68]: %timeit df.iloc[np.where(df.A.values=='foo')]  # fastest
1000 loops, best of 3: 380 µs per loop

In [69]: %timeit df.loc[df['A'] == 'foo']
1000 loops, best of 3: 745 µs per loop

In [71]: %timeit df.loc[df['A'].isin(['foo'])]
1000 loops, best of 3: 562 µs per loop

In [72]: %timeit df[df.A=='foo']
1000 loops, best of 3: 796 µs per loop

In [74]: %timeit df.query('(A=="foo")')  # slowest
1000 loops, best of 3: 1.71 ms per loop

11
2017-07-05 16:34



Hier ist ein einfaches Beispiel

from pandas import DataFrame

# Create data set
d = {'Revenue':[100,111,222], 
     'Cost':[333,444,555]}
df = DataFrame(d)


# mask = Return True when the value in column "Revenue" is equal to 111
mask = df['Revenue'] == 111

print mask

# Result:
# 0    False
# 1     True
# 2    False
# Name: Revenue, dtype: bool


# Select * FROM df WHERE Revenue = 111
df[mask]

# Result:
#    Cost    Revenue
# 1  444     111

10
2018-06-13 11:49



Ich habe gerade versucht, das zu bearbeiten, aber ich war nicht eingeloggt, also bin ich mir nicht sicher, wo meine Bearbeitung gelaufen ist. Ich habe versucht, mehrere Auswahlmöglichkeiten zu integrieren. Also ich denke eine bessere Antwort ist:

Für einen einzelnen Wert ist das einfachste (menschenlesbare) wahrscheinlich:

df.loc[df['column_name'] == some_value]

Für Wertelisten können Sie auch verwenden:

df.loc[df['column_name'].isin(some_values)]

Beispielsweise,

import pandas as pd
import numpy as np
df = pd.DataFrame({'A': 'foo bar foo bar foo bar foo foo'.split(),
               'B': 'one one two three two two one three'.split(),
               'C': np.arange(8), 'D': np.arange(8) * 2})
print(df)
#      A      B  C   D
# 0  foo    one  0   0
# 1  bar    one  1   2
# 2  foo    two  2   4
# 3  bar  three  3   6
# 4  foo    two  4   8
# 5  bar    two  5  10
# 6  foo    one  6  12
# 7  foo  three  7  14

print(df.loc[df['A'] == 'foo'])

Erträge

     A      B  C   D
0  foo    one  0   0
2  foo    two  2   4
4  foo    two  4   8
6  foo    one  6  12
7  foo  three  7  14

Wenn Sie mehrere Kriterien haben, gegen die Sie auswählen möchten, können Sie sie in eine Liste einfügen und 'isin' verwenden:

print(df.loc[df['B'].isin(['one','three'])])

Erträge

      A      B  C   D
0  foo    one  0   0
1  bar    one  1   2
3  bar  three  3   6
6  foo    one  6  12
7  foo  three  7  14

Beachten Sie jedoch, dass es effizienter ist, A zuerst den Index zu erstellen und dann df.loc zu verwenden, wenn Sie dies mehrmals tun möchten:

df = df.set_index(['A'])
print(df.loc['foo'])

Erträge

  A      B  C   D
foo    one  0   0
foo    two  2   4
foo    two  4   8
foo    one  6  12
foo  three  7  14

7
2018-01-25 23:27



df = pd.DataFrame({'A': 'foo bar foo bar foo bar foo foo'.split(),
                   'B': 'one one two three two two one three'.split(),
                   'C': np.arange(8), 'D': np.arange(8) * 2})
df[df['A']=='foo']

OUTPUT:
   A      B  C   D
0  foo    one  0   0
2  foo    two  2   4
4  foo    two  4   8
6  foo    one  6  12
7  foo  three  7  14

3
2018-03-06 06:02



An diese berühmte Frage anhängen (wenn auch etwas zu spät): Das können Sie auch tun df.groupby('column_name').get_group('column_desired_value').reset_index() um einen neuen Datenrahmen mit einer bestimmten Spalte mit einem bestimmten Wert zu erstellen. Z.B.

import pandas as pd
df = pd.DataFrame({'A': 'foo bar foo bar foo bar foo foo'.split(),
                   'B': 'one one two three two two one three'.split()})
print("Original dataframe:")
print(df)

b_is_two_dataframe = pd.DataFrame(df.groupby('B').get_group('two').reset_index()).drop('index', axis = 1) 
#NOTE: the final drop is to remove the extra index column returned by groupby object
print('Sub dataframe where B is two:')
print(b_is_two_dataframe)

Führen Sie dies aus:

Original dataframe:
     A      B
0  foo    one
1  bar    one
2  foo    two
3  bar  three
4  foo    two
5  bar    two
6  foo    one
7  foo  three
Sub dataframe where B is two:
     A    B
0  foo  two
1  foo  two
2  bar  two

3
2017-11-18 12:10