按标签选择的熊猫有时会返回系列,有时会返回数据帧

job*_*ers 83 python series slice dataframe pandas

在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
Run Code Online (Sandbox Code Playgroud)

Dan*_*lan 87

假设行为不一致,但我认为很容易想象这很方便的情况.无论如何,每次都要获取一个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
Run Code Online (Sandbox Code Playgroud)

  • 仅供参考,具有非重复索引和单个索引器(例如单个标签),您将始终获得一个系列,这只是因为您在索引中有重复项,因为它是一个DataFrame. (7认同)
  • 谢谢.值得注意的是,即使标签不在索引中,这也会返回DataFrame. (3认同)
  • 保罗,你用的是什么版本的熊猫?在最新版本中,当我尝试 `.loc[[nonexistent_label]]` 时,我得到一个 `KeyError`。 (2认同)
  • 使用 `.loc` 中的列表比不使用它要慢得多。为了仍然可读但也更快,最好使用`df.loc[1:1]` (2认同)

jor*_*ris 14

您有一个包含三个索引项的索引3.因此,df.loc[3]将返回一个数据帧.

原因是您没有指定列.因此,df.loc[3]选择所有列的三个项目(即列0),同时df.loc[3,0]返回一个系列.例如,df.loc[1:2]还会返回一个数据帧,因为您对行进行切片.

选择单行(as df.loc[1])将返回一个以列名作为索引的Series.

如果你想确保总是有一个DataFrame,你可以切片df.loc[1:1].另一个选项是boolean indexing(df.loc[df.index==1])或take方法(df.take([0])但是这个使用的位置不是标签!).

  • 这就是我期望的行为.我不明白将单行转换为系列的设计决策 - 为什么不是一行数据框? (3认同)

Col*_*ony 12

TLDR

使用时 loc

df.loc[:]= 数据

df.loc[int]=如果您有不止一列,则为数据框,如果数据框中只有 1 列,则为系列

df.loc[:, ["col_name"]]=如果您有不止一行,则为数据框,如果选择中只有 1 行,则为系列

df.loc[:, "col_name"]=系列

不使用 loc

df["col_name"]=系列

df[["col_name"]]= 数据

  • 这是不正确的。如果只选择一行,`df.loc[:, ["col_name"]]` 将返回一系列。 (3认同)

eyq*_*uem 5

您在对 joris 的回答的评论中写道:

“我不明白将单行转换为一系列的设计决策 - 为什么不使用一行数据框呢?”

单个行不会转换为系列。
一个系列:No, I don't think so, in fact; see the edit

考虑 pandas 数据结构的最佳方式是将其作为低维数据的灵活容器。例如,DataFrame是Series的容器,Panel是DataFrame对象的容器。我们希望能够以类似字典的方式从这些容器中插入和删除对象。

http://pandas.pydata.org/pandas-docs/stable/overview.html#why-more-than-1-data-struct

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])
Run Code Online (Sandbox Code Playgroud)

结果

-------- 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'>
Run Code Online (Sandbox Code Playgroud)

因此,假装 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?部分已由丹·艾伦回答。

然后,正如上面引用的 Pandas 文档所说,Pandas 的数据结构最好被视为低维数据的容器,在我看来,对原因的理解可以在 DataFrame 结构的本质特征中找到。

然而,我意识到这个引用的建议不能被视为对 Pandas 数据结构性质的精确描述。
此建议并不意味着 DataFrame 是 Series 的容器。
它表示将 DataFrame 作为 Series 容器(根据推理时考虑的选项的行或列)的心理表征是考虑 DataFrame 的好方法,即使现实情况并非严格如此。“好”意味着这个愿景能够高效地使用 DataFrame。就这样。

那么什么是DataFrame对象呢?

DataFrame生成具有源自NDFrame基类的特定结构的实例,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__
Run Code Online (Sandbox Code Playgroud)

结果

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'>,)
Run Code Online (Sandbox Code Playgroud)

所以我现在的理解是,DataFrame 实例具有某些精心设计的方法,以便控制从行和列中提取数据的方式。

这些提取方法的工作方式在此页面中描述: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing
我们在其中找到了 Dan Allan 给出的方法和其他方法。

为什么要设计这些提取方法?
这当然是因为它们被认为能够提供更好的可能性和更轻松的数据分析。
正是这句话所表达的意思:

考虑 pandas 数据结构的最佳方式是将其作为低维数据的灵活容器。

从 DataFRame 实例中提取数据的原因不在于其结构,而在于该结构的原因。我猜想 Pandas 数据结构的结构和功能已经过精心设计,以便尽可能直观地理解,要了解细节,必须阅读 Wes McKinney 的博客。


use*_*422 5

使用df['columnName']得到一个系列,并df[['columnName']]得到一个数据帧。