Aufteilen des Datenrahmens in mehrere Datenrahmen


89

Ich habe einen sehr großen Datenrahmen (ca. 1 Million Zeilen) mit Daten aus einem Experiment (60 Befragte).

Ich möchte den Datenrahmen in 60 Datenrahmen aufteilen (einen Datenrahmen für jeden Teilnehmer).

Im Datenrahmen datagibt es eine Variable namens 'name', die den eindeutigen Code für jeden Teilnehmer darstellt.

Ich habe Folgendes versucht, aber es passiert nichts (oder die Ausführung wird nicht innerhalb einer Stunde beendet). Was ich vorhabe, ist, die datain kleinere Datenrahmen aufzuteilen und diese an eine Liste anzuhängen ( datalist):

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

Ich erhalte keine Fehlermeldung, das Skript scheint nur für immer zu laufen!

Gibt es eine clevere Möglichkeit, dies zu tun?

Antworten:


53

Erstens ist Ihr Ansatz ineffizient, da das Anhängen an die Liste nacheinander langsam ist, da die Liste regelmäßig erweitert werden muss, wenn nicht genügend Platz für den neuen Eintrag vorhanden ist. Das Listenverständnis ist in dieser Hinsicht besser, wenn die Größe bestimmt wird vorne und einmal vergeben.

Grundsätzlich halte ich Ihren Ansatz jedoch für etwas verschwenderisch, da Sie bereits über einen Datenrahmen verfügen. Warum sollten Sie für jeden dieser Benutzer einen neuen erstellen?

Ich würde den Datenrahmen nach Spalten sortieren 'name', den Index so einstellen und bei Bedarf die Spalte nicht löschen .

Erstellen Sie dann eine Liste aller eindeutigen Einträge. Anschließend können Sie mit diesen Einträgen eine Suche durchführen. Wenn Sie nur die Daten abfragen, verwenden Sie die Auswahlkriterien, um eine Ansicht des Datenrahmens zurückzugeben, ohne dass eine kostspielige Datenkopie anfällt.

Verwenden Sie pandas.DataFrame.sort_valuesund 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'

72

Kann ich fragen, warum ich es nicht einfach durch Schneiden des Datenrahmens mache? Etwas wie

#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, Sie haben ein Wörterbuch mit Datenrahmen, so wie Sie es möchten (glaube ich). Müssen Sie auf eine zugreifen? Einfach eintreten

DataFrameDict['Joe']

hoffentlich hilft das


38

Sie können groupbyObjekte konvertieren in tuplesund dann in 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

Es wird nicht empfohlen , aber es ist möglich, DataFrames nach Gruppen zu erstellen:

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 kann Ihnen helfen:

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

Dann können Sie mit jeder Gruppe wie mit einem Datenrahmen für jeden Teilnehmer arbeiten. Und DataFrameGroupBy-Objektmethoden wie (Anwenden, Transformieren, Aggregieren, Kopf, Erste, Letzte) geben ein DataFrame-Objekt zurück.

Oder Sie können eine Liste groupederstellen und alle DataFrames nach Index abrufen:

l_grouped = list(grouped)

l_grouped[0][1] - DataFrame für die erste Gruppe mit Vornamen.



6

Zusätzlich zu Gusev Slavas Antwort möchten Sie möglicherweise die Gruppen von groupby verwenden:

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

Dies ergibt ein Wörterbuch mit den Schlüsseln, nach denen Sie gruppiert haben und das auf die entsprechenden Partitionen verweist. Der Vorteil ist, dass die Schlüssel beibehalten werden und nicht im Listenindex verschwinden.


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

Hier ist ein Groupby-Weg (und Sie könnten eine willkürliche Anwendung anstelle einer Summe durchführen)

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)

Die Summe ist cythonisiert, deshalb ist das so schnell

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

Die Methode basiert auf Listenverständnis und groupby - die den gesamten geteilten Datenrahmen in der Listenvariablen speichert und über den Index aufgerufen werden kann.

Beispiel

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

ans[0]
ans[0].column_name

0

Sie können den Befehl groupby verwenden, wenn Sie bereits einige Beschriftungen für Ihre Daten haben.

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

Hier ist ein detailliertes Beispiel:

Angenommen, wir möchten eine pd-Serie mithilfe einiger Beschriftungen in eine Liste von Blöcken aufteilen. Beispiel 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

Und das Entsprechende label_seriesist:

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

Lauf

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

was out_lista listvon zwei zurückgibt 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]

Beachten Sie, dass Sie einige Parameter aus sich in_seriesselbst verwenden können, um die Serie zu gruppieren, z.in_series.index.day


0
  • Erstens funktioniert die Methode im OP, ist aber nicht effizient. Es scheint für immer zu laufen, weil der Datensatz lang war.
  • Verwenden Sie .groupbyfür die 'method'Spalte und erstellen Sie ein dictvon DataFramesmit eindeutigen 'method'Werten als Schlüssel mit einem dict-comprehension.
    • .groupbyGibt ein groupbyObjekt zurück, das Informationen zu den Gruppen enthält, wobei gder eindeutige Wert 'method'für jede Gruppe und dder DataFramefür diese Gruppe ist.
  • Das valuevon jedem keyin df_dictwird ein sein DataFrame, auf das auf die übliche Weise zugegriffen werden kann df_dict['key'].
  • Die ursprüngliche Frage wollte ein listvon DataFrames, was mit einem gemacht werden kannlist-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) oder df_dict['Astrometry'].head(3)
  • Es gibt nur 2 in dieser Gruppe
         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) oder 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) oder 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

Alternative

  • Dies ist eine manuelle Methode zum Erstellen einer separaten DataFramesVerwendung Pandas : Boolesche Indizierung
  • Dies ähnelt der akzeptierten Antwort , aber.loc ist jedoch nicht erforderlich.
  • Dies ist eine akzeptable Methode, um ein paar zusätzliche zu erstellen DataFrames .
  • Die pythonic Möglichkeit , mehrere Objekte zu schaffen, ist , indem sie in einen Behälter gegeben ( zum Beispiel dict, list, generator, etc.), wie oben gezeigt.
df1 = df[df.method == 'Astrometry']
df2 = df[df.method == 'Eclipse Timing Variations']

-1

Ich hatte ein ähnliches Problem. Ich hatte eine Zeitreihe mit täglichen Verkäufen für 10 verschiedene Geschäfte und 50 verschiedene Artikel. Ich musste den ursprünglichen Datenrahmen in 500 Datenrahmen (10 Speicher * 50 Speicher) aufteilen, um Modelle für maschinelles Lernen auf jeden von ihnen anzuwenden, und ich konnte dies nicht manuell tun.

Dies ist der Kopf des Datenrahmens:

Kopf des Datenrahmens: df

Ich habe zwei Listen erstellt; eine für die Namen von Datenrahmen und eine für die paar Arrays [item_number, store_number].

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

Sobald die beiden Listen fertig sind, können Sie sie durchlaufen, um die gewünschten Datenrahmen zu erstellen:

         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)

Auf diese Weise habe ich 500 Datenrahmen erstellt.

Hoffe das wird hilfreich sein!

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.