Veri çerçevesini birden çok veri çerçevesine bölme


92

Bir deneyden elde edilen verilerle (60 katılımcı) çok büyük bir veri çerçevem ​​var (yaklaşık 1 milyon satır).

Veri çerçevesini 60 veri çerçevesine (her katılımcı için bir veri çerçevesi) bölmek istiyorum.

Veri çerçevesinde, her katılımcının benzersiz kodu olan databir değişken vardır 'name'.

Aşağıdakileri denedim, ancak hiçbir şey olmuyor (veya yürütme bir saat içinde durmuyor). Yapmak istediğim şey, verileri datadaha küçük veri çerçevelerine bölmek ve bunları bir listeye ( datalist) eklemek :

import pandas as pd

def splitframe(data, name='name'):
    
    n = data[name][0]

    df = pd.DataFrame(columns=data.columns)

    datalist = []

    for i in range(len(data)):
        if data[name][i] == n:
            df = df.append(data.iloc[i])
        else:
            datalist.append(df)
            df = pd.DataFrame(columns=data.columns)
            n = data[name][i]
            df = df.append(data.iloc[i])
        
    return datalist

Bir hata mesajı almıyorum, komut dosyası sonsuza kadar çalışıyor gibi görünüyor!

Bunu yapmanın akıllıca bir yolu var mı?

Yanıtlar:


53

Öncelikle yaklaşımınız verimsizdir çünkü listeye sıralı olarak eklemek, yeni giriş için yeterli alan olmadığında listeyi periyodik olarak büyütmek zorunda olduğu için yavaş olacaktır, boyut belirlendikçe liste anlayışları bu açıdan daha iyidir. ön ve bir kez tahsis edilir.

Bununla birlikte, temelde yaklaşımınızın biraz savurgan olduğunu düşünüyorum, çünkü zaten bir veri çerçeveniz var, öyleyse neden bu kullanıcıların her biri için yeni bir tane oluşturalım?

Veri çerçevesini sütuna göre sıralar 'name', dizini bu olacak şekilde ayarlar ve gerekirse sütunu düşürmezdim .

Ardından, tüm benzersiz girişlerin bir listesini oluşturun ve ardından bu girişleri kullanarak bir arama gerçekleştirebilirsiniz ve özellikle verileri sorguluyorsanız, maliyetli bir veri kopyasına maruz kalmadan veri çerçevesi üzerinde bir görünüm döndürmek için seçim kriterlerini kullanın.

Kullanım pandas.DataFrame.sort_valuesve pandas.DataFrame.set_index:

# sort the dataframe
df.sort_values(by='name', axis=1, inplace=True)

# set the index to be this and don't drop
df.set_index(keys=['name'], drop=False,inplace=True)

# get a list of names
names=df['name'].unique().tolist()

# now we can perform a lookup on a 'view' of the dataframe
joe = df.loc[df.name=='joe']

# now you can query all 'joes'

74

Bunu neden veri çerçevesini dilimleyerek yapmadığımı sorabilir miyim? Gibi bir şey

#create some data with Names column
data = pd.DataFrame({'Names': ['Joe', 'John', 'Jasper', 'Jez'] *4, 'Ob1' : np.random.rand(16), 'Ob2' : np.random.rand(16)})

#create unique list of names
UniqueNames = data.Names.unique()

#create a data frame dictionary to store your data frames
DataFrameDict = {elem : pd.DataFrame for elem in UniqueNames}

for key in DataFrameDict.keys():
    DataFrameDict[key] = data[:][data.Names == key]

Hey presto, tıpkı istediğiniz gibi (sanırım) bir veri çerçevesi sözlüğünüz var. Birine erişmeniz mi gerekiyor? Sadece girin

DataFrameDict['Joe']

umarım yardımcı olur


38

groupbyNesneyi tuplessonra şuna dönüştürebilirsiniz dict:

df = pd.DataFrame({'Name':list('aabbef'),
                   'A':[4,5,4,5,5,4],
                   'B':[7,8,9,4,2,3],
                   'C':[1,3,5,7,1,0]}, columns = ['Name','A','B','C'])

print (df)
  Name  A  B  C
0    a  4  7  1
1    a  5  8  3
2    b  4  9  5
3    b  5  4  7
4    e  5  2  1
5    f  4  3  0

d = dict(tuple(df.groupby('Name')))
print (d)
{'b':   Name  A  B  C
2    b  4  9  5
3    b  5  4  7, 'e':   Name  A  B  C
4    e  5  2  1, 'a':   Name  A  B  C
0    a  4  7  1
1    a  5  8  3, 'f':   Name  A  B  C
5    f  4  3  0}

print (d['a'])
  Name  A  B  C
0    a  4  7  1
1    a  5  8  3

O değil tavsiye , ancak olası gruplar tarafından DataFrames oluşturun:

for i, g in df.groupby('Name'):
    globals()['df_' + str(i)] =  g

print (df_a)
  Name  A  B  C
