Fügen Sie die in der Liste gefundene ID zu der neuen Spalte im Pandas-Datenrahmen hinzu

11

Angenommen, ich habe den folgenden Datenrahmen (eine Spalte mit Ganzzahlen und eine Spalte mit einer Liste von Ganzzahlen) ...

      ID                   Found_IDs
0  12345        [15443, 15533, 3433]
1  15533  [2234, 16608, 12002, 7654]
2   6789      [43322, 876544, 36789]

Und auch eine separate Liste von IDs ...

bad_ids = [15533, 876544, 36789, 11111]

Angesichts dessen und unter Ignorierung der df['ID']Spalte und eines Index möchte ich sehen, ob eine der IDs in der bad_idsListe in der df['Found_IDs']Spalte erwähnt wird. Der Code, den ich bisher habe, ist:

df['bad_id'] = [c in l for c, l in zip(bad_ids, df['Found_IDs'])]

Dies funktioniert jedoch nur, wenn die bad_idsListe länger als der Datenrahmen ist und für den realen Datensatz die bad_idsListe viel kürzer als der Datenrahmen ist. Wenn ich die bad_idsListe auf nur zwei Elemente setze ...

bad_ids = [15533, 876544]

Ich erhalte einen sehr beliebten Fehler (ich habe viele Fragen mit demselben Fehler gelesen) ...

ValueError: Length of values does not match length of index

Ich habe versucht, die Liste in eine Serie zu konvertieren (keine Änderung des Fehlers). Ich habe auch versucht, die neue Spalte hinzuzufügen und alle Werte auf zu setzen, Falsebevor ich die Verständniszeile mache (wieder keine Änderung des Fehlers).

Zwei Fragen:

  1. Wie kann ich meinen Code (unten) für eine Liste verwenden, die kürzer als ein Datenrahmen ist?
  2. Wie würde ich den Code zum Schreiben der tatsächlich gefundenen ID in die df['bad_id']Spalte erhalten (nützlicher als Richtig / Falsch)?

Erwartete Ausgabe für bad_ids = [15533, 876544]:

      ID                   Found_IDs  bad_id
0  12345        [15443, 15533, 3433]    True
1  15533  [2234, 16608, 12002, 7654]   False
2   6789      [43322, 876544, 36789]    True

Ideale Ausgabe für bad_ids = [15533, 876544](ID (s) werden in eine oder mehrere neue Spalten geschrieben):

      ID                   Found_IDs  bad_id
0  12345        [15443, 15533, 3433]    15533
1  15533  [2234, 16608, 12002, 7654]   False
2   6789      [43322, 876544, 36789]    876544

Code:

import pandas as pd

result_list = [[12345,[15443,15533,3433]],
        [15533,[2234,16608,12002,7654]],
        [6789,[43322,876544,36789]]]

df = pd.DataFrame(result_list,columns=['ID','Found_IDs'])

# works if list has four elements
# bad_ids = [15533, 876544, 36789, 11111]

# fails if list has two elements (less elements than the dataframe)
# ValueError: Length of values does not match length of index
bad_ids = [15533, 876544]

# coverting to Series doesn't change things
# bad_ids = pd.Series(bad_ids)
# print(type(bad_ids))

# setting up a new column of false values doesn't change things
# df['bad_id'] = False

print(df)

df['bad_id'] = [c in l for c, l in zip(bad_ids, df['Found_IDs'])]

print(bad_ids)

print(df)
MDR
quelle

Antworten:

7

Verwenden np.intersect1d, um den Schnittpunkt der beiden Listen zu erhalten:

df['bad_id'] = df['Found_IDs'].apply(lambda x: np.intersect1d(x, bad_ids))

      ID                   Found_IDs    bad_id
0  12345        [15443, 15533, 3433]   [15533]
1  15533  [2234, 16608, 12002, 7654]        []
2   6789      [43322, 876544, 36789]  [876544]

Oder mit nur Vanille-Python unter Verwendung von sets:

bad_ids_set = set(bad_ids)
df['Found_IDs'].apply(lambda x: list(set(x) & bad_ids_set))
Erfan
quelle
3

Wenn Sie alle Werte von Listen in der Found_IDsSpalte anhand aller bad_idsVerwendungswerte testen möchten :

bad_ids = [15533, 876544]

