Jak zamienić małymi literami kolumnę łańcucha danych pandy, jeśli ma brakujące wartości?


87

Poniższy kod nie działa.

import pandas as pd
import numpy as np
df=pd.DataFrame(['ONE','Two', np.nan],columns=['x']) 
xLower = df["x"].map(lambda x: x.lower())

Jak powinienem to zmienić, aby uzyskać xLower = ['one', 'two', np.nan]? Wydajność jest ważna, ponieważ rzeczywista ramka danych jest ogromna.


Od wersji 0.25 polecam str.casefoldbardziej agresywne porównania ciągów ze składaniem wielkości liter. Więcej informacji w tej odpowiedzi .
cs95

Odpowiedzi:


189

używaj pand wektoryzowanych metod ciągów ; jak w dokumentacji:

metody te automatycznie wykluczają brakujące wartości / NA

.str.lower() to pierwszy przykład;

>>> df['x'].str.lower()
0    one
1    two
2    NaN
Name: x, dtype: object

co ciekawe, jest to wolniejsze niż metoda mapy w drugiej odpowiedzi w 10000 loops, best of 3: 96.4 µs per loopporównaniu z10000 loops, best of 3: 125 µs per loop
EdChum

1
@EdChum, co nie jest zaskakujące, mając tylko 3 elementy; ale nie byłoby tak w przypadku, powiedzmy, zaledwie 100 elementów;
behzad.nouri

@ behzad.nouri Próbowałem df1 ['komentarz'] = df1 ['komentarz']. str.lower (), ale otrzymałem błąd KeyError: 'komentarz' za każdym razem. Sprawdziłem - mam kolumnę o nazwie exaclty tak samo. Co może spowodować błąd?
Katya

16

Innym możliwym rozwiązaniem, w przypadku gdy kolumna zawiera nie tylko łańcuchy, ale także liczby, jest użycie astype(str).str.lower()lub to_string(na_rep='')ponieważ w przeciwnym razie, biorąc pod uwagę, że liczba nie jest łańcuchem, po obniżeniu zwróci NaN, dlatego:

import pandas as pd
import numpy as np
df=pd.DataFrame(['ONE','Two', np.nan,2],columns=['x']) 
xSecureLower = df['x'].to_string(na_rep='').lower()
xLower = df['x'].str.lower()

potem będzie:

>>> xSecureLower
0    one
1    two
2   
3      2
Name: x, dtype: object

i nie

>>> xLower
0    one
1    two
2    NaN
3    NaN
Name: x, dtype: object

edytować:

jeśli nie chcesz zgubić NaNów, to lepiej będzie używać mapy (od @ wojciech-walczak i komentarza @ cs95) będzie wyglądać mniej więcej tak

xSecureLower = df['x'].map(lambda x: x.lower() if isinstance(x,str) else x)

1
Dzięki! Zapomniałem o NaNs, właśnie poprawiłem odpowiedź
Mike W

7

możesz spróbować również tego,

df= df.applymap(lambda s:s.lower() if type(s) == str else s)

1
type(s) == strzamiast tego powinno byćisinstance(s, str)
cs95

7

Możliwe rozwiązanie:

import pandas as pd
import numpy as np

df=pd.DataFrame(['ONE','Two', np.nan],columns=['x']) 
xLower = df["x"].map(lambda x: x if type(x)!=str else x.lower())
print (xLower)

A wynik:

0    one
1    two
2    NaN
Name: x, dtype: object

Nie jestem jednak pewien co do wydajności.


Tak samo jak w przypadku drugiej odpowiedzi, użyj isinstancepodczas sprawdzania typu obiektu.
cs95

6

Pandy> = 0,25: Usuń rozróżnienia wielkości liter za pomocą str.casefold

Począwszy od wersji 0.25, polecam użycie metody ciągów „wektoryzowanych”, str.casefoldjeśli masz do czynienia z danymi Unicode (działa niezależnie od ciągu znaków lub Unicode):

s = pd.Series(['lower', 'CAPITALS', np.nan, 'SwApCaSe'])
s.str.casefold()

0       lower
1    capitals
2         NaN
3    swapcase
dtype: object

Zobacz także powiązany problem z usługą GitHub GH25405 .

casefoldnadaje się do bardziej agresywnego porównania składania skrzynek. Z wdziękiem obsługuje również NaN (tak jakstr.lower ).

Ale dlaczego to jest lepsze?

Różnica jest widoczna w przypadku Unicode. Biorąc przykład z dokumentacji Pythonastr.casefold ,

Zwijanie liter jest podobne do małych liter, ale bardziej agresywne, ponieważ ma na celu usunięcie wszystkich rozróżnień wielkości liter w ciągu. Na przykład niemiecka mała litera 'ß'jest równoważna z "ss". Ponieważ jest już małe, lower()nic nie zrobi 'ß'; casefold() konwertuje to na "ss".

Porównaj dane wyjściowe lowerdla,

s = pd.Series(["der Fluß"])
s.str.lower()

0    der fluß
dtype: object

Versus casefold,

s.str.casefold()

0    der fluss
dtype: object

Zobacz także Python: lower () vs. casefold () w dopasowywaniu ciągów i konwertowaniu na małe litery .


2

Może używać rozumienia z list

import pandas as pd
import numpy as np
df=pd.DataFrame(['ONE','Two', np.nan],columns=['Name']})
df['Name'] = [str(i).lower() for i in df['Name']] 

print(df)

2

Zastosuj funkcję lambda

df['original_category'] = df['original_category'].apply(lambda x:x.lower())

1

Użyj funkcji zastosuj,

Xlower = df['x'].apply(lambda x: x.upper()).head(10) 

1
Ponieważ wydajność jest ważna dla użytkownika (Efficiency is important since the real data frame is huge.)i jest jeszcze kilka odpowiedzi, spróbuj ujawnić, która z nich jest dobrym punktem odpowiedzi.
David García Bodego

0

skopiuj kolumnę Dataframe i po prostu zastosuj

df=data['x']
newdf=df.str.lower()
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.