Wie teste ich, ob eine Zeichenfolge in Pandas eine der Teilzeichenfolgen in einer Liste enthält?

119

Gibt es eine Funktion, die einer Kombination von entspricht? df.isin() und entspricht df[col].str.contains()?

Angenommen, ich habe die Serie s = pd.Series(['cat','hat','dog','fog','pet']) und möchte alle Orte finden, an denen sich eine sbefindet ['og', 'at']. Ich möchte alles außer "Haustier" erhalten.

Ich habe eine Lösung, aber sie ist ziemlich unelegant:

searchfor = ['og', 'at']
found = [s.str.contains(x) for x in searchfor]
result = pd.DataFrame[found]
result.any()

Gibt es einen besseren Weg, dies zu tun?

ari
quelle
Hinweis : Es gibt eine von @unutbu beschriebene Lösung , die effizienter ist als die Verwendung pd.Series.str.contains. Wenn die Leistung ein Problem darstellt, kann dies eine Untersuchung wert sein.
Jpp
Es wird dringend empfohlen, diese Antwort für die teilweise Zeichenfolgensuche mit mehreren Schlüsselwörtern / regulären Ausdrücken zu lesen (scrollen Sie nach unten zur Unterüberschrift " Suche nach mehreren Teilzeichenfolgen ").
CS95

Antworten:

219

Eine Möglichkeit besteht darin, nur das Regex- |Zeichen zu verwenden, um zu versuchen, die einzelnen Teilzeichenfolgen in den Wörtern Ihrer Serie abzugleichen s(wird immer noch verwendet str.contains).

Sie können den regulären Ausdruck konstruieren, indem Sie die Wörter searchformit verbinden |:

>>> searchfor = ['og', 'at']
>>> s[s.str.contains('|'.join(searchfor))]
0    cat
1    hat
2    dog
3    fog
dtype: object

Wie @AndyHayden in den Kommentaren unten vermerkt hat, achten Sie darauf, ob Ihre Teilzeichenfolgen Sonderzeichen wie $und enthalten, mit ^denen Sie buchstäblich übereinstimmen möchten. Diese Zeichen haben im Zusammenhang mit regulären Ausdrücken eine bestimmte Bedeutung und wirken sich auf die Übereinstimmung aus.

Sie können Ihre Liste der Teilzeichenfolgen sicherer machen, indem Sie nicht alphanumerische Zeichen mit re.escapefolgenden Überschriften maskieren :

>>> import re
>>> matches = ['$money', 'x^y']
>>> safe_matches = [re.escape(m) for m in matches]
>>> safe_matches
['\\$money', 'x\\^y']

Die Zeichenfolgen in dieser neuen Liste stimmen bei Verwendung mit jedem Zeichen buchstäblich überein str.contains.

Alex Riley
quelle
4
Vielleicht ist es auch gut, diesen Link pandas.pydata.org/pandas-docs/stable/… hinzuzufügen . Ab Pandas 0.15 sind die String-Operationen noch einfacher
goofd
6
Eine Sache, auf die Sie achten müssen, ist, wenn eine Zeichenfolge in searchfor spezielle Regex-Zeichen enthält (Sie können sie mit re.escape zuordnen ).
Andy Hayden
@AndyHayden Vielen Dank, ich habe meine Antwort verbessert, um diese Komplikation zu berücksichtigen.
Alex Riley
Ich weiß nicht, warum Ihre Methode nicht mit "str.startswith ('|' .join (searchfor))" funktioniert
Doo Hyun Shin
48

Sie können str.containsallein mit einem Regex-Muster verwenden, indem Sie OR (|):

s[s.str.contains('og|at')]

Oder Sie können die Serie zu einer dataframedann verwendeten hinzufügen str.contains:

df = pd.DataFrame(s)
df[s.str.contains('og|at')] 

Ausgabe:

0 cat
1 hat
2 dog
3 fog 
l'L'l
quelle
wie geht das für AND?
JacoSolari
1
@JacoSolari Check out this answer stackoverflow.com/questions/37011734/…
James
1
@ James ja, danke. Zur Vervollständigung ist hier der am besten bewertete Oneliner in dieser Antwort. df.col.str.contains(r'(?=.*apple)(?=.*banana)',regex=True)
JacoSolari
0

Hier ist ein einzeiliges Lambda, das auch funktioniert:

df["TrueFalse"] = df['col1'].apply(lambda x: 1 if any(i in x for i in searchfor) else 0)

Eingang:

searchfor = ['og', 'at']

df = pd.DataFrame([('cat', 1000.0), ('hat', 2000000.0), ('dog', 1000.0), ('fog', 330000.0),('pet', 330000.0)], columns=['col1', 'col2'])

   col1  col2
0   cat 1000.0
1   hat 2000000.0
2   dog 1000.0
3   fog 330000.0
4   pet 330000.0

Lambda auftragen:

df["TrueFalse"] = df['col1'].apply(lambda x: 1 if any(i in x for i in searchfor) else 0)

Ausgabe:

    col1    col2        TrueFalse
0   cat     1000.0      1
1   hat     2000000.0   1
2   dog     1000.0      1
3   fog     330000.0    1
4   pet     330000.0    0
Grant Shannon
quelle