Mam kolumnę z tekstem. Ten tekst może zawierać nazwy krajów. Chcę mieć listę wszystkich krajów wymienionych w kolumnie w tym samym wierszu, co tekst. Mam już serię z krajami, które chcę wyodrębnić.
SomeText | ... | .... | CountryInText
Something Canada | | |
RUSSIAAreACountry | | |
Mexicoand Brazil is South of USA
SomeText | ... | .... | CountryInText
Something Canada | | | Canada
RUSSIAAreACountry | | | Russia
Mexicoand Brazil is South of USA | | | Mexico, Brazil, USA
Próbowałem z
pd.Series(df['SomeText'].str.findall(f"({'|'.join(countryname['CommonName'])})"))
Jednak to daje mi listę obiektów, których nie mogę dopasować z powrotem do oryginalnej ramki danych. Nazwa kraju [„CommonName”] to seria nazw krajów.
Czy ktoś może mi pomóc ?
Z góry dziękuję
2 odpowiedzi
Rozwiązanie (z małym przykładem testowania) wykorzystujące pakiet re
(dla większej elastyczności):
import pandas as pd
import re
df = pd.DataFrame({"SomeText": ["Something Canada", "RUSSIAAreACountry"]})
countryname = pd.Series({"CommonName": ["Canada", "Russia"]})
df["CountryInText"] = df["SomeText"].str.title().map(lambda x:
re.findall('|'.join(countryname['CommonName']), x, re.I))
UPDATE (na podstawie opinii Erfana w komentarzu):
import pandas as pd
import re
df = pd.DataFrame({"SomeText": ["Something Canada", "RUSSIAAreACountry"]})
countryname = pd.Series({"CommonName": ["Canada", "Russia"]})
df["CountryInText"] = df["SomeText"].str.title().str.findall('|'.join(countryname['CommonName']), re.I)
AKTUALIZACJA 2 (na podstawie przydatnych dodatkowych przypadków testowych opublikowanych przez OP) :
Powyższe podejścia zwróciłyby USA zamiast USA. Dba o to ten poniżej:
import pandas as pd
df = pd.DataFrame({"SomeText": ["Something Canada",
"RUSSIAAreACountry",
"Mexicoand Brazil is South of USA"]})
countryname = pd.Series({"CommonName": ["Canada", "Russia", "Mexico", "Brazil", "USA"]})
df["CountryInText"] = df["SomeText"].map(lambda x: [c for c in countryname['CommonName']
if c.lower() in x.lower()])
Trochę za późno i dupe, ale kod napisałem, więc równie dobrze mogę :)
import pandas as pd
import re
countryname = pd.DataFrame(
data={
"Name": ["Rep. of Congo", "Russia Long", "Canada Long"],
"CommonName": ["Congo", "Russia", "Canada"]})
df = pd.DataFrame(
data={
"SomeText": ["Something Canada", "RUSSIAAreACountry", "Rep ofIreland", "Unrelated"],
"CountryInText": ["","","",""]})
names = "|".join(list(countryname["CommonName"]))
Dałby ci:
Nazwa kraju:
Name CommonName
0 Rep. of Congo Congo
1 Russia Long Russia
2 Canada Long Canada
Df:
SomeText CountryInText
0 Something Canada
1 RUSSIAAreACountry
2 Rep ofIreland
3 Unrelated
Nazwy:
Congo|Russia|Canada
Następnie za pomocą findall i prostej funkcji możesz znaleźć wszystkie wystąpienia łańcuchów we wspólnych nazwach i jeśli cokolwiek zostanie znalezione, wybierz pierwszy i uczyń go wielkością tytułu lub zwróć pusty ciąg, jeśli nic nie zostanie znalezione. To podejście ignoruje wszystkie opcje ograniczeń i zmienia wszystko na wielkość liter. Po napisaniu odpowiedzi widziałem również najbardziej prawe dodanie nazwy, więc to również jest wyłączone.
# re.I is there to do case insensitive matching
df["CountryInText"] = df["SomeText"].str.findall(names, flags = re.I)
def cleanup(country_list):
if len(country_list) > 0:
return str(country_list[0])
return ""
df["CountryInText"] = df["CountryInText"].apply(cleanup).apply(str.title)
Teraz df:
SomeText CountryInText
0 Something Canada Canada
1 RUSSIAAreACountry Russia
2 Rep ofIreland
3 Unrelated
Podobne pytania
Powiązane pytania
Nowe pytania
python
Python to wielozadaniowy, wielozadaniowy język programowania dynamicznie typowany. Został zaprojektowany tak, aby był szybki do nauczenia się, zrozumienia i użycia oraz wymuszania czystej i jednolitej składni. Należy pamiętać, że Python 2 oficjalnie nie jest obsługiwany od 01-01-2020. Mimo to, w przypadku pytań Pythona specyficznych dla wersji, dodaj znacznik [python-2.7] lub [python-3.x]. Korzystając z wariantu Pythona (np. Jython, PyPy) lub biblioteki (np. Pandas i NumPy), należy umieścić go w tagach.