Zaznaczanie wielu kolumn w ramce danych pandy

1109

Mam dane w różnych kolumnach, ale nie wiem, jak je wyodrębnić, aby zapisać je w innej zmiennej.

index  a   b   c
1      2   3   4
2      3   4   5

Jak wybrać 'a', 'b'i zapisać go w celu DF1?

próbowałem

df1 = df['a':'b']
df1 = df.ix[:, 'a':'b']

Wydaje się, że żaden nie działa.

użytkownik1234440
źródło
2
Nigdy nie chcesz używać, .ixponieważ jest to niejednoznaczne. Użyj .iloclub .locjeśli musisz.
Acumenus,
1
Czy można to zrobić bez odwoływania się do nazw nagłówków? tak jak w R, mogę to zrobić w następujący sposób: > csvtable_imp_1 <- csvtable_imp[0:6]i wybiera wielkość delty pierwszych kolumn od 0 do 6. Wszystko, co musiałem zrobić, to odczytać tabelę csv ograniczoną przez bibliotekę readr.
MichaelR
Pracowałem z tym trochę więcej. Znaleziono coś, co działało tak, jak chciał. Domyślnie wybierane są liczby znaków, a nie kolumny. infile_1 = largefile_stay.ix[:,0:6]
MichaelR
3
Dla tych, którzy natkną się na tak późno, ixjest teraz przestarzały. Panda zaleca stosowanie: loc(indeksowania na podstawie etykiet) lub iloc(indeksowania na podstawie pozycji).
ZaydH,

Odpowiedzi:

1768

Nazwy kolumn (które są ciągami znaków) nie mogą być pocięte na plasterki w sposób, w jaki próbowałeś.

Tutaj masz kilka opcji. Jeśli wiesz z kontekstu, które zmienne chcesz wyciąć, możesz po prostu zwrócić widok tylko tych kolumn, przekazując listę do __getitem__składni ([]).

df1 = df[['a','b']]

Alternatywnie, jeśli ważne jest indeksowanie ich numerycznie, a nie według nazwy (powiedzmy, że Twój kod powinien to zrobić automatycznie bez znajomości nazw dwóch pierwszych kolumn), możesz to zrobić w zamian:

df1 = df.iloc[:,0:2] # Remember that Python does not slice inclusive of the ending index.

Dodatkowo powinieneś zapoznać się z ideą widoku na obiekt Pandas vs. kopię tego obiektu. Pierwsza z powyższych metod zwróci nową kopię w pamięci pożądanego podobiektu (pożądanych wycinków).

Czasami jednak w Pandach istnieją konwencje indeksowania, które tego nie robią i zamiast tego dają nową zmienną, która odnosi się tylko do tego samego fragmentu pamięci, co podobiektyw lub plasterek w oryginalnym obiekcie. Stanie się tak w przypadku drugiego sposobu indeksowania, dzięki czemu można go zmodyfikować za pomocą copy()funkcji, aby uzyskać zwykłą kopię. Kiedy tak się dzieje, zmiana tego, co uważasz za wycięty obiekt, może czasem zmienić obiekt oryginalny. Zawsze dobrze jest na to uważać.

df1 = df.iloc[0,0:2].copy() # To avoid the case where changing df1 also changes df

Aby użyć iloc, musisz znać pozycje kolumn (lub indeksy). Ponieważ pozycje kolumn mogą się zmieniać, zamiast indeksów kodowanych na stałe , można użyć ilocwraz z get_locfunkcją columnsmetody obiektu obiektu ramki danych w celu uzyskania indeksów kolumny.

{df.columns.get_loc(c):c for idx, c in enumerate(df.columns)}

Teraz możesz użyć tego słownika, aby uzyskać dostęp do kolumn poprzez nazwy i użycie iloc.

