В Pandas, когда я выбираю метку, которая имеет только одну запись в индексе, я возвращаю серию, но когда я выбираю запись, которая имеет более одной записи, я возвращаю фрейм данных.
Почему это? Есть ли способ гарантировать, что я всегда получу фрейм данных?
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
когда пытаюсь.loc[[nonexistent_label]]
..loc
намного медленнее, чем без него. Чтобы было по-прежнему читаемым, но при этом гораздо быстрее, лучше использоватьdf.loc[1:1]
У вас есть индекс с тремя элементами индекса
3
. По этой причинеdf.loc[3]
вернет фрейм данных.Причина в том, что вы не указываете столбец. Итак,
df.loc[3]
выбирает три элемента из всех столбцов (это столбец0
), аdf.loc[3,0]
вернет Series. Например,df.loc[1:2]
также возвращает фрейм данных, потому что вы нарезаете строки.Выбор одной строки (как
df.loc[1]
) возвращает серию с именами столбцов в качестве индекса.Если вы хотите быть уверены, что у вас всегда есть DataFrame, вы можете нарезать как
df.loc[1:1]
. Другой вариант - это логическое индексирование (df.loc[df.index==1]
) или метод take (df.take([0])
но это используемое местоположение, а не метки!).источник
Используйте
df['columnName']
для получения серии иdf[['columnName']]
для получения фрейма данных.источник
TLDR
Когда используешь
loc
df.loc[:]
= Фрейм данныхdf.loc[int]
= Dataframe, если у вас более одного столбца, и Series, если у вас только 1 столбец в dataframedf.loc[:, ["col_name"]]
= Фрейм данныхdf.loc[:, "col_name"]
= СерияНе используя
loc
df["col_name"]
= Серияdf[["col_name"]]
= Фрейм данныхисточник
В комментарии к ответу Джориса вы написали:
Одна строка не преобразуется в серию.
Это IS Серия:
No, I don't think so, in fact; see the edit
Так была выбрана модель данных объектов Pandas. Причина, безусловно, заключается в том, что он обеспечивает некоторые преимущества, о которых я не знаю (я не полностью понимаю последнее предложение цитаты, возможно, это причина)
.
Изменить: я не согласен со мной
DataFrame не может состоять из элементов, которые были бы Series, потому что следующий код дает тот же тип «Series» как для строки, так и для столбца:
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])
результат
-------- 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'>
Итак, нет смысла притворяться, что DataFrame состоит из Series, потому что чем должны быть эти упомянутые Series: столбцами или строками? Глупый вопрос и видение.
.
Тогда что такое DataFrame?
В предыдущей версии этого ответа я задавал этот вопрос, пытаясь найти ответ на
Why is that?
часть вопроса ОП и аналогичного допросаsingle rows to get converted into a series - why not a data frame with one row?
в одном из его комментариев, вто время как
Is there a way to ensure I always get back a data frame?
часть ответил Дэн Аллан.Затем, поскольку документы Pandas, процитированные выше, говорят, что структуры данных pandas лучше всего рассматривать как контейнеры низкоразмерных данных, мне казалось, что понимание причины можно найти в характеристиках природы структур DataFrame.
Однако я понял, что этот процитированный совет не следует воспринимать как точное описание природы структур данных Pandas.
Этот совет не означает, что DataFrame является контейнером Series.
Он выражает то, что мысленное представление DataFrame как контейнера Series (строк или столбцов в соответствии с вариантом, рассматриваемым в один момент рассуждения) - хороший способ рассмотреть DataFrames, даже если это не совсем так в действительности. «Хорошо» означает, что это видение позволяет эффективно использовать DataFrames. Вот и все.
.
Тогда что такое объект DataFrame?
Класс DataFrame создает экземпляры, имеющие определенную структуру, происходящую из базового класса NDFrame , который сам является производным от базового класса PandasContainer, который также является родительским классом класса Series .
Обратите внимание, что это верно для Pandas до версии 0.12. В следующей версии 0.13 Series будет производным только от класса 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__
результат
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'>,)
Итак, я понимаю, что теперь экземпляр DataFrame имеет определенные методы, которые были созданы для управления способом извлечения данных из строк и столбцов.
Принципы работы этих методов извлечения описаны на этой странице: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing В нем
мы находим метод, данный Дэном Алланом, и другие методы.
Почему эти методы извлечения созданы именно так?
Это определенно потому, что они были оценены как те, которые предоставляют лучшие возможности и легкость анализа данных.
Именно это выражено в этом предложении:
Почему экстракции данных из экземпляра DataFRame не лежит в его структуре, она лежит в почему этой структуры. Я предполагаю, что структура и функционирование структуры данных Pandas были тщательно продуманы, чтобы быть максимально интуитивно понятными, и что для понимания деталей нужно прочитать блог Уэса МакКинни.
источник
Если цель состоит в том, чтобы получить подмножество набора данных с помощью индекса, лучше избегать использования
loc
илиiloc
. Вместо этого вы должны использовать синтаксис, подобный этому: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
источник
Если вы также выберете индекс фрейма данных, результатом может быть либо DataFrame, либо серия, либо серия или скаляр (одно значение).
Эта функция гарантирует, что вы всегда получите список из вашего выбора (если df, index и column действительны):
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)
источник