Как сделать строковый столбец pandas dataframe в нижнем регистре, если в нем отсутствуют значения?

87

Следующий код не работает.

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

Как мне настроить его, чтобы получить xLower = ['one', 'two', np.nan]? Эффективность важна, поскольку реальный фрейм данных огромен.

П.Эскондидо
источник
Начиная с v0.25, я рекомендую str.casefoldдля более агрессивных сравнений строк сворачивания регистра. Больше информации в этом ответе .
cs95

Ответы:

188

использовать векторизованные строковые методы pandas ; как в документации:

эти методы автоматически исключают отсутствующие значения / значения NA

.str.lower() это самый первый пример;

>>> df['x'].str.lower()
0    one
1    two
2    NaN
Name: x, dtype: object
behzad.nouri
источник
интересно, что это медленнее, чем метод карты в другом ответе по 10000 loops, best of 3: 96.4 µs per loopсравнению с10000 loops, best of 3: 125 µs per loop
EdChum
1
@EdChum, что неудивительно, ведь всего 3 элемента; но это было бы не так, скажем, со 100 элементами;
behzad.nouri 07
@ behzad.nouri Я попробовал df1 ['comment'] = df1 ['comment']. str.lower (), но получил ошибку KeyError: 'comment' каждый раз. Я проверил - у меня столбец точно такой же. Что может вызвать ошибку?
Катя
16

Другое возможное решение, если в столбце есть не только строки, но и числа, - использовать astype(str).str.lower()или to_string(na_rep='')потому что в противном случае, учитывая, что число не является строкой, при уменьшении оно вернется NaN, поэтому:

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

тогда у нас есть:

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

и нет

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

редактировать:

если вы не хотите терять NaN, тогда будет лучше использовать карту (из комментариев @ wojciech-walczak и @ cs95) это будет выглядеть примерно так

xSecureLower = df['x'].map(lambda x: x.lower() if isinstance(x,str) else x)
Майк В
источник
1
Спасибо чувак! Я забыл про NaN, просто поправил ответ
Mike W
7

вы также можете попробовать это,

df= df.applymap(lambda s:s.lower() if type(s) == str else s)
Фарид
источник
1
type(s) == strвместо этого должно бытьisinstance(s, str)
cs95
7

Возможное решение:

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)

И результат:

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

Хотя не уверен в эффективности.

Войцех Вальчак
источник
То же, что и другой ответ, используйте isinstanceпри проверке типа объекта.
cs95
6

Pandas> = 0,25: удалить различия в регистре с помощью str.casefold

Начиная с v0.25, я рекомендую использовать "векторизованный" строковый метод, str.casefoldесли вы имеете дело с данными в Юникоде (он работает независимо от строки или юникода):

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

0       lower
1    capitals
2         NaN
3    swapcase
dtype: object

См. Также связанную проблему GitHub GH25405 .

casefoldподдается более агрессивному сравнению со складыванием корпуса. Он также изящно обрабатывает NaN (точно так str.lowerже).

Но почему так лучше?

Разница видна с юникодами. Взяв пример из документации Pythonstr.casefold ,

Раскладка регистра похожа на регистр нижнего регистра, но более агрессивна, поскольку предназначена для устранения всех различий регистра в строке. Например, немецкая строчная буква 'ß'эквивалентна "ss". Поскольку это уже строчная буква, lower()ничего не делать 'ß'; casefold() преобразует его в "ss".

Сравните вывод lowerдля,

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

0    der fluß
dtype: object

Versus casefold,

s.str.casefold()

0    der fluss
dtype: object

Также см. Python: lower () vs. casefold () в сопоставлении строк и преобразовании в нижний регистр .

cs95
источник
2

Может использоваться понимание списка

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

Применить лямбда-функцию

df['original_category'] = df['original_category'].apply(lambda x:x.lower())
Aravinda_gn
источник
1

Используйте функцию применения,

Xlower = df['x'].apply(lambda x: x.upper()).head(10) 
Ашутош Шанкар
источник
1
Поскольку для пользователя важна эффективность (Efficiency is important since the real data frame is huge.)и есть еще несколько ответов, пожалуйста, постарайтесь показать, какой из них является хорошей точкой вашего ответа.
Дэвид Гарсия Бодего
0

скопируйте столбец Dataframe и просто примените

df=data['x']
newdf=df.str.lower()
Ch HaXam
источник