Заміна порожніх значень (пробіл) на NaN у пандах


150

Я хочу знайти всі значення у фреймі даних Pandas, які містять пробіл (будь-яку довільну кількість) і замінити ці значення NaN.

Будь-які ідеї, як це можна вдосконалити?

В основному я хочу перетворити це:

                   A    B    C
2000-01-01 -0.532681  foo    0
2000-01-02  1.490752  bar    1
2000-01-03 -1.387326  foo    2
2000-01-04  0.814772  baz     
2000-01-05 -0.222552         4
2000-01-06 -1.176781  qux     

У це:

                   A     B     C
2000-01-01 -0.532681   foo     0
2000-01-02  1.490752   bar     1
2000-01-03 -1.387326   foo     2
2000-01-04  0.814772   baz   NaN
2000-01-05 -0.222552   NaN     4
2000-01-06 -1.176781   qux   NaN

Мені вдалося це зробити з кодом нижче, але людина це некрасиво. Це не Pythonic, і я впевнений, що це не найефективніше використання панд. Я проходжу цикл через кожен стовпчик і роблю булеву заміну проти маски стовпця, що генерується, застосовуючи функцію, яка здійснює пошук регулярних виразів кожного значення, збігаючись на пробіл.

for i in df.columns:
    df[i][df[i].apply(lambda i: True if re.search('^\s*$', str(i)) else False)]=None

Його можна трохи оптимізувати, лише повторивши поля, які можуть містити порожні рядки:

if df[i].dtype == np.dtype('object')

Але це не дуже покращення

І, нарешті, цей код встановлює цільові рядки до None, який працює з функціями Pandas, як fillna(), але було б добре для повноти, якби я міг фактично вставити NaNбезпосередньо замість None.


2
Те, що ви дійсно хочете, - це можливість використовувати replaceрегекс ... (можливо, це потрібно запитати як функцію).
Енді Хайден

3
Я створив випуск github для цієї функції: github.com/pydata/pandas/isissue/2285 . Будемо вдячні за PR! :)
Chang She

Для тих, хто хоче перетворити один-єдиний порожній символ на зниклий, дивіться це просте рішення нижче
Тед Петру

Відповіді:


198

Я думаю, df.replace()що це працює, оскільки панди 0,13 :

df = pd.DataFrame([
    [-0.532681, 'foo', 0],
    [1.490752, 'bar', 1],
    [-1.387326, 'foo', 2],
    [0.814772, 'baz', ' '],     
    [-0.222552, '   ', 4],
    [-1.176781,  'qux', '  '],         
], columns='A B C'.split(), index=pd.date_range('2000-01-01','2000-01-06'))

# replace field that's entirely space (or empty) with NaN
print(df.replace(r'^\s*$', np.nan, regex=True))

Виробляє:

                   A    B   C
2000-01-01 -0.532681  foo   0
2000-01-02  1.490752  bar   1
2000-01-03 -1.387326  foo   2
2000-01-04  0.814772  baz NaN
2000-01-05 -0.222552  NaN   4
2000-01-06 -1.176781  qux NaN

Як зазначив Темак , використовуйте df.replace(r'^\s+$', np.nan, regex=True)у випадку, якщо ваші дійсні дані містять пробіли.


1
regex - булевий прапор. Можливо, ви маєте на увазі, pd.Series(["1", "#", "9", " .", None]).replace(r"( +\.)|#", "X", regex=True).valuesщо дає['1', 'X', '9', 'X', None]
patricksurry

2
Через 2 роки я змінив прийняту відповідь на це, тепер, коли панди це підтримують. Дякую!
Кріс Кларк

35
ПРИМІТКА : якщо ви не хочете, щоб елемент, що містить пробіл посередині, замінили на використання NaNdf.replace(r'^\s+$', np.nan, regex=True)
Temak

7
Я спробував це використати, але виявив, що r '^ \ s * $' має бути виразом для використання. без ^ і $ вона буде відповідати будь-якій рядку з двома послідовними пробілами. Також змінено + на *, щоб включити порожній рядок "" у список речей, які потрібно перетворити на NaN
Master Yogurt

1
Я пробую ваше рішення в коді, але це не має ефекту. Я намагаюся "energy [" Energy Supply "]. Substitute (to_replace =" ... ", value = np.NaN)". Бажаючи змінити рядок "..." на значення NaN, але він нічого не робить і повертає той самий кадр даних.
Арчан Джоші

50

Якщо ви хочете замінити порожній рядок і записи лише пробілами, правильна відповідь :

df = df.replace(r'^\s*$', np.nan, regex=True)

Прийнята відповідь

df.replace(r'\s+', np.nan, regex=True)

Чи не замінює порожній рядок !, Ви можете спробувати себе з наведеним прикладом, трохи оновленим:

df = pd.DataFrame([
    [-0.532681, 'foo', 0],
    [1.490752, 'bar', 1],
    [-1.387326, 'fo o', 2],
    [0.814772, 'baz', ' '],     
    [-0.222552, '   ', 4],
    [-1.176781,  'qux', ''],         
], columns='A B C'.split(), index=pd.date_range('2000-01-01','2000-01-06'))

