Usuwanie wielu kolumn na podstawie nazw kolumn w Pandas

96

Mam trochę danych i kiedy je importuję, otrzymuję następujące niepotrzebne kolumny Szukam łatwego sposobu na usunięcie ich wszystkich

   'Unnamed: 24', 'Unnamed: 25', 'Unnamed: 26', 'Unnamed: 27',
   'Unnamed: 28', 'Unnamed: 29', 'Unnamed: 30', 'Unnamed: 31',
   'Unnamed: 32', 'Unnamed: 33', 'Unnamed: 34', 'Unnamed: 35',
   'Unnamed: 36', 'Unnamed: 37', 'Unnamed: 38', 'Unnamed: 39',
   'Unnamed: 40', 'Unnamed: 41', 'Unnamed: 42', 'Unnamed: 43',
   'Unnamed: 44', 'Unnamed: 45', 'Unnamed: 46', 'Unnamed: 47',
   'Unnamed: 48', 'Unnamed: 49', 'Unnamed: 50', 'Unnamed: 51',
   'Unnamed: 52', 'Unnamed: 53', 'Unnamed: 54', 'Unnamed: 55',
   'Unnamed: 56', 'Unnamed: 57', 'Unnamed: 58', 'Unnamed: 59',
   'Unnamed: 60'

Są indeksowane przez indeksowanie 0, więc spróbowałem czegoś takiego

    df.drop(df.columns[[22, 23, 24, 25, 
    26, 27, 28, 29, 30, 31, 32 ,55]], axis=1, inplace=True)

Ale to nie jest zbyt wydajne. Próbowałem napisać kilka pętli for, ale wydało mi się to złe zachowanie Pand. Dlatego zadaję tutaj pytanie.

Widziałem kilka przykładów, które są podobne ( upuść wiele pand kolumn ), ale to nie odpowiada na moje pytanie.

Peadar Coyle
źródło
2
Co masz na myśli, wydajne? Czy działa zbyt wolno? Jeśli Twoim problemem jest to, że nie chcesz uzyskać indeksów wszystkich kolumn, które chcesz usunąć, pamiętaj, że możesz po prostu podać df.droplistę nazw kolumn:df.drop(['Unnamed: 24', 'Unnamed: 25', ...], axis=1)
Carsten
Czy nie byłoby łatwiej po prostu podzielić kolumny, które nas interesują, tj. W df = df[cols_of_interest]przeciwnym razie można by df.drop(df.ix[:,'Unnamed: 24':'Unnamed: 60'].head(0).columns, axis=1)
podzielić
2
Miałem na myśli nieefektywne pisanie lub „nieprzyjemny zapach kodu”
Peadar Coyle
1
Warto zauważyć, że w większości przypadków łatwiej jest po prostu zachować żądane kolumny, a następnie usunąć te, których nie chcesz: df = df ['col_list']
sparrow

Odpowiedzi:

65

Nie wiem, co masz na myśli mówiąc nieefektywne, ale jeśli chodzi o pisanie, łatwiej byłoby po prostu wybrać kolumny, które nas interesują i przypisać je z powrotem do df:

df = df[cols_of_interest]

Gdzie cols_of_interestjest lista kolumn, na których Ci zależy.

Możesz też pokroić kolumny i przekazać to do drop:

df.drop(df.ix[:,'Unnamed: 24':'Unnamed: 60'].head(0).columns, axis=1)

Wywołanie po headprostu wybiera 0 wierszy, ponieważ interesują nas tylko nazwy kolumn, a nie dane

aktualizacja

Inna metoda: prościej byłoby użyć maski logicznej zi str.containsodwrócić ją, aby zamaskować kolumny:

In [2]:
df = pd.DataFrame(columns=['a','Unnamed: 1', 'Unnamed: 1','foo'])
df

Out[2]:
Empty DataFrame
Columns: [a, Unnamed: 1, Unnamed: 1, foo]
Index: []

In [4]:
~df.columns.str.contains('Unnamed:')

Out[4]:
array([ True, False, False,  True], dtype=bool)

In [5]:
df[df.columns[~df.columns.str.contains('Unnamed:')]]

Out[5]:
Empty DataFrame
Columns: [a, foo]
Index: []
EdChum
źródło
Pojawiają się błędy, gdy próbuję wykonać albo ~ df.columns ... (TypeError: zły typ operandu dla unary ~: 'str') lub df.columns.str.contains ... (AttributeError: obiekt 'Index' nie ma atrybutu „str”). Jakieś pomysły, dlaczego tak może być?
Dai
@EdChum Czy mogę utworzyć df = df [cols_of_interest] , gdzie cols_of_interest dodaje do niej nazwę kolumny za każdym razem, gdy iteruje pętla for?
@Victor nie, jeśli to zrobisz, nadpisujesz swoją dfnową kolumną, być appendmoże powinieneś, ale tak naprawdę nie rozumiem twojego pytania, powinieneś opublikować prawdziwe pytanie na SO zamiast pytać jako komentarz, ponieważ jest to kiepska forma na SO
EdChum
@EdChum masz absolutną rację. Stworzyłem pytanie i próbuję je rozwiązać, przeszukując różne części SO. Tutaj jest link ! jakikolwiek wkład pomoże stackoverflow.com/questions/48923915/ ...
220

