2015-10-13 16 views
5

Wie kann ich einen Pandas-Datenrahmen oder Graphlab-Sframe basierend auf einer gegebenen Klasse \ Label-Verteilungswerte abfragen, zB: Ich möchte einen Datenrahmen mit einer label \ class-Spalte abtasten, um solche Zeilen auszuwählen jedes Klassenetikett wird gleichermaßen abgerufen, wodurch es für jedes Klassenetikett, das einer gleichmäßigen Verteilung von Klassenetiketten entspricht, eine ähnliche Häufigkeit aufweist. Oder am besten wäre es, Samples entsprechend der gewünschten Klassenverteilung zu erhalten.Abtastung eines Datenrahmens basierend auf einer gegebenen Verteilung

 
+------+-------+-------+ 
| col1 | clol2 | class | 
+------+-------+-------+ 
| 4 | 45 | A  | 
+------+-------+-------+ 
| 5 | 66 | B  | 
+------+-------+-------+ 
| 5 | 6  | C  | 
+------+-------+-------+ 
| 4 | 6  | C  | 
+------+-------+-------+ 
| 321 | 1  | A  | 
+------+-------+-------+ 
| 32 | 432 | B  | 
+------+-------+-------+ 
| 5 | 3  | B  | 
+------+-------+-------+ 

given a huge dataframe like above and the required frequency distribution like below: 
+-------+--------------+ 
| class | nostoextract | 
+-------+--------------+ 
| A  | 2   | 
+-------+--------------+ 
| B  | 2   | 
+-------+--------------+ 
| C  | 2   | 
+-------+--------------+ 


Die oben sollten Zeilen aus dem ersten Datenrahmen auf der gegebene Häufigkeitsverteilung in dem zweiten Rahmen, wo die Frequenz Zählwerte sind in nostoextract Spalt basierend extrahieren einen abgetastetes Rahmen zu geben, wo jede Klasse bei max 2 mal erscheint. sollte ignoriert und fortgesetzt werden, wenn nicht genügend Klassen gefunden werden können, um die erforderliche Anzahl zu erreichen. Der resultierende Datenrahmen soll für einen Entscheidungsbaum-basierten Klassifikator verwendet werden.

Wie ein Kommentator setzt es das Sampling-Datenframe muss nostextract verschiedene Instanzen der entsprechenden Klasse enthalten? Es sei denn, es gibt nicht genug Beispiele für eine bestimmte Klasse, in diesem Fall nehmen Sie einfach alle verfügbaren.

+1

