W Pandas, kiedy wybieram etykietę, która ma tylko jeden wpis w indeksie, otrzymuję z powrotem serię, ale kiedy wybieram wpis, który ma więcej niż jeden wpis, otrzymuję ramkę danych.
Dlaczego? Czy istnieje sposób, aby zawsze odzyskać ramkę danych?
In [1]: import pandas as pd
In [2]: df = pd.DataFrame(data=range(5), index=[1, 2, 3, 3, 3])
In [3]: type(df.loc[3])
Out[3]: pandas.core.frame.DataFrame
In [4]: type(df.loc[1])
Out[4]: pandas.core.series.Series
KeyError
gdy próbuję.loc[[nonexistent_label]]
..loc
jest znacznie wolniejsze niż bez niej. Aby nadal był czytelny, ale także znacznie szybszy, lepszy w użyciudf.loc[1:1]
Masz indeks z trzema elementami indeksu
3
. Z tego powodudf.loc[3]
zwróci ramkę danych.Powodem jest to, że nie określasz kolumny.
df.loc[3]
Wybiera więc trzy elementy ze wszystkich kolumn (czyli kolumnę0
), adf.loc[3,0]
zwróci Series. Np.df.loc[1:2]
Zwraca również ramkę danych, ponieważ tniesz wiersze.Wybranie pojedynczego wiersza (jako
df.loc[1]
) zwraca serię z nazwami kolumn jako indeksem.Jeśli chcesz mieć pewność, że zawsze masz DataFrame, możesz pokroić w podobny sposób
df.loc[1:1]
. Inną opcją jest indeksowanie boolowskie (df.loc[df.index==1]
) lub metoda take (df.take([0])
ale ta lokalizacja nie zawiera etykiet!).źródło
Użyj,
df['columnName']
aby otrzymać serię idf[['columnName']]
otrzymać Dataframe.źródło
TLDR
Podczas używania
loc
df.loc[:]
= Dataframedf.loc[int]
= Dataframe, jeśli masz więcej niż jedną kolumnę i serie, jeśli masz tylko jedną kolumnę w ramce danychdf.loc[:, ["col_name"]]
= Dataframedf.loc[:, "col_name"]
= SeriaNie używam
loc
df["col_name"]
= Seriadf[["col_name"]]
= Dataframeźródło
W komentarzu do odpowiedzi Jorisa napisałeś:
Pojedynczy wiersz nie jest konwertowany w serii.
To JEST Seria:
No, I don't think so, in fact; see the edit
Model danych obiektów Pandy został wybrany w ten sposób. Przyczyna na pewno tkwi w tym, że zapewnia pewne korzyści, których nie znam (nie do końca rozumiem ostatnie zdanie cytatu, może to jest powód)
.
Edycja: Nie zgadzam się ze mną
DataFrame nie mogą składać się z elementów, które mogłyby być Series, ponieważ po kod daje ten sam typ „seria”, jak również do rzędu, jak dla kolumny:
import pandas as pd df = pd.DataFrame(data=[11,12,13], index=[2, 3, 3]) print '-------- df -------------' print df print '\n------- df.loc[2] --------' print df.loc[2] print 'type(df.loc[1]) : ',type(df.loc[2]) print '\n--------- df[0] ----------' print df[0] print 'type(df[0]) : ',type(df[0])
wynik
-------- df ------------- 0 2 11 3 12 3 13 ------- df.loc[2] -------- 0 11 Name: 2, dtype: int64 type(df.loc[1]) : <class 'pandas.core.series.Series'> --------- df[0] ---------- 2 11 3 12 3 13 Name: 0, dtype: int64 type(df[0]) : <class 'pandas.core.series.Series'>
Nie ma więc sensu udawać, że DataFrame składa się z Series, ponieważ czym powinny być te serie: kolumny czy wiersze? Głupie pytanie i wizja.
.
Więc co to jest DataFrame?
W poprzedniej wersji tej odpowiedzi zadałem to pytanie, próbując znaleźć odpowiedź na
Why is that?
część pytania PO i podobne przesłuchaniesingle rows to get converted into a series - why not a data frame with one row?
w jednym z jego komentarzy,podczas gdy na tę
Is there a way to ensure I always get back a data frame?
część odpowiedział Dan Allan.Następnie, jak cytowane powyżej dokumenty Pand mówią, że struktury danych pand są najlepiej postrzegane jako pojemniki z danymi niższych wymiarów, wydawało mi się, że zrozumienie przyczyny można znaleźć w charakterystyce struktur DataFrame.
Jednak zdałem sobie sprawę, że tej cytowanej rady nie można traktować jako dokładnego opisu natury struktur danych Pand.
Ta rada nie oznacza, że DataFrame jest kontenerem serii.
Wyraża, że mentalna reprezentacja ramki DataFrame jako kontenera serii (wiersze lub kolumny zgodnie z opcją rozważaną w jednym momencie rozumowania) jest dobrym sposobem na rozważenie ramek DataFrame, nawet jeśli w rzeczywistości tak nie jest. „Dobra” oznacza, że ta wizja umożliwia efektywne korzystanie z ramek DataFrames. To wszystko.
.
Co to jest obiekt DataFrame?
DataFrame klasa wytwarza przykładów, które mają szczególną strukturą pochodzi z NDFrame klasy bazowej sam pochodzi z PandasContainer klasy bazowej, która ma również klasa dominującą serii klasy.
Zauważ, że jest to poprawne dla Pand do wersji 0.12. W nadchodzącej wersji 0.13 Series będzie również wywodzić się tylko z klasy NDFrame .
# with pandas 0.12 from pandas import Series print 'Series :\n',Series print 'Series.__bases__ :\n',Series.__bases__ from pandas import DataFrame print '\nDataFrame :\n',DataFrame print 'DataFrame.__bases__ :\n',DataFrame.__bases__ print '\n-------------------' from pandas.core.generic import NDFrame print '\nNDFrame.__bases__ :\n',NDFrame.__bases__ from pandas.core.generic import PandasContainer print '\nPandasContainer.__bases__ :\n',PandasContainer.__bases__ from pandas.core.base import PandasObject print '\nPandasObject.__bases__ :\n',PandasObject.__bases__ from pandas.core.base import StringMixin print '\nStringMixin.__bases__ :\n',StringMixin.__bases__
wynik
Series : <class 'pandas.core.series.Series'> Series.__bases__ : (<class 'pandas.core.generic.PandasContainer'>, <type 'numpy.ndarray'>) DataFrame : <class 'pandas.core.frame.DataFrame'> DataFrame.__bases__ : (<class 'pandas.core.generic.NDFrame'>,) ------------------- NDFrame.__bases__ : (<class 'pandas.core.generic.PandasContainer'>,) PandasContainer.__bases__ : (<class 'pandas.core.base.PandasObject'>,) PandasObject.__bases__ : (<class 'pandas.core.base.StringMixin'>,) StringMixin.__bases__ : (<type 'object'>,)
Dlatego teraz rozumiem, że instancja DataFrame ma pewne metody, które zostały utworzone w celu kontrolowania sposobu wyodrębniania danych z wierszy i kolumn.
Sposoby działania tych metod wyodrębniania są opisane na tej stronie: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing
Znajdujemy w niej metodę podaną przez Dana Allana i inne metody.
Dlaczego te metody ekstrakcji zostały stworzone tak, jak były?
Z pewnością dlatego, że zostały one ocenione jako dające lepsze możliwości i łatwość w analizie danych.
Dokładnie to wyraża to zdanie:
Dlaczego ekstrakcji danych z instancji DataFRame nie leży w jej strukturze, leży w dlaczego tej struktury. Wydaje mi się, że struktura i funkcjonowanie struktury danych Pand zostały wyrzeźbione tak, aby były jak najbardziej intuicyjne intelektualnie, a żeby zrozumieć szczegóły, trzeba przeczytać blog Wesa McKinneya.
źródło
Jeśli celem jest uzyskanie podzbioru zbioru danych za pomocą indeksu, najlepiej unikać używania
loc
lubiloc
. Zamiast tego powinieneś użyć składni podobnej do tej:df = pd.DataFrame(data=range(5), index=[1, 2, 3, 3, 3]) result = df[df.index == 3] isinstance(result, pd.DataFrame) # True result = df[df.index == 1] isinstance(result, pd.DataFrame) # True
źródło
Jeśli zaznaczysz również indeks ramki danych, wynikiem może być DataFrame lub Series lub może to być Series lub skalar (pojedyncza wartość).
Ta funkcja zapewnia, że zawsze otrzymasz listę z twojego wyboru (jeśli df, indeks i kolumna są prawidłowe):
def get_list_from_df_column(df, index, column): df_or_series = df.loc[index,[column]] # df.loc[index,column] is also possible and returns a series or a scalar if isinstance(df_or_series, pd.Series): resulting_list = df_or_series.tolist() #get list from series else: resulting_list = df_or_series[column].tolist() # use the column key to get a series from the dataframe return(resulting_list)
źródło