0    a  4  7  1
1    a  5  8  3


16

Groupby size şu konularda yardımcı olabilir:

grouped = data.groupby(['name'])

Daha sonra, her katılımcı için bir veri çerçevesi gibi her grupla çalışabilirsiniz. Ve (apply, transform, aggregate, head, first, last) gibi DataFrameGroupBy nesne yöntemleri bir DataFrame nesnesi döndürür.

Veya groupedDataFrame'den liste oluşturabilir ve tüm DataFrame'leri indekse göre alabilirsiniz:

l_grouped = list(grouped)

l_grouped[0][1] - İlk ada sahip ilk grup için DataFrame.


7

Gusev Slava'nın cevabına ek olarak, groupby'nin gruplarını da kullanmak isteyebilirsiniz:

{key: df.loc[value] for key, value in df.groupby("name").groups.items()}

Bu, ilgili bölümleri işaret ederek grupladığınız tuşların bulunduğu bir sözlük verecektir. Bunun avantajı, anahtarların muhafaza edilmesi ve liste dizininde kaybolmamasıdır.


3
In [28]: df = DataFrame(np.random.randn(1000000,10))

In [29]: df
Out[29]: 
<class 'pandas.core.frame.DataFrame'>
Int64Index: 1000000 entries, 0 to 999999
Data columns (total 10 columns):
0    1000000  non-null values
1    1000000  non-null values
2    1000000  non-null values
3    1000000  non-null values
4    1000000  non-null values
5    1000000  non-null values
6    1000000  non-null values
7    1000000  non-null values
8    1000000  non-null values
9    1000000  non-null values
dtypes: float64(10)

In [30]: frames = [ df.iloc[i*60:min((i+1)*60,len(df))] for i in xrange(int(len(df)/60.) + 1) ]

In [31]: %timeit [ df.iloc[i*60:min((i+1)*60,len(df))] for i in xrange(int(len(df)/60.) + 1) ]
1 loops, best of 3: 849 ms per loop

In [32]: len(frames)
Out[32]: 16667

İşte grup halinde bir yol (ve toplamdan ziyade keyfi bir uygulama yapabilirsiniz)

In [9]: g = df.groupby(lambda x: x/60)

In [8]: g.sum()    

Out[8]: 
<class 'pandas.core.frame.DataFrame'>
Int64Index: 16667 entries, 0 to 16666
Data columns (total 10 columns):
0    16667  non-null values
1    16667  non-null values
2    16667  non-null values
3    16667  non-null values
4    16667  non-null values
5    16667  non-null values
6    16667  non-null values
7    16667  non-null values
8    16667  non-null values
9    16667  non-null values
dtypes: float64(10)

Sum cythonized, bu yüzden bu çok hızlı

In [10]: %timeit g.sum()
10 loops, best of 3: 27.5 ms per loop

In [11]: %timeit df.groupby(lambda x: x/60)
1 loops, best of 3: 231 ms per loop

1

Listeyi anlamaya dayalı yöntem ve groupby - Tüm bölünmüş veri çerçevesini liste değişkeninde depolayan ve indeks kullanılarak erişilebilen yöntem.

Misal

ans = [pd.DataFrame(y) for x, y in DF.groupby('column_name', as_index=False)]

ans[0]
ans[0].column_name

1
  • İlk olarak, OP'deki yöntem işe yarıyor, ancak verimli değil. Veri kümesi uzun olduğu için sonsuza kadar çalışıyor gibi görünebilir.
  • Kullanım .groupbyile ilgili 'method'sütuna ve yaratmak dictait DataFramesbenzersiz ile 'method'bir ile, tuşları olarak değerler dict-comprehension.
    • .groupbyBir döner groupbygrupları hakkında bilgi içeren bir nesne, gbenzersiz değeri 'method'her bir grup için, ve dbir DataFrameo grup için.
  • valueHer bir keyin df_dict, bir olacaktır DataFrame, standart bir şekilde erişilebilen, df_dict['key'].
  • Orijinal soru istediği bir listbir DataFramesa ile yapılabilir ki,list-comprehension
    • df_list = [d for _, d in df.groupby('method')]
import pandas as pd
import seaborn as sns  # for test dataset

# load data for example
df = sns.load_dataset('planets')

# display(df.head())
            method  number  orbital_period   mass  distance  year
0  Radial Velocity       1         269.300   7.10     77.40  2006
1  Radial Velocity       1         874.774   2.21     56.95  2008
2  Radial Velocity       1         763.000   2.60     19.84  2011
3  Radial Velocity       1         326.030  19.40    110.62  2007
4  Radial Velocity       1         516.220  10.50    119.47  2009


# Using a dict-comprehension, the unique 'method' value will be the key
df_dict = {g: d for g, d in df.groupby('method')}

print(df_dict.keys())
[out]:
dict_keys(['Astrometry', 'Eclipse Timing Variations', 'Imaging', 'Microlensing', 'Orbital Brightness Modulation', 'Pulsar Timing', 'Pulsation Timing Variations', 'Radial Velocity', 'Transit', 'Transit Timing Variations'])

