Etikete göre seçim yapan pandalar bazen Seri döndürür, bazen DataFrame döndürür


98

Pandalarda, dizinde yalnızca bir girişi olan bir etiket seçtiğimde bir Seriyi geri alıyorum, ancak birden fazla girişi olan bir girişi seçtiğimde bir veri çerçevesi geri alıyorum.

Neden? Her zaman bir veri çerçevesini geri almamın bir yolu var mı?

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

Yanıtlar:


107

Davranışın tutarsız olduğu kabul edildi, ancak bunun uygun olduğu durumları hayal etmenin kolay olduğunu düşünüyorum. Her neyse, her seferinde bir DataFrame almak için, sadece bir liste iletin loc. Başka yollar da var ama bence bu en temiz olanı.

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
Teşekkürler. Etiket dizinde olmasa bile bunun bir DataFrame döndürdüğünü belirtmek gerekir.
jobevers

7
Bilginize, yinelenmemiş bir dizin ve tek bir dizinleyici (örneğin, tek bir etiket) ile, HER ZAMAN bir Diziyi geri alacaksınız, bunun tek nedeni, dizinde bir DataFrame olmasıdır.
Jeff

1
Yine başka bir sorun olduğuna dikkat edin: Önerilen geçici çözümü kullanıyorsanız ve eşleşen satır yoksa, sonuç, tümü NaN olan tek satırlı bir DataFrame olacaktır.
Paul Oyster

2
Paul, pandaların hangi versiyonunu kullanıyorsun? En son sürümde, KeyErrordenediğimde bir alıyorum .loc[[nonexistent_label]].
Dan Allan

2
Bir listeyi içinde kullanmak .loc, onsuzdan çok daha yavaştır. Hâlâ okunabilir olması, aynı zamanda çok daha hızlı, daha iyi kullanım içindf.loc[1:1]
Jonathan

17

Üç dizin öğesi içeren bir dizininiz var 3. Bu nedenle df.loc[3]bir veri çerçevesi döndürecektir.

Nedeni, sütunu belirtmemenizdir. Bu nedenle df.loc[3], tüm sütunların (sütun olan 0) üç öğesini seçerken df.loc[3,0], bir Seri döndürür. Örneğin df.loc[1:2], satırları dilimlediğiniz için bir veri çerçevesi de döndürür.

Tek bir satırı (as df.loc[1]) seçmek , dizin olarak sütun adlarına sahip bir Seri döndürür.

Her zaman bir DataFrame'iniz olduğundan emin olmak istiyorsanız, gibi dilimleyebilirsiniz df.loc[1:1]. Diğer bir seçenek de boole indeksleme ( df.loc[df.index==1]) veya alma yöntemidir ( df.take([0])ancak bu konum etiketleri kullanmaz!).


3
Beklediğim davranış buydu. Tek satırların bir seriye dönüştürülmesi için tasarım kararını anlamıyorum - neden tek satırlı bir veri çerçevesi olmasın?
jobevers

Ah, neden tek bir satır seçmek bir Seri döndürüyor, gerçekten bilmiyorum.
joris

7

Kullanım df['columnName']Seriyi almak ve df[['columnName']]bir Dataframe olsun.


1
Orijinal df'nin bir kopyasını alan dikkat edin.
smci

6

TLDR

Kullanırken loc

df.loc[:]= Dataframe

df.loc[int]= Dataframe , birden fazla sütununuz varsa ve veri çerçevesinde yalnızca 1 sütununuz varsa Seri

df.loc[:, ["col_name"]]= Dataframe

df.loc[:, "col_name"]= Seri

Kullanmıyor loc

df["col_name"]= Seri

df[["col_name"]]= Dataframe


3

Joris'in cevabına bir yorum yazdın:

"Tek satırların bir seriye dönüştürülmesine yönelik tasarım kararını anlamıyorum - neden tek satırlı bir veri çerçevesi olmasın?"

Tek bir satır, Serilerde dönüştürülmez .
Bir Dizidir :No, I don't think so, in fact; see the edit

Pandaların veri yapıları hakkında düşünmenin en iyi yolu, daha düşük boyutlu veriler için esnek kaplar olarak kullanmaktır. Örneğin, DataFrame, Series için bir konteynerdir ve Panel, DataFrame nesneleri için bir konteynerdir. Bu kaplardan nesneleri sözlük benzeri bir şekilde ekleyip çıkarabilmek istiyoruz.

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

Pandas nesnelerinin veri modeli bu şekilde seçilmiştir. Sebep kesinlikle bilmediğim bazı avantajlar sağlaması gerçeğinde yatmaktadır (alıntının son cümlesini tam olarak anlamıyorum, belki de nedeni budur)

.

Düzenleme: Bana katılmıyorum

Bir DataFrame olur unsurlardan oluşan edilemez olması Aşağıdaki kod aynı tür "Serisi" için de bir sütun için bir satır verir çünkü, Seri:

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])

sonuç

-------- 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'>