Zdecydowanie najprostsze podejście to:

yourdf.drop(['columnheading1', 'columnheading2'], axis=1, inplace=True)
Philipp Schwarz
źródło
1
Użyłem tego formatu w części mojego kodu i otrzymuję SettingWithCopyWarningostrzeżenie?
KillerSnail,
2
@KillerSnail, można zapisać, aby zignorować. Aby uniknąć błędów, spróbuj: df = df.drop (['colheading1', 'colheading2'], axis = 1)
Philipp Schwarz
6
axisWyjaśniony termin : stackoverflow.com/questions/22149584/… . Zasadniczo axis=0mówi się, że jest „pod względem kolumn” i axis=1„pod względem wierszy”.
Rohmer
6
I inplace=Trueśrodki, że DataFramejest modyfikowany w miejscu.
Rohmer
1
@Killernail, jeśli nie chcesz ostrzeżenia, zróbyourdf = yourdf.drop(['columnheading1', 'columnheading2'], axis=1)
happy_sisyphus
41

Mój osobisty ulubiony i łatwiejszy niż odpowiedzi, które widziałem tutaj (dla wielu kolumn):

df.drop(df.columns[22:56], axis=1, inplace=True)

Lub tworzenie listy dla wielu kolumn.

col = list(df.columns)[22:56]
df.drop(col, axis=1, inplace=1)
sheldonzy
źródło
8
To powinna być odpowiedź. Najczystszy, najłatwiejszy do odczytania, z prostą natywną składnią indeksowania Pand.
Brent Faust
2
Obok tej odpowiedzi powinien znajdować się zielony haczyk, a nie inne.
Siavosh Mahboubian
1
Mała poprawka (chyba że się mylę): drugi blok kodu powinien mieć „inplace = True” zamiast „inplace = 1”.
Thredolsen
20

To prawdopodobnie dobry sposób na robienie tego, co chcesz. Spowoduje to usunięcie wszystkich kolumn, które zawierają w nagłówku słowo „Bez nazwy”.

for col in df.columns:
    if 'Unnamed' in col:
        del df[col]
knightofni
źródło
to for col in df.columns:można uprościć for col in df:, także PO nie wskazał co schemat nazewnictwa dla pozostałych kolumn, mogą zawierać wszystko „Bez nazwy”, także ten jest nieskuteczny, ponieważ usuwa kolumny po jednym na raz
EdChum
Z pewnością nie jest wydajna, ale dopóki nie pracujemy nad ogromnymi ramkami danych, nie będzie to miało znaczącego wpływu. Zaletą tej metody jest to, że jest łatwa do zapamiętania i szybka w kodzie - tworzenie listy kolumn, które chcesz zachować, może być dość bolesne.
knightofni
Myślę, że będzie to najbardziej wydajne na dużym df, ponieważ nie musisz tworzyć lokalnej kopii za pomocąinplace = True
Matt
13

Możesz to zrobić w jednej linii i za jednym razem:

df.drop([col for col in df.columns if "Unnamed" in col], axis=1, inplace=True)

Wiąże się to z mniejszym poruszaniem się / kopiowaniem obiektu niż powyższe rozwiązania.

Piotr
źródło
11

Nie jestem pewien, czy to rozwiązanie zostało jeszcze nigdzie wspomniane, ale można to zrobić pandas.Index.difference.

>>> df = pd.DataFrame(columns=['A','B','C','D'])
>>> df
Empty DataFrame
Columns: [A, B, C, D]
Index: []
>>> to_remove = ['A','C']
>>> df = df[df.columns.difference(to_remove)]
>>> df
Empty DataFrame
Columns: [B, D]
Index: []
px06
źródło
5

Proste i łatwe. Usuń wszystkie kolumny po 22.

df.drop(columns=df.columns[22:]) # love it
Niedson
źródło
Aby zmodyfikować dfw miejscu, dodaj flagę inplace=True, więcdf.drop(columns=df.columns[22:], inplace=True)
arilwan
4

Możesz po prostu przekazać nazwy kolumn jako listę z określeniem osi jako 0 lub 1

  • oś = 1: Wzdłuż rzędów
  • oś = 0: Wzdłuż kolumn
  • Domyślnie oś = 0

    data.drop(["Colname1","Colname2","Colname3","Colname4"],axis=1)

Maddu Swaroop
źródło
1

Poniższe działały dla mnie:

for col in df:
    if 'Unnamed' in col:
        #del df[col]
        print col
        try:
            df.drop(col, axis=1, inplace=True)
        except Exception:
            pass
Shivgan
źródło
0

df = df[[col for col in df.columns if not ('Unnamed' in col)]]

Sarah
źródło
1
Jest to podobne do Petera z tym wyjątkiem, że niepożądane kolumny są odfiltrowywane, a nie odrzucane.
Sarah,