Ely
źródło
192
Uwaga: df[['a','b']]produkuje kopię
Wes McKinney,
1
Tak, to wynikało z mojej odpowiedzi. Trochę o kopii było tylko do użytku, ix[]jeśli wolisz używać ix[]z jakiegokolwiek powodu.
ely
1
ixindeksuje wiersze, a nie kolumny. Myślałem, że OP chce kolumn.
płyty grzewcze
9
ixakceptuje argumenty wycinków, dzięki czemu można uzyskać kolumny. Na przykład df.ix[0:2, 0:2]pobiera lewą górną pod-macierz 2x2, tak jak ma to miejsce w przypadku macierzy NumPy (oczywiście w zależności od nazw kolumn). Możesz nawet użyć składni plasterka w nazwach łańcuchów kolumn, takich jak df.ix[0, 'Col1':'Col5']. To powoduje, że wszystkie kolumny, które przypadkowo są uporządkowane między Col1i Col5w df.columnstablicy. Błędne jest twierdzenie, że ixindeksuje wiersze. To tylko jego najbardziej podstawowe zastosowanie. Obsługuje także znacznie więcej indeksowania. Jest więc ixcałkowicie ogólny dla tego pytania.
ely
7
@AndrewCassidy Nigdy więcej nie używaj .ix. Jeśli chcesz wycinać za pomocą liczb całkowitych, użyj opcji, .ilocktóra nie obejmuje ostatniej pozycji, podobnie jak listy w języku Python.
Ted Petrou
133

Począwszy od wersji 0.11.0, kolumny mogą być pocięte na plasterki w sposób, w jaki próbowałeś użyć .locindeksatora:

df.loc[:, 'C':'E']

jest równoważne z

df[['C', 'D', 'E']]  # or df.loc[:, ['C', 'D', 'E']]

i zwraca kolumny Cprzez E.


Demo na losowo generowanej DataFrame:

import pandas as pd
import numpy as np
np.random.seed(5)
df = pd.DataFrame(np.random.randint(100, size=(100, 6)), 
                  columns=list('ABCDEF'), 
                  index=['R{}'.format(i) for i in range(100)])
df.head()

Out: 
     A   B   C   D   E   F
R0  99  78  61  16  73   8
R1  62  27  30  80   7  76
R2  15  53  80  27  44  77
R3  75  65  47  30  84  86
R4  18   9  41  62   1  82

Aby uzyskać kolumny od C do E (zwróć uwagę, że w przeciwieństwie do krojenia na liczby całkowite, w kolumnach znajduje się „E”):

df.loc[:, 'C':'E']

Out: 
      C   D   E
R0   61  16  73
R1   30  80   7
R2   80  27  44
R3   47  30  84
R4   41  62   1
R5    5  58   0
...

To samo działa w przypadku wybierania wierszy na podstawie etykiet. Uzyskaj wiersze „R6” do „R10” z tych kolumn:

df.loc['R6':'R10', 'C':'E']

Out: 
      C   D   E
R6   51  27  31
R7   83  19  18
R8   11  67  65
R9   78  27  29
R10   7  16  94

.locakceptuje również tablicę boolowską, dzięki czemu można wybrać kolumny, których odpowiadający wpis w tablicy to True. Na przykład df.columns.isin(list('BCD'))zwraca array([False, True, True, True, False, False], dtype=bool)- Prawda, jeśli nazwa kolumny znajduje się na liście ['B', 'C', 'D']; W przeciwnym razie fałszywe.

df.loc[:, df.columns.isin(list('BCD'))]

Out: 
      B   C   D
R0   78  61  16
R1   27  30  80
R2   53  80  27
R3   65  47  30
R4    9  41  62
R5   78   5  58
...
ayhan
źródło
110

Zakładając, że masz nazwy kolumn ( df.columns) ['index','a','b','c'], to dane, które chcesz, znajdują się w trzeciej i czwartej kolumnie. Jeśli nie znasz ich nazw podczas działania skryptu, możesz to zrobić

newdf = df[df.columns[2:4]] # Remember, Python is 0-offset! The "3rd" entry is at slot 2.

Jak wskazuje EMS w swojej odpowiedzi , df.ixwycina kolumny nieco bardziej zwięźle, ale .columnsinterfejs krojenia może być bardziej naturalny, ponieważ wykorzystuje składnię indeksowania / krojenia list waniliowych 1-D.

OSTRZEŻENIE: 'index'to zła nazwa DataFramekolumny. Ta sama etykieta jest również używana dla rzeczywistego df.indexatrybutu, Indextablicy. Twoja kolumna jest zwracana przez, df['index']a rzeczywisty indeks DataFrame jest zwracany przez df.index. An Indexjest specjalnym rodzajem Serieszoptymalizowanym do wyszukiwania wartości jego elementów. W przypadku df.index służy do wyszukiwania wierszy według ich etykiety. Ten df.columnsatrybut jest również pd.Indextablicą służącą do wyszukiwania kolumn według ich etykiet.