Dolayısıyla, bir DataFrame'in Serilerden oluştuğunu varsaymanın bir anlamı yoktur, çünkü bu Serilerin ne olması gerekir: sütunlar mı yoksa satırlar mı? Aptalca soru ve vizyon.

.

O halde DataFrame nedir?

Bu cevabın önceki sürümünde, ben cevabını bulmaya çalışırken, bu soru soruldu Why is that?OP ve benzeri sorgulama sorunun parçası single rows to get converted into a series - why not a data frame with one row?, onun yorumun birinde
ise Is there a way to ensure I always get back a data frame?parçası Dan Allan tarafından yanıtlandı.

Daha sonra, yukarıda alıntılanan Pandaların dokümanları, pandaların veri yapılarının en iyi şekilde daha düşük boyutlu verilerin kapsayıcıları olarak görüldüğünü söylediği için, bana, nedeninin anlaşılmasının DataFrame yapılarının doğasının özelliklerinde bulunabileceği gibi geldi.

Ancak, alıntılanan bu tavsiyenin Pandaların veri yapılarının doğasının kesin bir açıklaması olarak alınmaması gerektiğini fark ettim.
Bu tavsiye, DataFrame'in bir Seri kapsayıcı olduğu anlamına gelmez.
Bir DataFrame'in bir Seri kapsayıcı olarak zihinsel temsilinin (bir muhakemenin bir anında dikkate alınan seçeneğe göre satırlar veya sütunlar), gerçekte kesinlikle böyle olmasa bile DataFrame'leri dikkate almanın iyi bir yolu olduğunu ifade eder. "İyi", bu vizyonun DataFrame'lerin verimli bir şekilde kullanılmasını sağladığı anlamına gelir. Bu kadar.

.

O halde DataFrame nesnesi nedir?

DataFrame sınıfı, belirli bir yapı kökenli olan örneklerini üreten NDFrame temel sınıf, kendisinden türetilen PandasContainer da bir üst sınıf temel sınıf Seri sınıfı.
Bunun, 0.12 sürümüne kadar Pandalar için doğru olduğunu unutmayın. Gelecek 0.13 sürümünde, Series ayrıca yalnızca NDFrame sınıfından türetilecektir .

# 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__

sonuç

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'>,)

Şimdi anladığım kadarıyla, bir DataFrame örneğinin, verilerin satırlardan ve sütunlardan çıkarılma şeklini kontrol etmek için hazırlanmış belirli yöntemlere sahip olduğu.

Bu ayıklama yöntemlerinin çalışma yolları bu sayfada açıklanmaktadır: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing
Dan Allan tarafından verilen yöntemi ve diğer yöntemleri buluyoruz.

Neden bu ayıklama yöntemleri olduğu gibi oluşturuldu?
Bunun nedeni, veri analizinde daha iyi olanaklar ve kolaylık sağlayanlar olarak değerlendirilmiş olmalarıdır.
Bu cümlede tam olarak ifade edilen şey:

Pandaların veri yapıları hakkında düşünmenin en iyi yolu, daha düşük boyutlu veriler için esnek kaplar olarak kullanmaktır.

Neden bir DataFRame örneğinden veri çıkarılması does not yapısında yatıyor, bu yatıyor neden bu yapının. Pandaların veri yapısının yapısı ve işleyişinin mümkün olduğunca entelektüel olarak sezgisel olması için yontulmuş olduğunu ve ayrıntıları anlamak için Wes McKinney'nin blogunu okumak gerektiğini tahmin ediyorum.


1
Bilginize, DataFrame bir ndarray alt sınıfı DEĞİLDİR, Seri de değildir (bundan önce 0.13'ten başlayarak). Bunlar daha çok dikte gibidir.
Jeff

Beni bilgilendirdiğiniz için teşekkür ederim. Pandaların öğrenilmesinde yeniyim çünkü gerçekten minnettarım. Ama iyi anlamak için daha fazla bilgiye ihtiyacım var. Bir Serinin ndarray'in bir alt sınıfı olduğu neden belgelerde yazılıdır?
eyquem


TAMAM. Çok teşekkür ederim. Ancak akıl yürütmemin ve anlayışımın temelini değiştirmiyor, değil mi? - 0.13'ten daha düşük Pandalar'da, DataFrame ve diğer Pandaların Seriden farklı nesneleri: alt sınıfı nedir?
eyquem

@Jeff Teşekkürler. Verdiğiniz bilgilerden sonra cevabımı değiştirdim. Düzenlemem hakkında ne düşündüğünüzü öğrenmekten memnuniyet duyarım.
eyquem

1

Amaç, dizini kullanarak veri kümesinin bir alt kümesini elde etmekse, en iyisi locveya kullanmaktan kaçınmaktır iloc. Bunun yerine şuna benzer bir sözdizimi kullanmalısınız:

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

Ayrıca dataframe endeksi üzerinde seçerseniz sonuç DataFrame veya Serisi de olabilir ya da bir Serisi veya skalar (tek değer) olabilir.

Bu işlev, seçiminizden her zaman bir liste almanızı sağlar (df, dizin ve sütun geçerliyse):

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)
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.