Видаліть рядки, що містять порожні клітинки, з pandas DataFrame


87

У мене є, pd.DataFrameякий був створений шляхом аналізу деяких таблиць Excel. Стовпець якого має порожні клітинки. Наприклад, нижче наведено вихідні дані для частоти цього стовпця, 32320 записів мають відсутні значення для Tenant .

>>> value_counts(Tenant, normalize=False)
                              32320
    Thunderhead                8170
    Big Data Others            5700
    Cloud Cruiser              5700
    Partnerpedia               5700
    Comcast                    5700
    SDP                        5700
    Agora                      5700
    dtype: int64

Я намагаюся скинути рядки, де Tenant відсутній, однак .isnull()параметр не розпізнає відсутні значення.

>>> df['Tenant'].isnull().sum()
    0

Стовпець має тип даних "Об'єкт". Що відбувається в цьому випадку? Як я можу скинути записи там, де немає орендаря ?

Відповіді:


174

Pandas розпізнає значення як нуль, якщо це np.nanоб'єкт, який буде друкувати як NaNу DataFrame. Ваші відсутні значення - це, мабуть, порожні рядки, які Pandas не розпізнає як нульові. Щоб виправити це, ви можете перетворити порожні жала (або все, що є у ваших порожніх клітинках) в np.nanвикористовувані об'єкти replace(), а потім зателефонувати dropna()до вашого DataFrame, щоб видалити рядки з нульовими орендарями.

Для демонстрації ми створюємо DataFrame з деякими випадковими значеннями та деякими порожніми рядками в Tenantsстовпці:

>>> import pandas as pd
>>> import numpy as np
>>> 
>>> df = pd.DataFrame(np.random.randn(10, 2), columns=list('AB'))
>>> df['Tenant'] = np.random.choice(['Babar', 'Rataxes', ''], 10)
>>> print df

          A         B   Tenant
0 -0.588412 -1.179306    Babar
1 -0.008562  0.725239         
2  0.282146  0.421721  Rataxes
3  0.627611 -0.661126    Babar
4  0.805304 -0.834214         
5 -0.514568  1.890647    Babar
6 -1.188436  0.294792  Rataxes
7  1.471766 -0.267807    Babar
8 -1.730745  1.358165  Rataxes
9  0.066946  0.375640         

Тепер ми замінюємо будь-які порожні рядки в Tenantsстовпці np.nanоб'єктами, наприклад:

>>> df['Tenant'].replace('', np.nan, inplace=True)
>>> print df

          A         B   Tenant
0 -0.588412 -1.179306    Babar
1 -0.008562  0.725239      NaN
2  0.282146  0.421721  Rataxes
3  0.627611 -0.661126    Babar
4  0.805304 -0.834214      NaN
5 -0.514568  1.890647    Babar
6 -1.188436  0.294792  Rataxes
7  1.471766 -0.267807    Babar
8 -1.730745  1.358165  Rataxes
9  0.066946  0.375640      NaN

Тепер ми можемо скинути нульові значення:

>>> df.dropna(subset=['Tenant'], inplace=True)
>>> print df

          A         B   Tenant
0 -0.588412 -1.179306    Babar
2  0.282146  0.421721  Rataxes
3  0.627611 -0.661126    Babar
5 -0.514568  1.890647    Babar
6 -1.188436  0.294792  Rataxes
7  1.471766 -0.267807    Babar
8 -1.730745  1.358165  Rataxes

Велике спасибі, я спробую це зробити і повернутися!
Амріта Савант

2
@mcmath, трохи цікаво. Чому ви імпортуєте numpy і використовуєте, np.nanколи це можливо pd.np.nan?
propjk007

3
@ propjk007, як і в багатьох речах у житті, є багато способів зробити багато речей
Ендрю

З моїх тестів , здається, робити df[df['Tenant'].astype(bool)](припускаючи відсутність пробілів - лише порожній рядок) швидше, ніжdf.replace('', np.nan).dropna(subset=['Tenant'])
cs95