płyty grzewcze
źródło
3
Jak zauważono w komentarzu powyżej moim, .ixjest nie tylko dla wierszy. Służy do krojenia ogólnego i może być używany do krojenia wielowymiarowego. Jest to po prostu interfejs do zwykłej __getitem__składni NumPy . Mimo to, można łatwo przekonwertować problem kolumny krojenia do krojenia problemu wiersz po prostu stosując operację transpozycji df.T. Twój przykład wykorzystuje columns[1:3], co jest nieco mylące. Wynikiem columnsjest Series; uważaj, aby nie traktować go jak tablicy. Powinieneś też zmienić tę opcję, columns[2:3]aby dopasować ją do komentarza „3 i 4”.
ely
@ Mr.F: Mój [2:4]jest poprawny. Twój [2:3]jest zły. A użycie standardowej notacji krojenia Pythona do generowania sekwencji / Serii nie wprowadza w błąd IMO. Ale podoba mi się obejście interfejsu DataFrame w celu uzyskania dostępu do podstawowej tablicy numpy ix.
płyty grzewcze
Masz rację w tym przypadku, ale chciałem nadmienić, że ogólnie rzecz biorąc, krojenie za pomocą etykiet w Pandach obejmuje punkt końcowy plasterka (a przynajmniej takie było zachowanie w większości poprzednich wersji Pandas). Więc jeśli pobierzesz df.columnsi chcesz pokroić go według etykiety , wówczas będziesz miał inną semantykę cięcia niż gdybyś pokroić według pozycji indeksu liczb całkowitych . Jednak zdecydowanie nie wyjaśniłem tego dobrze w poprzednim komentarzu.
ely
Ach, teraz rozumiem twój punkt widzenia. Zapomniałem, że columnsto niezmienna seria, a getter został nadpisany, aby używać etykiet jako indeksów. Dziękujemy za poświęcenie czasu na wyjaśnienie.
płyty grzewcze
2
Uwaga Ostrzeżenie o wycofaniu: .ix jest przestarzałe. Dlatego ma to sens: newdf = df [df.columns [2: 4]]
Martien Lubberink
64
In [39]: df
Out[39]: 
   index  a  b  c
0      1  2  3  4
1      2  3  4  5

In [40]: df1 = df[['b', 'c']]

In [41]: df1
Out[41]: 
   b  c
