¿Cómo poner en minúscula una columna de cadena de marco de datos de pandas si tiene valores faltantes?

84

El siguiente código no funciona.

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())

¿Cómo debo modificarlo para obtener xLower = ['one', 'two', np.nan]? La eficiencia es importante ya que el marco de datos real es enorme.

P. Escondido
fuente
A partir de la versión 0.25 en adelante, recomiendo str.casefoldpara comparaciones de cuerdas plegables más agresivas. Más información en esta respuesta .
cs95

Respuestas:

180

utilizar métodos de cadena vectorizados de pandas ; como en la documentación:

estos métodos excluyen automáticamente los valores faltantes / NA

.str.lower() es el primer ejemplo allí;

>>> df['x'].str.lower()
0    one
1    two
2    NaN
Name: x, dtype: object
behzad.nouri
fuente
10000 loops, best of 3: 96.4 µs per loop10000 loops, best of 3: 125 µs per loop
Curiosamente,
1
@EdChum eso no sorprende con solo 3 elementos; pero no sería el caso con, digamos, solo 100 elementos;
behzad.nouri
@ behzad.nouri Intenté df1 ['comentario'] = df1 ['comentario']. str.lower () pero obtuve el error KeyError: 'comentario' cada vez. Verifiqué: tengo una columna llamada exactamente igual. ¿Qué puede causar un error?
Katya
16

Otra posible solución, en caso de que la columna no solo tenga cadenas sino también números, es usar astype(str).str.lower()o to_string(na_rep='')porque de lo contrario, dado que un número no es una cadena, al bajarlo retornará NaN, por lo tanto:

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()

entonces tenemos:

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

y no

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

editar:

si no desea perder los NaN, entonces usar el mapa será mejor, (de @ wojciech-walczak y @ cs95 comment) se verá así

xSecureLower = df['x'].map(lambda x: x.lower() if isinstance(x,str) else x)
Mike W
fuente
1
¡Gracias hombre! Me olvidé de los NaN, acabo de corregir la respuesta
Mike W
7

Una posible solución:

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)

Y un resultado:

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

Sin embargo, no estoy seguro de la eficiencia.

Wojciech Walczak
fuente
Igual que la otra respuesta, utilícela isinstancepara verificar el tipo de un objeto.
cs95
6

también puedes probar este,

df= df.applymap(lambda s:s.lower() if type(s) == str else s)
Farid
fuente
1
type(s) == stren su lugar debería serisinstance(s, str)
cs95
6

Pandas> = 0.25: Elimina las distinciones de mayúsculas y minúsculas con str.casefold

A partir de la versión 0.25, recomiendo usar el método de cadena "vectorizada" str.casefoldsi se trata de datos unicode (funciona independientemente de la cadena o unicodes):

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

0       lower
1    capitals
2         NaN
3    swapcase
dtype: object

Consulte también el problema relacionado con GitHub GH25405 .

casefoldse presta a una comparación más agresiva de plegado de cajas. También maneja los NaN con elegancia (al igual que lo str.lowerhace).

Pero, ¿por qué es esto mejor?

La diferencia se ve con Unicodes. Tomando el ejemplo en los documentos de Pythonstr.casefold ,

El plegado de mayúsculas y minúsculas es similar a las minúsculas, pero más agresivo porque está destinado a eliminar todas las distinciones de mayúsculas y minúsculas en una cadena. Por ejemplo, la letra minúscula alemana 'ß'es equivalente a "ss". Dado que ya está en minúsculas, lower()no haría nada 'ß'; casefold() lo convierte a "ss".

Compare la salida de lowerpara,

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

0    der fluß
dtype: object

Versus casefold,

s.str.casefold()

0    der fluss
dtype: object

También vea Python: lower () vs casefold () en la coincidencia de cadenas y la conversión a minúsculas .

cs95
fuente
2

Puede estar usando la comprensión de listas

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)
profundo
fuente
2

Aplicar la función lambda

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

Utilice la función de aplicación,

Xlower = df['x'].apply(lambda x: x.upper()).head(10) 
Ashutosh Shankar
fuente
1
Como la eficiencia es importante para el usuario (Efficiency is important since the real data frame is huge.)y hay algunas respuestas más, intente exponer cuál es el buen punto de su respuesta.
David García Bodego
0

copie su columna Dataframe y simplemente aplique

df=data['x']
newdf=df.str.lower()
Ch HaXam
fuente