2017-04-13 11 views
2

たとえば、次のようなDataFrameがあります。パンダで複雑なデータクリーニングを行う方法

lineNum  id   name   Cname   score 
    1   001  Jack    Math   99 
    2   002  Jack    English  110 
    3   003  Jack    Chinese  90 
    4   003  Jack    Chinese  90 
    5   004  Tom    Math   Nan 
    6   005  Tom    English  75 
    7   006  Tom    Chinese  85 

ご覧のとおり、このデータのデータクリーニングが必要です。 1)3行目と4行目の重複値を削除します。 2)不合理な値を扱います。 2行目で、Jackの英語は最大値100を超える110を取得します。私はすべての学生の英語スコアの平均値にスコアを設定したいと思います。 3)Nan値を処理します。トムの数学の得点はナンです。私はすべての生徒の数学の平均値に変更したいと思います。

それぞれの要件をすべて満たすことができます。しかし、私はこれらの3つの要件すべてをどうやって行うのか分かりません。ありがとう!

+0

を埋めるためにそれを使用します最初のように重複を取り除き、すべてのnull値と範囲外の値については、平均値 –

+0

に置き換えて、 'Dataframe.drop_duplicate()'を使用して110スコアを取り除くことができますあなたが知っているように簡単ですmaxは100です。次に、nan値に 'Dataframe.fillna()'を使います –

答えて

0

データが大きすぎない場合は、 `.apply(func) 'を考慮する必要があります。

を使用でき
import pandas as pd 

df = pd.read_table('sample.txt', delimiter='\s+', na_values='Nan') # Your sample data 
df = df.set_index('lineNum').drop_duplicates() 

def deal_with(x): 
    if (x['score'] > 100.) or (pd.isnull(x['score'])): 
     df_ = df[df['id'] != x['id']] 
     x['score'] = df_.loc[df_['Cname'] == x['Cname'], 'score'].mean() 

    return x 

print(df.apply(deal_with, axis=1)) 

     id name Cname score 
lineNum       
1   1 Jack  Math 99.0 
2   2 Jack English 75.0 
3   3 Jack Chinese 90.0 
5   4 Tom  Math 99.0 
6   5 Tom English 75.0 
7   6 Tom Chinese 85.0 
1

NaNためmask

cols = ['id','name','Cname','score'] 
#remove duplicates by columns 
df = df.drop_duplicates(subset=cols) 
#replace values > 100 to NaN 
df.loc[df['score'] > 100, 'score'] = np.nan 
#replace NaN by mean for all students by subject 
df['score'] = df.groupby('Cname')['score'].transform(lambda x: x.fillna(x.mean())) 
print (df) 
    lineNum id name Cname score 
0  1 1 Jack  Math 99.0 
1  2 2 Jack English 75.0 
2  3 3 Jack Chinese 90.0 
4  5 4 Tom  Math 99.0 
5  6 5 Tom English 75.0 
6  7 6 Tom Chinese 85.0 

代替ソリューション:

cols = ['id','name','Cname','score'] 
df = df.drop_duplicates(subset=cols) 
df['score'] = df['score'].mask(df['score'] > 100) 

df['score'] = df.groupby('Cname')['score'].apply(lambda x: x.fillna(x.mean())) 
print (df) 
    lineNum id name Cname score 
0  1 1 Jack  Math 99.0 
1  2 2 Jack English 75.0 
2  3 3 Jack Chinese 90.0 
4  5 4 Tom  Math 99.0 
5  6 5 Tom English 75.0 
6  7 6 Tom Chinese 85.0 
2

計画

  • 私は開始するために重複をドロップします。
  • 平均で
  • マップ手段100ヌル
  • フィルタ新しいデータフレームとグループよりもスコアを作るために使用mask>とそうでない理由をヌル

d = df.drop_duplicates(['id', 'name', 'Cname']) 

s0 = d.score 
s1 = s0.mask(s > 100) 
m = s1.mask(s1 > 100).notnull() 

d.assign(score=s1.fillna(d.Cname.map(d[m].groupby('Cname').score.mean()))) 

    lineNum id name Cname score 
0  1 1 Jack  Math 99.0 
1  2 2 Jack English 110.0 
2  3 3 Jack Chinese 90.0 
4  5 4 Tom  Math 99.0 
5  6 5 Tom English 75.0 
6  7 6 Tom Chinese 85.0 
関連する問題