0  3  4
1  4  5
Wes McKinney
źródło
1
Co jeśli chciałbym zmienić nazwę kolumny, na przykład coś takiego: df[['b as foo', 'c as bar']tak, że wyjście zmienia nazwę kolumny bjako fooi kolumny cjako bar?
kuanb
5
df[['b', 'c']].rename(columns = {'b' : 'foo', 'c' : 'bar'})
Greg,
61

Zdaję sobie sprawę, że to pytanie jest dość stare, ale w najnowszej wersji pand istnieje prosty sposób, aby to zrobić. Nazwy kolumn (które są ciągami znaków) można kroić w dowolny sposób.

columns = ['b', 'c']
df1 = pd.DataFrame(df, columns=columns)
zerovector
źródło
6
Można to zrobić tylko podczas tworzenia. Pytanie brzmi, czy masz go już w ramce danych.
Banjocat
2
@ Banjocat, działa z istniejącą ramką danych
mhery
23

Możesz podać listę kolumn do usunięcia i zwrócić DataFrame z potrzebnymi tylko kolumnami przy użyciu drop()funkcji Pandas DataFrame.

Tylko mówię

colsToDrop = ['a']
df.drop(colsToDrop, axis=1)

zwróci DataFrame tylko z kolumnami bi c.

dropMetoda udokumentowane tutaj .

Muthu Chithambara Jothi
źródło
23

Z pandami,

nazwy kolumn dowcipu

dataframe[['column1','column2']]

aby wybrać według iloc i określonych kolumn o numerze indeksu:

dataframe.iloc[:,[1,2]]

z loc nazwy kolumn mogą być używane jak

dataframe.loc[:,['column1','column2']]
Vivek Ananthan
źródło
20

Uważam, że ta metoda jest bardzo przydatna:

# iloc[row slicing, column slicing]
surveys_df.iloc [0:3, 1:4]

Więcej informacji można znaleźć tutaj

Alvis
źródło
Jak weźmiesz, powiedzmy, tylko kolumny 2 i 5?
324
1
To by było surveys_df.iloc [:, [2,5]]wtedy.
Julian Gorfer
15

Począwszy od 0.21.0, używanie .loclub []z listą z jedną lub kilkoma brakującymi etykietami jest przestarzałe na korzyść .reindex. Tak więc odpowiedź na twoje pytanie brzmi:

df1 = df.reindex(columns=['b','c'])

W poprzednich wersjach używanie .loc[list-of-labels]działało tak długo, jak znaleziono przynajmniej 1 klucz (w przeciwnym razie powodowałoby powstanie a KeyError). To zachowanie jest przestarzałe i teraz wyświetla komunikat ostrzegawczy. Zalecaną alternatywą jest użycie .reindex().

Przeczytaj więcej na stronie Indeksowanie i wybieranie danych

tozCSS
źródło
10

Możesz użyć pand. Tworzę DataFrame:

    import pandas as pd
    df = pd.DataFrame([[1, 2,5], [5,4, 5], [7,7, 8], [7,6,9]], 
                      index=['Jane', 'Peter','Alex','Ann'],
                      columns=['Test_1', 'Test_2', 'Test_3'])

DataFrame:

           Test_1  Test_2  Test_3
    Jane        1       2       5
    Peter       5       4       5
    Alex        7       7       8
    Ann         7       6       9

Aby wybrać 1 lub więcej kolumn według nazwy:

    df[['Test_1','Test_3']]

           Test_1  Test_3
    Jane        1       5
    Peter       5       5
    Alex        7       8
    Ann         7       9

Możesz także użyć:

    df.Test_2

I dostaniesz kolumnę Test_2

    Jane     2
    Peter    4
    Alex     7
    Ann      6

Możesz także wybrać kolumny i wiersze z tych wierszy za pomocą .loc(). Nazywa się to „krojeniem” . Zauważ, że zabieram z kolumny Test_1doTest_3

    df.loc[:,'Test_1':'Test_3']

„Kromka” to:

            Test_1  Test_2  Test_3
     Jane        1       2       5
     Peter       5       4       5
     Alex        7       7       8
     Ann         7       6       9

A jeśli chcesz Peteri tylko Annz kolumn Test_1i Test_3:

    df.loc[['Peter', 'Ann'],['Test_1','Test_3']]

Dostajesz:

           Test_1  Test_3
    Peter       5       5
    Ann         7       9
różowy.slash
źródło
8

Jeśli chcesz uzyskać jeden element według indeksu wierszy i nazwy kolumny, możesz to zrobić podobnie df['b'][0]. To jest tak proste, jak możesz sobie wyobrazić.

Lub możesz użyć df.ix[0,'b']mieszanego użycia indeksu i etykiety.

Uwaga: Od wersji 2.0.20 ixjest przestarzałe na rzecz loc/ iloc.

W.Perrin
źródło
6

Jedno inne i łatwe podejście: powtarzanie wierszy

używając iterow

 df1= pd.DataFrame() #creating an empty dataframe
 for index,i in df.iterrows():
    df1.loc[index,'A']=df.loc[index,'A']
    df1.loc[index,'B']=df.loc[index,'B']
    df1.head()
Ankita
źródło
5
Nie zaleca się używania iterrows (). Jest rażącym narzędziem najgorszego anty-wzoru w historii pand.
cs95
Czy mógłbyś wyjaśnić, co rozumiesz przez „najgorszy anty-wzór”?
Ankita,
1
IMHO, iterrows () powinna być ostatnią opcją przy korzystaniu z pand.
Elf
5

Różne podejścia omówione w powyższych odpowiedziach opierają się na założeniu, że albo użytkownik zna indeksy kolumn, które należy upuścić lub podzbiór, albo użytkownik chce podzestawić ramkę danych przy użyciu zakresu kolumn (na przykład między „C”: „E”) . pandas.DataFrame.drop () jest z pewnością opcja podzbiór danych na podstawie listy kolumn zdefiniowanych przez użytkownika (chociaż trzeba być ostrożnym, aby zawsze używać kopię dataframe i Ustalone parametry nie powinna być ustawiona na wartość True !!)

Inną opcją jest użycie pandas.columns.difference () , która robi różnicę w nazwach kolumn i zwraca typ indeksu tablicy zawierającej pożądane kolumny. Oto rozwiązanie:

df = pd.DataFrame([[2,3,4],[3,4,5]],columns=['a','b','c'],index=[1,2])
columns_for_differencing = ['a']
df1 = df.copy()[df.columns.difference(columns_for_differencing)]
print(df1)

Dane wyjściowe będą: b c 1 3 4 2 4 5

Harshit
źródło
1
Kopiowanie () nie jest konieczne. tzn .: df1 = df[df.columns.difference(columns_for_differencing)]zwróci nową / skopiowaną ramkę danych. Będziesz mógł modyfikować df1bez zmian df. Dziękuję, btw. Właśnie tego potrzebowałem.
Bazyli Dębowski,
4

możesz także użyć df.pop ()

>>> df = pd.DataFrame([('falcon', 'bird',    389.0),
...                    ('parrot', 'bird',     24.0),
...                    ('lion',   'mammal',   80.5),
...                    ('monkey', 'mammal', np.nan)],
...                   columns=('name', 'class', 'max_speed'))
>>> df
     name   class  max_speed
0  falcon    bird      389.0
1  parrot    bird       24.0
2    lion  mammal       80.5
3  monkey  mammal 

>>> df.pop('class')
0      bird
1      bird
2    mammal
3    mammal
Name: class, dtype: object

>>> df
     name  max_speed
0  falcon      389.0
1  parrot       24.0
2    lion       80.5
3  monkey        NaN

daj mi znać, jeśli to ci pomoże, użyj df.pop (c)

Puneet Sinha
źródło
3

Widziałem kilka odpowiedzi na ten temat, ale pozostały mi niejasne. Jak wybrałbyś te interesujące kolumny? Odpowiedź brzmi: jeśli masz je zebrane na liście, możesz po prostu odwoływać się do kolumn za pomocą listy.

Przykład

print(extracted_features.shape)
print(extracted_features)

(63,)
['f000004' 'f000005' 'f000006' 'f000014' 'f000039' 'f000040' 'f000043'
 'f000047' 'f000048' 'f000049' 'f000050' 'f000051' 'f000052' 'f000053'
 'f000054' 'f000055' 'f000056' 'f000057' 'f000058' 'f000059' 'f000060'
 'f000061' 'f000062' 'f000063' 'f000064' 'f000065' 'f000066' 'f000067'
 'f000068' 'f000069' 'f000070' 'f000071' 'f000072' 'f000073' 'f000074'
 'f000075' 'f000076' 'f000077' 'f000078' 'f000079' 'f000080' 'f000081'
 'f000082' 'f000083' 'f000084' 'f000085' 'f000086' 'f000087' 'f000088'
 'f000089' 'f000090' 'f000091' 'f000092' 'f000093' 'f000094' 'f000095'
 'f000096' 'f000097' 'f000098' 'f000099' 'f000100' 'f000101' 'f000103']

Mam następującą tablicę list / numpy extracted_features, określającą 63 kolumny. Oryginalny zestaw danych ma 103 kolumny i chciałbym wyodrębnić dokładnie te, a następnie użyłbym

dataset[extracted_features]

I skończysz z tym

wprowadź opis zdjęcia tutaj

Tego często używasz w uczeniu maszynowym (a dokładniej w wyborze funkcji). Chciałbym również omówić inne sposoby, ale myślę, że zostały już omówione przez inne kwiaty stosu. Mam nadzieję, że to było pomocne!

Kareem Jeiroudi
źródło
1

Możesz użyć pandas.DataFrame.filtermetody do filtrowania lub zmiany kolejności kolumn w następujący sposób:

df1 = df.filter(['a', 'b'])
Ramin Melikov
źródło
0
df[['a','b']] # select all rows of 'a' and 'b'column 
df.loc[0:10, ['a','b']] # index 0 to 10 select column 'a' and 'b'
df.loc[0:10, ['a':'b']] # index 0 to 10 select column 'a' to 'b'
df.iloc[0:10, 3:5] # index 0 to 10 and column 3 to 5
df.iloc[3, 3:5] # index 3 of column 3 to 5
Biplob Das
źródło