web-dev-qa-db-ja.com

Pandasラベルで選択するとSeriesが返されることがあり、DataFrameが返されることがあります

パンダでは、インデックスにエントリが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
75
jobevers

振る舞いが一貫していないことは確かですが、これが便利な場合は簡単に想像できると思います。とにかく、毎回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
82
Dan Allan

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

その理由は、列を指定しないからです。したがって、_df.loc[3]_はすべての列の3つのアイテム(列_0_)を選択し、_df.loc[3,0]_はシリーズを返します。例えば。 _df.loc[1:2]_は、行をスライスするため、データフレームも返します。

(_df.loc[1]_として)単一の行を選択すると、インデックスとして列名を持つSeriesが返されます。

常にDataFrameを使用したい場合は、_df.loc[1:1]_のようにスライスできます。別のオプションは、ブールインデックス(_df.loc[df.index==1]_)またはtakeメソッド(df.take([0])ですが、これはラベルではなく場所を使用しました!)です。

13
joris

つかいます df['columnName']を取得してシリーズとdf[['columnName']]データフレームを取得します。

5
user4422

あなたはジョリスの答えにコメントを書きました:

変換してシリーズに変換する単一行の設計決定がわかりません。1行のデータフレームはどうでしょうか?」

単一の行は、シリーズではconvertedではありません。
It[〜#〜] is [〜#〜]シリーズ: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-structure

Pandasオブジェクトのデータモデルはそのように選択されています。理由は確かに、それが私が知らないいくつかの利点を保証するという事実にあります(私は最後の文を完全に理解していません引用、おそらくそれが理由です)

編集:私は同意しません

DataFrameは、beSeriesとなる要素で構成することはできません。これは、次のコードが行に対しても同じタイプの "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?彼のコメントの1つで、
Is there a way to ensure I always get back a data frame?一部はダンアランによって回答されました。

次に、上記のパンダのドキュメントが、パンダのデータ構造は低次元データのcontainersとして最もよく見られると述べているように、 whyの理解は、DataFrame構造の性質の特性にあります。

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

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

DataFrameクラスは、NDFrameに由来する特定の構造を持つインスタンスを生成しますPandasContainerから派生した基本クラスであり、Seriesクラス。
これはPandasバージョン0.12までは正しいことに注意してください。次のバージョン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
Dan Allanによって与えられた方法と他の方法を見つけます。

なぜこれらの抽出方法がそのままに作られたのですか?
それは確かに、データ分析の可能性と容易さを向上させるものとして評価されているからです。
まさにこの文で表現されているものです。

pandasデータ構造について考える最良の方法は、低次元データの柔軟なコンテナとしてです。

DataFRameインスタンスからのデータの抽出のwhyはその構造にはなく、このwhyにあります構造。パンダのデータ構造の構造と機能は、できるだけ知的に直感的になるように削られており、詳細を理解するには、Wes McKinneyのブログを読む必要があると思います。

3
eyquem

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

データフレームのインデックスも選択した場合、結果は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)
0
Wouter