df['bad_id'] = [any(c in l for c in bad_ids) for l  in df['Found_IDs']]
print (df)
      ID                   Found_IDs  bad_id
0  12345        [15443, 15533, 3433]    True
1  15533  [2234, 16608, 12002, 7654]   False
2   6789      [43322, 876544, 36789]    True

Wenn alle übereinstimmen wollen:

df['bad_id'] = [[c for c in bad_ids if c in l] for l  in df['Found_IDs']]
print (df)
      ID                   Found_IDs    bad_id
0  12345        [15443, 15533, 3433]   [15533]
1  15533  [2234, 16608, 12002, 7654]        []
2   6789      [43322, 876544, 36789]  [876544]

Und für die erste Übereinstimmung, wenn eine leere Liste gesetzt ist False, mögliche Lösung, aber nicht empfohlen, Boolesche Werte und Zahlen zu mischen:

df['bad_id'] = [next(iter([c for c in bad_ids if c in l]), False) for l  in df['Found_IDs']]
print (df)
      ID                   Found_IDs  bad_id
0  12345        [15443, 15533, 3433]   15533
1  15533  [2234, 16608, 12002, 7654]   False
2   6789      [43322, 876544, 36789]  876544

Lösung mit Sets:

df['bad_id'] = df['Found_IDs'].map(set(bad_ids).intersection)
print (df)

      ID                   Found_IDs    bad_id
0  12345        [15443, 15533, 3433]   {15533}
1  15533  [2234, 16608, 12002, 7654]        {}
2   6789      [43322, 876544, 36789]  {876544}

Und auch ähnlich beim Listenverständnis:

df['bad_id'] = [list(set(bad_ids).intersection(l)) for l  in df['Found_IDs']]
print (df)
      ID                   Found_IDs    bad_id
0  12345        [15443, 15533, 3433]   [15533]
1  15533  [2234, 16608, 12002, 7654]        []
2   6789      [43322, 876544, 36789]  [876544]
jezrael
quelle
1

Sie können np.any anwenden und verwenden:

df['bad_id'] = df['Found_IDs'].apply(lambda x: np.any([c in x for c in bad_ids]))

Dies gibt den Bool zurück, wenn in Found_IDs eine bad_id vorhanden ist, wenn Sie diese bad_ids abrufen möchten:

df['bad_id'] = df['Found_IDs'].apply(lambda x: [*filter(lambda x: c in x, bad_ids)])

Dies gibt eine Liste der bad_ids bei found_ids zurück. Wenn 0 vorhanden ist, wird [] zurückgegeben.

Bruno Mello
quelle
1

Verwenden von mergeund concatwährend der Gruppierung nach Ihrem Index, um alle Übereinstimmungen zurückzugeben.

bad_ids = [15533, 876544, 36789, 11111]

df2 = pd.concat(
    [
        df,
        pd.merge(
            df["Found_IDs"].explode().reset_index(),
            pd.Series(bad_ids, name="bad_ids"),
            left_on="Found_IDs",
            right_on="bad_ids",
            how="inner",
        )
        .groupby("index")
        .agg(bad_ids=("bad_ids", list)),
    ],
    axis=1,
).fillna(False)
print(df2)


      ID                   Found_IDs          bad_ids
0  12345        [15443, 15533, 3433]          [15533]
1  15533  [2234, 16608, 12002, 7654]            False
2   6789      [43322, 876544, 36789]  [876544, 36789]
Datanovice
quelle
0

Verwenden Sie Explode und Groupby Aggregat

s = df['Found_IDs'].explode()
df['bad_ids'] = s.isin(bad_ids).groupby(s.index).any()

Zum bad_ids = [15533, 876544]

>>> df
      ID                   Found_IDs  bad_ids
0  12345        [15443, 15533, 3433]     True
1  15533  [2234, 16608, 12002, 7654]    False
2   6789      [43322, 876544, 36789]     True

ODER

Zum Abgleichen von Werten

s = df['Found_IDs'].explode()
s.where(s.isin(bad_ids)).groupby(s.index).agg(lambda x: list(x.dropna()))

Zum bad_ids = [15533, 876544]

      ID                   Found_IDs   bad_ids
0  12345        [15443, 15533, 3433]   [15533]
1  15533  [2234, 16608, 12002, 7654]        []
2   6789      [43322, 876544, 36789]  [876544]
Vishnudev
quelle