43

Pythonic + Пандорант: df[df['col'].astype(bool)]

Порожні рядки хибні, це означає, що ви можете фільтрувати значення bool наступним чином:

df = pd.DataFrame({
    'A': range(5),
    'B': ['foo', '', 'bar', '', 'xyz']
})
df
   A    B
0  0  foo
1  1     
2  2  bar
3  3     
4  4  xyz
df['B'].astype(bool)                                                                                                                      
0     True
1    False
2     True
3    False
4     True
Name: B, dtype: bool

df[df['B'].astype(bool)]                                                                                                                  
   A    B
0  0  foo
2  2  bar
4  4  xyz

Якщо ваша мета - видалити не тільки порожні рядки, а й рядки, що містять лише пробіли, використовуйте str.stripзаздалегідь:

df[df['B'].str.strip().astype(bool)]
   A    B
0  0  foo
2  2  bar
4  4  xyz

Швидше, ніж ви думаєте

.astypeє векторизованою операцією, це швидше, ніж будь-який варіант, представлений на даний момент. Принаймні, з моїх тестів. YMMV.

Ось порівняння часу, я використав деякі інші методи, які міг подумати.

введіть тут опис зображення

Бенчмаркінг-код, для довідки:

import pandas as pd
import perfplot

df1 = pd.DataFrame({
    'A': range(5),
    'B': ['foo', '', 'bar', '', 'xyz']
})

perfplot.show(
    setup=lambda n: pd.concat([df1] * n, ignore_index=True),
    kernels=[
        lambda df: df[df['B'].astype(bool)],
        lambda df: df[df['B'] != ''],
        lambda df: df[df['B'].replace('', np.nan).notna()],  # optimized 1-col
        lambda df: df.replace({'B': {'': np.nan}}).dropna(subset=['B']),  
    ],
    labels=['astype', "!= ''", "replace + notna", "replace + dropna", ],
    n_range=[2**k for k in range(1, 15)],
    xlabel='N',
    logx=True,
    logy=True,
    equality_check=pd.DataFrame.equals)

33

value_counts за замовчуванням опускає NaN, тому ви, швидше за все, маєте справу з "".

Тож ви можете просто відфільтрувати їх як

filter = df["Tenant"] != ""
dfNew = df[filter]

1
Рішення @Bobs у мене не працювало. df.dropna (subset = ['tenant'], inplace = True) працює.
Амріта Савант

1
Вибач за те. Я думав, ви маєте справу з "". Ви повинні опублікувати своє рішення як відповідь
Боб Хаффнер,

8

Існує ситуація, коли в комірці є пробіл, ви не можете його побачити, використовуйте

df['col'].replace('  ', np.nan, inplace=True)

щоб замінити пробіли як NaN, тоді

df= df.dropna(subset=['col'])

4

Ви можете використовувати цей варіант:

import pandas as pd
vals = {
    'name' : ['n1', 'n2', 'n3', 'n4', 'n5', 'n6', 'n7'],
    'gender' : ['m', 'f', 'f', 'f',  'f', 'c', 'c'],
    'age' : [39, 12, 27, 13, 36, 29, 10],
    'education' : ['ma', None, 'school', None, 'ba', None, None]
}
df_vals = pd.DataFrame(vals) #converting dict to dataframe

Виведеться (** - виділення лише бажаних рядків):

   age education gender name
0   39        ma      m   n1 **
1   12      None      f   n2    
2   27    school      f   n3 **
3   13      None      f   n4
4   36        ba      f   n5 **
5   29      None      c   n6
6   10      None      c   n7

Отже, щоб скинути все, що не має значення «освіта», використовуйте наведений нижче код:

df_vals = df_vals[~df_vals['education'].isnull()] 

(`~ ~ означає НЕ)

Результат:

   age education gender name
0   39        ma      m   n1
2   27    school      f   n3
4   36        ba      f   n5
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.