Зауважте також, що "fo o" не замінюється на Nan, хоча воно містить пробіл. Далі зауважимо, що просте:

df.replace(r'', np.NaN)

Не працює і тест - спробуйте.


33

Як щодо:

d = d.applymap(lambda x: np.nan if isinstance(x, basestring) and x.isspace() else x)

applymapФункція застосовує функцію до кожної клітини dataframe.


Яке приємне поліпшення! Я мав би подумати про це заднім часом, але затримався, щоб зробити булеві заміни чомусь. Одне запитання - чи є перевага робити перевірку базових рядків проти просто str (x) .isspace ()?
Кріс Кларк

1
@ChrisClark: Або добре, хоча я б здогадався, що isinstanceбуде трохи швидше.
BrenBarn

13
Посилання на "basestring" у наведеному вище коді не працюватиме в Python 3 .... у такому випадку спробуйте скористатись "str".
Спайк Вільямс

4
Зауважте, що це рішення не замінює порожні рядки ''. Для розгляду також порожніх рядків використовуйте:d = d.applymap(lambda x: np.nan if isinstance(x, basestring) and (not x or x.isspace()) else x)
tuomastik

18

Я зробив це:

df = df.apply(lambda x: x.str.strip()).replace('', np.nan)

або

df = df.apply(lambda x: x.str.strip() if isinstance(x, str) else x).replace('', np.nan)

Ви можете зняти всі str, а потім замінити порожню str на np.nan.


lambda x: x.str.strip () має бути лямбда x: x.strip ()? незначна пропозиція: додати .astype (str) попереду, це вирішує інші проблеми для мене. Це працює для мене: df = df.apply ['column']. Astype (str) .apply (лямбда x: x.strip ()). Замінити ('', np.nan)
Wouter

Другий рядок коду обробляє колонки типу int / float та string. Приємно. Ткс!
Кейт Стор


5

Якщо ви експортуєте дані з файлу CSV, це може бути так само просто:

df = pd.read_csv(file_csv, na_values=' ')

Це створить кадр даних, а також замінить порожні значення як Na


2
Інший варіант. Використання skipinitialspace=Trueтакож видаляє пробіли після розмежувача, що може спричинити зчитування будь-якої довжини білого простору, порожні рядки nan. Однак якщо ви хочете зберегти початкові пробіли з будь-якої причини, цей варіант не є хорошим вибором.
Райджекар Редді

1
@RajshekarReddy чи можете ви будь-ласка поставити це як відповідь десь, це було геніально!
User2321

2

Для дуже швидкого і простого рішення, коли ви перевіряєте рівність на одне значення, ви можете використовувати maskметод.

df.mask(df == ' ')

1

Усі вони близькі до правильної відповіді, але я б не сказав, що будь-яке рішення проблеми, залишаючись найбільш читабельним для інших, хто читає ваш код. Я б сказав, що відповідь - це поєднання відповіді BrenBarn та коментаря tuomasttik нижче цієї відповіді . Відповідь BrenBarn використовує isspaceвбудований, але не підтримує видалення порожніх рядків, як цього вимагав ОП, і я схильний би приписувати це як стандартний випадок використання рядків на нуль.

Я переписав його на .apply, щоб ви могли зателефонувати на pd.Seriesабо pd.DataFrame.


Пітон 3:

Щоб замінити порожні рядки або рядки повністю пробілів:

df = df.apply(lambda x: np.nan if isinstance(x, str) and (x.isspace() or not x) else x)

Щоб замінити рядки повністю пробілів:

df = df.apply(lambda x: np.nan if isinstance(x, str) and x.isspace() else x)

Щоб використовувати цю функцію в Python 2, вам необхідно замінити strз basestring.

Пітон 2:

Щоб замінити порожні рядки або рядки повністю пробілів:

df = df.apply(lambda x: np.nan if isinstance(x, basestring) and (x.isspace() or not x) else x)

Щоб замінити рядки повністю пробілів:

df = df.apply(lambda x: np.nan if isinstance(x, basestring) and x.isspace() else x)

1

Це працювало для мене. Коли я імпортую свій файл csv, я додав na_values ​​= ''. Проміжки не включаються до значень NaN за замовчуванням.

df = pd.read_csv (filepath, na_values ​​= '')


0

ви можете також використовувати фільтр для цього.

df = PD.DataFrame([
    [-0.532681, 'foo', 0],
    [1.490752, 'bar', 1],
    [-1.387326, 'foo', 2],
    [0.814772, 'baz', ' '],     
    [-0.222552, '   ', 4],
    [-1.176781,  'qux', '  '])
    df[df=='']='nan'
    df=df.astype(float)

Кожен рядок цього коду (крім даних) є несправним.
Юлій

0
print(df.isnull().sum()) # check numbers of null value in each column

modifiedDf=df.fillna("NaN") # Replace empty/null values with "NaN"

# modifiedDf = fd.dropna() # Remove rows with empty values

print(modifiedDf.isnull().sum()) # check numbers of null value in each column

0

Це не елегантне рішення, але те, що, здається, працює - це заощадити XLSX і потім імпортувати його. Інші рішення на цій сторінці не спрацювали для мене, не знаючи чому.

data.to_excel(filepath, index=False)
data = pd.read_excel(filepath)
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.