# or a specific name for the key, using enumerate (e.g. df1, df2, etc.)
df_dict = {f'df{i}': d for i, (g, d) in enumerate(df.groupby('method'))}

print(df_dict.keys())
[out]:
dict_keys(['df0', 'df1', 'df2', 'df3', 'df4', 'df5', 'df6', 'df7', 'df8', 'df9'])
  • df_dict['df1].head(3) veya df_dict['Astrometry'].head(3)
  • Bu grupta sadece 2 tane var
         method  number  orbital_period  mass  distance  year
113  Astrometry       1          246.36   NaN     20.77  2013
537  Astrometry       1         1016.00   NaN     14.98  2010
  • df_dict['df2].head(3) veya df_dict['Eclipse Timing Variations'].head(3)
                       method  number  orbital_period  mass  distance  year
32  Eclipse Timing Variations       1         10220.0  6.05       NaN  2009
37  Eclipse Timing Variations       2          5767.0   NaN    130.72  2008
38  Eclipse Timing Variations       2          3321.0   NaN    130.72  2008
  • df_dict['df3].head(3) veya df_dict['Imaging'].head(3)
     method  number  orbital_period  mass  distance  year
29  Imaging       1             NaN   NaN     45.52  2005
30  Imaging       1             NaN   NaN    165.00  2007
31  Imaging       1             NaN   NaN    140.00  2004

Alternatif olarak

  • Bu, pandalarıDataFrames kullanarak ayrı oluşturmak için manuel bir yöntemdir : Boole Dizin Oluşturma
  • Bu, kabul edilen cevaba benzer , ancak .loczorunlu değildir.
  • Bu, fazladan bir çift oluşturmak için kabul edilebilir bir yöntemdir. DataFrames .
  • Birden çok nesne oluşturmak için pythonic yolu, (örneğin, bir kap içinde yerleştirerek olduğu dict, list, generatoryukarıda gösterildiği gibi, vb.)
df1 = df[df.method == 'Astrometry']
df2 = df[df.method == 'Eclipse Timing Variations']

0

Verileriniz için zaten bazı etiketleriniz varsa groupby komutunu kullanabilirsiniz.

 out_list = [group[1] for group in in_series.groupby(label_series.values)]

İşte ayrıntılı bir örnek:

Diyelim ki bir pd serisini bazı etiketler kullanarak bir yığın listesine bölmek istiyoruz. Örneğin in_series:

2019-07-01 08:00:00   -0.10
2019-07-01 08:02:00    1.16
2019-07-01 08:04:00    0.69
2019-07-01 08:06:00   -0.81
2019-07-01 08:08:00   -0.64
Length: 5, dtype: float64

Ve label_serieskarşılığı:

2019-07-01 08:00:00   1
2019-07-01 08:02:00   1
2019-07-01 08:04:00   2
2019-07-01 08:06:00   2
2019-07-01 08:08:00   2
Length: 5, dtype: float64

Çalıştırmak

out_list = [group[1] for group in in_series.groupby(label_series.values)]

burada döner out_listbir listiki pd.Series:

[2019-07-01 08:00:00   -0.10
2019-07-01 08:02:00   1.16
Length: 2, dtype: float64,
2019-07-01 08:04:00    0.69
2019-07-01 08:06:00   -0.81
2019-07-01 08:08:00   -0.64
Length: 3, dtype: float64]

in_seriesSeriyi gruplamak için kendisinden bazı parametreleri kullanabileceğinizi unutmayın , örneğin,in_series.index.day


-1

Benim de benzer bir problemim vardı. 10 farklı mağaza ve 50 farklı ürün için bir dizi günlük satışım oldu. Her birine Makine Öğrenimi modellerini uygulamak için orijinal veri çerçevesini 500 veri çerçevesine (10 mağaza * 50 mağaza) bölmem gerekiyordu ve bunu manuel olarak yapamadım.

Bu, veri çerçevesinin başıdır:

veri çerçevesinin başı: df

İki liste oluşturdum; biri veri çerçevelerinin adları için ve diğeri [öğe_sayı, depo_sayı] dizisi çifti için.

    list=[]
    for i in range(1,len(items)*len(stores)+1):
    global list
    list.append('df'+str(i))

    list_couple_s_i =[]
    for item in items:
          for store in stores:
                  global list_couple_s_i
                  list_couple_s_i.append([item,store])

Ve iki liste hazır olduğunda, istediğiniz veri çerçevelerini oluşturmak için bunların üzerinde döngü yapabilirsiniz:

         for name, it_st in zip(list,list_couple_s_i):
                   globals()[name] = df.where((df['item']==it_st[0]) & 
                                                (df['store']==(it_st[1])))
                   globals()[name].dropna(inplace=True)

Bu şekilde 500 veri çerçevesi oluşturdum.

Umarım bu yardımcı olur!

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.