dodaj prefiks ciągu do każdej wartości w kolumnie ciągów przy użyciu Pandas

119

Chciałbym dołączyć ciąg na początku każdej wartości we wspomnianej kolumnie ramki danych pandy (elegancko). Dowiedziałem się już, jak to zrobić i obecnie używam:

df.ix[(df['col'] != False), 'col'] = 'str'+df[(df['col'] != False), 'col']

Wydaje się to cholernie nieeleganckie - czy znasz inny sposób (który może również dodaje znak do wierszy, w których ta kolumna ma wartość 0 lub NaN)?

W przypadku, gdy nie jest to jeszcze jasne, chciałbym zwrócić się:

    col 
1     a
2     0

w:

       col 
1     stra
2     str0
TheChymera
źródło
O co dokładnie pytasz? napisz wyjaśnienie, co robi twój kod / chciałbyś, żeby zrobił
Ryan Saxe
1
Pomyślałem, że to, co robi przykładowy kod, jest bardzo jasne dla przeciętnego użytkownika pand. Dla Twojej wygody dodałem przykłady użycia.
TheChymera
3
Twój opis jest nieco sprzeczny z Twoim kodem. O co chodzi z tą != Falsefirmą? Chcesz dodać strkażdą wartość, czy tylko część?
BrenBarn
do każdej wartości, jak pokazano w moich przykładowych ramkach danych.
TheChymera
1
Twój przykład wciąż jest trochę niejasny, czy chcesz coś takiego df['col'] = 'str' + df['col'].astype(str)?
Roman Pekar

Odpowiedzi:

223
df['col'] = 'str' + df['col'].astype(str)

Przykład:

>>> df = pd.DataFrame({'col':['a',0]})
>>> df
  col
0   a
1   0
>>> df['col'] = 'str' + df['col'].astype(str)
>>> df
    col
0  stra
1  str0
Roman Pekar
źródło
1
Dziękuję Ci. jeśli jest to interesujące, indeksy dataframe również obsługują takie operacje na łańcuchach.
tagoma,
2
Jak to zrobić, jeśli przed konkatenacją muszą zostać spełnione warunki?
acecabana
1
@tagoma, po 4 latach, tak: obsługuje również indeksy dataframe. Możesz utworzyć nową kolumnę i dołączyć do wartości indeksu jako: df ['col'] = 'str' + df.index.astype (str)
MEdwin
„astype (str)” może zepsuć kodowanie, jeśli w końcu próbujesz zapisać do pliku.
Raein Hashemi
2
Kiedy próbuję tego, jak i każdego innego podejścia, otrzymuję SettingWithCopyWarning. Czy jest sposób, aby tego uniknąć?
Madan Ivan
13

Alternatywnie możesz również użyć applykombinacji z format(lub lepiej z f-stringami), co uważam za nieco bardziej czytelne, jeśli np. Chcesz również dodać sufiks lub manipulować samym elementem:

df = pd.DataFrame({'col':['a', 0]})

df['col'] = df['col'].apply(lambda x: "{}{}".format('str', x))

co również daje pożądaną wydajność:

    col
0  stra
1  str0

Jeśli używasz Pythona 3.6+, możesz także użyć f-strings:

df['col'] = df['col'].apply(lambda x: f"str{x}")

dające ten sam wynik.

Wersja f-string jest prawie tak szybka, jak rozwiązanie @ RomanPekar (python 3.6.4):

df = pd.DataFrame({'col':['a', 0]*200000})

%timeit df['col'].apply(lambda x: f"str{x}")
117 ms ± 451 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

%timeit 'str' + df['col'].astype(str)
112 ms ± 1.04 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

Używanie jest formatjednak znacznie wolniejsze:

%timeit df['col'].apply(lambda x: "{}{}".format('str', x))
185 ms ± 1.07 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
Cleb
źródło
ten sam wynik, ale znacznie wolniejszy ;-)
Philipp_Kats,
1
@Philipp_Kats: Dodałem trochę czasu, dzięki za sugestię! Wygląda na to, że f-stringi są prawie tak samo szybkie; formatrzeczywiście działa gorzej. Jak wypadłeś?
Cleb
oh fajnie! w moim rozumieniu .applyjest zawsze albo tak szybka, albo wolniejsza niż "bezpośrednie" operacje wektoryzowane; nawet jeśli nie są wolniejsze, wolę ich unikać w miarę możliwości.
Philipp_Kats,
@Philipp_Kats: Zgadzam się, jednak w tym konkretnym przypadku uważam, że jest bardziej czytelny, gdy dodam sufiks, zrobię coś ze xsobą itd., Ale to tylko kwestia gustu ... :)
Cleb
4

Możesz użyć pandy.Series.map:

df['col'].map('str{}'.format)

Zastosuje słowo „str” przed wszystkimi wartościami.

Boxtell
źródło
3

Jeśli załadujesz plik tabeli dtype=str
lub przekonwertujesz typ kolumny na łańcuch df['a'] = df['a'].astype(str)
, możesz użyć takiego podejścia:

df['a']= 'col' + df['a'].str[:]

Takie podejście umożliwia dołączanie, dołączanie i podzbiór ciągu df.
Działa na Pandas v0.23.4, v0.24.1. Nie wiem o wcześniejszych wersjach.

Wasyl Waskiwskij
źródło
0

Inne rozwiązanie z .loc:

df = pd.DataFrame({'col': ['a', 0]})
df.loc[df.index, 'col'] = 'string' + df['col'].astype(str)

Nie jest to tak szybkie jak powyższe rozwiązania (> 1 ms wolniej na pętlę), ale może być przydatne w przypadku konieczności zmiany warunkowej, na przykład:

mask = (df['col'] == 0)
df.loc[mask, 'col'] = 'string' + df['col'].astype(str)
Lukas
źródło
Dlaczego .indexw df[mask].index?
AMC
@AMC, ponieważ dla .loc potrzebujesz indeksów ramki danych. Oznacza to, że - df [maska] zwraca ramkę danych pasującą do warunku, a df [maska] .index zwraca indeksy ramki danych. Ale prawdą jest, że możesz zrobić to samo z df.loc [(df ['col'] == 'a'), 'col'] lub df.loc [maska, 'col'].
Lukas
1
ponieważ dla .loc potrzebujesz indeksów ramki danych. Jeśli df.loc[mask]działa i działa, to .indexjest zbędne, prawda?
AMC
@AMC dokładnie :). Edytowałem rozwiązanie. Dziękuję Ci.
Lukas