ラベルで選択したパンダは時々シリーズを返し、時々DataFrameを返します


95

パンダでは、インデックスにエントリが1つしかないラベルを選択するとシリーズが返されますが、エントリが1つ以上あるエントリを選択すると、データフレームが返されます。

何故ですか?常にデータフレームを確実に取得する方法はありますか?

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

回答:


101

動作に一貫性がないことは確かですが、これが便利な場合を想像するのは簡単だと思います。とにかく、毎回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

6
ありがとう。ラベルがインデックスにない場合でもDataFrameを返すことに注意してください。
求職者2013

7
重複しないインデックスと単一のインデクサー(たとえば、単一のラベル)を使用する場合、DataFrameであるインデックスに重複があるため、常にシリーズが返されます。
ジェフ

1
さらに別の問題があることに注意してください:提案された回避策を使用していて、一致する行がない場合、結果は単一の行、すべてNaNを持つDataFrameになります。
ポールオイスター

2
ポール、使用しているパンダのバージョンは?最新バージョンでは、KeyError試してみるとが表示され.loc[[nonexistent_label]]ます。
Dan Allan

2
リストを使用すると、リストを使用し.locない場合よりもはるかに遅くなります。読みやすくするだけでなく、より速く、より適切に使用するにはdf.loc[1:1]
Jonathan

15

3つのインデックス項目を持つインデックスがあります3。このためdf.loc[3]、データフレームを返します。

その理由は、列を指定しないためです。したがってdf.loc[3]、すべての列(column 0)の3つのアイテムを選択します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])ですが、これはラベルではなく場所を使用しました!)です。


3
それは私が期待する行動です。単一の行をシリーズに変換するための設計上の決定を理解していません-なぜ1行のデータフレームがないのですか?
jobevers 2013

ああ、なぜ単一の行を選択するとシリーズが返されるのか、私にはよくわかりません。
joris

6

TLDR

使用する場合 loc

df.loc[:]= データフレーム

df.loc[int]= データフレームあなたは複数のカラムと持っている場合はシリーズを使用すると、データフレーム内の唯一の1列を持っている場合

df.loc[:, ["col_name"]]= データフレーム

df.loc[:, "col_name"]= シリーズ

使用していない loc

df["col_name"]= シリーズ

df[["col_name"]]= データフレーム


5

df['columnName']シリーズdf[['columnName']]を取得し、データフレームを取得するために使用します。


1
元のdfのコピーを取ることに注意してください。
smci

3

jorisの回答にコメントを書き込んだ:

「単一の行をシリーズに変換するための設計上の決定を理解していません。なぜ1行のデータフレームでないのですか?」

1つの行はシリーズでは変換されません。
これは、ISシリーズ: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オブジェクトのデータモデルは、そのように選択されています。その理由は確かに、私が知らないいくつかの利点を保証するという事実にあります(引用の最後の文を完全に理解していない、それが理由かもしれません)。

編集:同意しません

次のコードは、行と列で同じタイプ「Series」を提供するため、DataFrameを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'>

したがって、これらのSeriesは列または行であると想定されているため、DataFrameがSeriesで構成されているように見せかけるのは意味がありません。愚かな質問とビジョン。

次に、DataFrameとは何ですか?

この回答の以前のバージョンでWhy is that?は、OPの質問の一部に対する回答と同様の質問single rows to get converted into a series - why not a data frame with one row?が彼のコメントの1つで見つかるようにこの質問
をしましたが、Is there a way to ensure I always get back a data frame?一部はDan Allanによって回答されています。

次に、上記のパンダのドキュメントでパンダのデータ構造が低次元データのコンテナとして最もよく見られると述べているように、DataFrame構造の性質の特徴にその理由が理解されているように思えました。

しかしながら、私はこの引用されたアドバイスがパンダのデータ構造の性質の正確な説明として取られるべきではないことに気づきました。
このアドバイスは、DataFrameがシリーズのコンテナーであることを意味するものではありません。
それは、実際には厳密には当てはまらない場合でも、シリーズのコンテナーとしてのDataFrameのメンタル表現(推論のある瞬間に考慮されるオプションに応じて行または列のいずれか)がDataFrameを検討する良い方法であることを示しています。「良い」とは、このビジョンによってDataFrameを効率的に使用できるようになることを意味します。それで全部です。

次に、DataFrameオブジェクトとは何ですか?

データフレームのクラスは、特定の構造は、に由来しているインスタンス生成NDFrameの基本クラスを、自身が由来する PandasContainerのもの親クラスであるベースクラスシリーズクラス。
これは、バージョン0.12までのPandasでは正しいことに注意してください。次のバージョン0.13では、SeriesNDFrameクラスのみからも派生します。

# 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のデータ構造の構造と機能は、可能な限り知的に直感的に理解できるように彫られており、詳細を理解するには、Wes McKinneyのブログを読む必要があると思います。


1
ちなみに、DataFrameはndarrayサブクラスではなく、Seriesでもありません(0.13から始まりますが、その前は)。これらは何よりも口述のようなものです。
ジェフ

お知らせいただきありがとうございます。私はパンダの学習に新しいので本当に感謝しています。しかし、よく理解するにはさらに情報が必要です。ドキュメントにシリーズがndarrayのサブクラスであると書かれているのはなぜですか?
eyquem 2013

0.13以前(まもなくリリースされます)でした
Jeff

OK。どうもありがとうございました。しかし、それは私の推論と理解の根拠を変えません、そうですか?-0.13よりも下位のPandasでは、DataFrameおよび他のPandaのオブジェクトはSeriesとは異なります。それらのサブクラスは何ですか?
eyquem 2013

@ジェフありがとうございます。私はあなたの情報の後で私の答えを修正しました。あなたが私の編集についてどう思うか知りたいです。
eyquem 2013

1

インデックスを使用してデータセットのサブセットを取得することが目的の場合は、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

0

あなたはまた、データフレームのインデックスに選択した場合、結果はデータフレームまたはシリーズのいずれかになります、それはシリーズまたはスカラー(単一の値)とすることができます。

この関数は、選択から常にリストを取得することを保証します(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)
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.