Können Sie einige Beispiele hinzufügen, was Sie erreichen möchten? Und hast du 'pandas.DataFrame.sample' angeschaut? (http://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.sample.html) –

+0

@ chris-sc Ja, es erlaubt nicht zu Probe basierend auf Klasse Spalte – stackit

+0

im Grunde möchte ich einen verzerrten Datenrahmen, so dass alle Klassenschilder ausreichend vertreten sind so viel wie möglich zu probieren. Die Klassenbezeichnungen befinden sich in der Spalte "Label". Dies wird einem Klassifikator zugeführt. @ chris-sc – stackit

Antwort

3

Ich denke, das Ihr Problem lösen:

import pandas as pd 

data = pd.DataFrame({'cols1':[4, 5, 5, 4, 321, 32, 5], 
        'clol2':[45, 66, 6, 6, 1, 432, 3], 
        'class':['A', 'B', 'C', 'C', 'A', 'B', 'B']}) 

freq = pd.DataFrame({'class':['A', 'B', 'C'], 
        'nostoextract':[2, 2, 2], }) 

def bootstrap(data, freq): 
    freq = freq.set_index('class') 

    # This function will be applied on each group of instances of the same 
    # class in `data`. 
    def sampleClass(classgroup): 
     cls = classgroup['class'].iloc[0] 
     nDesired = freq.nostoextract[cls] 
     nRows = len(classgroup) 

     nSamples = min(nRows, nDesired) 
     return classgroup.sample(nSamples) 

    samples = data.groupby('class').apply(sampleClass) 

    # If you want a new index with ascending values 
    # samples.index = range(len(samples)) 

    # If you want an index which is equal to the row in `data` where the sample 
    # came from 
    samples.index = samples.index.get_level_values(1) 

    # If you don't change it then you'll have a multiindex with level 0 
    # being the class and level 1 being the row in `data` where 
    # the sample came from. 

    return samples 

print(bootstrap(data,freq)) 

Drucke:

class clol2 cols1 
0  A  45  4 
4  A  1 321 
1  B  66  5 
5  B 432  32 
3  C  6  4 
2  C  6  5 

Wenn Sie das Ergebnis nicht wollen nach Klassen geordnet werden, können Sie es am Ende permute kann.

+0

danke kann das gleiche für einen sframe gemacht werden? (graphlab – stackit

+0

@stackit, weiß nicht ... sie scheinen die gleiche Schnittstelle zu haben. Haben Sie es versucht? – swenzel

4

Können Sie Ihren ersten Datenrahmen in klassenspezifische Subdatenrahmen aufteilen und dann nach Belieben aus diesen Daten filtern?

dh

dfa = df[df['class']=='A'] 
dfb = df[df['class']=='B'] 
dfc = df[df['class']=='C'] 
.... 

Dann, sobald Sie haben Split/erstellt/auf DFA gefiltert, dfb, DFC, eine Reihe von oben holen wie gewünscht (wenn Datenrahmen haben kein bestimmtes Art-Muster)

dfasamplefive = dfa[:5] 

oder die Probenmethode verwenden, wie durch einen vorhergehenden Kommentator beschrieben, um direkt eine Stichprobe zu nehmen:

dfasamplefive = dfa.sample(n=5) 

Wenn dies Ihren Anforderungen entspricht, müssen Sie nur noch den Prozess automatisieren, indem Sie die Anzahl der zu prüfenden Daten aus dem Steuerdatenrahmen als zweiten Datenrahmen eingeben, der die gewünschte Anzahl an Proben enthält.

+1

sollte dfasamplefive = dfa [: 5] sein, wenn Sie die oberen 5 Werte wollen ... – PALEN

+0

Ja, Sie sind ziemlich richtig, danke dafür! [entsprechend bearbeitet] –

1

Hier ist eine Lösung für SFrames. Es ist nicht genau was Sie wollen, weil es Punkte nach dem Zufallsprinzip abfragt, so dass die Ergebnisse nicht unbedingt genau die Anzahl der Zeilen haben, die Sie angeben. Eine genaue Methode würde wahrscheinlich die Daten zufällig mischen und dann die ersten k Reihen für eine bestimmte Klasse nehmen, aber das bringt Sie verdammt nah.

import random 
import graphlab as gl 

## Construct data. 
sf = gl.SFrame({'col1': [4, 5, 5, 4, 321, 32, 5], 
       'col2': [45, 66, 6, 6, 1, 432, 3], 
       'class': ['A', 'B', 'C', 'C', 'A', 'B', 'B']}) 

freq = gl.SFrame({'class': ['A', 'B', 'C'], 
        'number': [3, 1, 0]}) 

## Count how many instances of each class and compute a sampling 
# probability. 
grp = sf.groupby('class', gl.aggregate.COUNT) 
freq = freq.join(grp, on ='class', how='left') 
freq['prob'] = freq.apply(lambda x: float(x['number'])/x['Count']) 

## Join the sampling probability back to the original data. 
sf = sf.join(freq[['class', 'prob']], on='class', how='left') 

## Sample the original data, then subset. 
sf['sample_mask'] = sf.apply(lambda x: 1 if random.random() <= x['prob'] 
          else 0) 
sf2 = sf[sf['sample_mask'] == 1] 

In meinem Probelauf, ich zufällig die genaue Anzahl der Proben, die ich angegeben, aber auch dies ist nicht garantiert mit dieser Lösung zu erhalten.

>>> sf2 
+-------+------+------+ 
| class | col1 | col2 | 
+-------+------+------+ 
| A | 4 | 45 | 
| A | 321 | 1 | 
| B | 32 | 432 | 
+-------+------+------+ 
+0

danke wird es auch skalieren? – stackit

+0

Wie skalieren Sie? – papayawarrior

Verwandte Themen