问题:通过标签选择的熊猫有时返回Series,有时返回DataFrame
在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
回答 0
可以肯定的是,这种行为是不一致的,但是我认为很容易想到这种情况是方便的。无论如何,要每次获取一个DataFrame,只需将一个列表传递给即可loc
。还有其他方法,但我认为这是最干净的方法。
In [2]: type(df.loc[[3]])
Out[2]: pandas.core.frame.DataFrame
In [3]: type(df.loc[[1]])
Out[3]: pandas.core.frame.DataFrame
回答 1
您有一个包含三个索引项的索引3
。因此,df.loc[3]
将返回一个数据帧。
原因是您未指定列。因此,df.loc[3]
选择所有列中的三个项目(即column 0
),同时df.loc[3,0]
将返回一个Series。例如df.loc[1:2]
,由于对行进行了切片,因此它还会返回一个数据框。
选择单个行(如df.loc[1]
)将返回一个以列名作为索引的Series。
如果要确保始终有一个DataFrame,可以像这样切片df.loc[1:1]
。另一个选项是布尔索引(df.loc[df.index==1]
)或take方法(df.take([0])
,但是此使用的位置不是标签!)。
回答 2
TLDR
使用时 loc
df.loc[:]
=数据框
df.loc[int]
=数据框(如果您有多于一列)和系列(如果您在数据框中只有一列)
df.loc[:, ["col_name"]]
=数据框
df.loc[:, "col_name"]
= 系列
不使用 loc
df["col_name"]
= 系列
df[["col_name"]]
=数据框
回答 3
使用df['columnName']
得到一个系列,并df[['columnName']]
得到一个数据帧。
回答 4
您在评论joris的答案中写道:
“我不理解将单行转换为系列的设计决策-为什么不将一行数据框呢?”
单行不会在系列中转换。
它是一个系列:No, I don't think so, in fact; see the edit
考虑熊猫数据结构的最佳方法是将其作为低维数据的灵活容器。例如,DataFrame是Series的容器,Panel是DataFrame对象的容器。我们希望能够以类似字典的方式从这些容器中插入和删除对象。
http://pandas.pydata.org/pandas-docs/stable/overview.html#why-more-than-1-data-structure
这样选择了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?
OP问题部分的答案以及类似的审问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?
Dan Allan 对此部分做了回答。
然后,正如上面引用的Pandas的文档所述,最好将Pandas的数据结构看作是低维数据的容器,在我看来,对为什么的理解可以从DataFrame结构的性质中找到。
但是,我意识到,不应将引用的建议作为对熊猫数据结构本质的精确描述。
此建议并不意味着DataFrame是Series的容器。
它表示,将DataFrame作为Series的容器的心理表示形式(根据推理的某个时刻考虑的选项是行还是列)是考虑DataFrame的一种好方法,即使实际上并非严格如此。“良好”意味着该愿景可以高效地使用DataFrame。就这样。
。
那么什么是DataFrame对象?
所述数据帧类产生具有特定结构起源于实例NDFrame基类,本身从派生 PandasContainer基类,也是一个父类的系列类。
请注意,这对于0.12版之前的Pandas才是正确的。在即将发布的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
我们在其中找到了Dan Allan给出的方法和其他方法。
为什么这些提取方法是照原样制作的?
当然,这是因为它们被认为是提供更好的可能性和简化数据分析的方法。
这句话正是这样表达的:
考虑熊猫数据结构的最佳方法是将其作为低维数据的灵活容器。
该为什么数据从数据帧的实例提取的不在于它的结构,它位于为什么这种结构。我猜想,Pandas数据结构的结构和功能已经过精心设计,以便尽可能地提高智力上的直观性,并且要了解详细信息,必须阅读Wes McKinney的博客。
回答 5
如果目标是使用索引获取数据集的子集,则最好避免使用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
回答 6
如果您还选择数据框的索引,则结果可以是DataFrame或Series ,也可以是Series或标量(单个值)。
此函数可确保您始终从选择中获得列表(如果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)