2015-10-13 7 views
5

与えられたクラス\ラベル分布値に基づいてpandasデータフレームまたはグラフラブsframeをサンプリングするにはどうすればいいですか?たとえば、\ classカラムを持つデータフレームをサンプリングして、各クラスラベルは均等にフェッチされ、それによってクラスラベルの一様な分布に対応する各クラスラベルについて同様の頻度を有する。あるいは、私たちが望むクラスの分布に従ってサンプルを得ることが最善です。与えられた分布に基づいてデータフレームをサンプリングする

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


上記周波数カウント値が各クラスは、最大で2回表示され、サンプリングフレームを与えるnostoextract列に示されている第二のフレームに与えられた周波数分布に基づいて第1データフレームから行を抽出しなければなりません。 cantが必要な数を満たすのに十分なクラスを見つけた場合は、無視して続行する必要があります。結果として生じるデータフレームは、決定木ベースの分類器に使用される。

解説者は、サンプリングされたデータフレームには、対応するクラスの異なるインスタンスを別々に抽出する必要がありますか?与えられたクラスのための十分な例がない場合を除いて、利用可能なすべてのものを取るだけです。

+1

達成したいことのいくつかの例を追加できますか?そして、あなたは 'pandas.DataFrame.sample'を見ましたか? (http://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.sample)。html) –

+0

@ chris-scはいクラス列 – stackit

+0

に基づいてサンプルを作成することはできません。すべてのクラスラベルができるだけ十分に表現されるように、歪んだデータフレームをサンプリングしたいと考えています。クラスラベルは「ラベル」列にあります。これは分類器に送られる。 @ chris-sc – stackit

答えて

3

私は、これはあなたの問題を解決すると思います:

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

プリント:

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 

あなたは結果がクラスで注文することにしたくない場合は、あなたが最後にそれをpermuteすることができます。

+0

同じことがsframeのために同じことができますか? (graphlab – stackit

+0

@stackit、dunno ...彼らは同じインターフェースを持っているようです。 – swenzel

4

最初のデータフレームをクラス固有のサブデータフレームに分割し、それから自由にサンプリングできますか?必要に応じて(データフレームは、特定の並べ替えパターンを持っていない場合)次に

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

すなわち

あなたはDFAで濾過/作成/分割したら、DFB、DFCは、先頭から番号を選びます

dfasamplefive = dfa[:5] 

または以前のコメント投稿者によって記載されているように直接ランダムサンプル取るサンプルメソッドを使用:

dfasamplefive = dfa.sample(n=5) 

それがあなたのニーズに合っているなら、必要な数のサンプルを含む2番目のデータフレームとして持っているコントロールデータフレームからサンプリングする番号を入力して、プロセスを自動化するだけです。

+1

はdfasamplefive = dfa [:5]でなければなりません。もしあなたがトップ5の値を持っていたら... – PALEN

+0

はい、あなたはかなりですそれに感謝です。[それに応じて編集しました] –

1

ここにSFramesのソリューションがあります。 正確にはではありません。ポイントをランダムにサンプリングするので、結果に指定する行の数が正確になるわけではありません。正確な方法は、ランダムにデータをランダムにシャッフルしてから、最初のk行を特定のクラスに使用しますが、これによってクローズドな結果が得られます。私のサンプル実行で

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] 

、私は指定されたサンプルの正確な数を取得するために起こった、しかし、再び、これは、このソリューションを保証するものではありません。

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

それはまたスケールになりますか? – stackit

+0

どのようにスケール? – papayawarrior

関連する問題