2016-10-14 6 views
7

の間で選択、私はいくつかのデータクリーニングを行うと口論とこれは各.csvファイルの最終的な構造です(図解の目的でのみ偽のデータ)。はパンダ、OOPクラス、およびdicts(パイソン)

import pandas as pd 
data = [[112233, 'Rob', 99], [445566, 'John', 88]] 
managers = pd.DataFrame(data) 
managers.columns = ['ManagerId', 'ManagerName', 'ShopId'] 
print managers 

    ManagerId ManagerName ShopId 
0  112233   Rob  99 
1  445566  John  88 


data = [[99, 'Shop1'], [88, 'Shop2']] 
shops = pd.DataFrame(data) 
shops.columns = ['ShopId', 'ShopName'] 
print shops 

    ShopId ShopName 
0  99 Shop1 
1  88 Shop2 

data = [[99, 2000, 3000, 4000], [88, 2500, 3500, 4500]] 
sales = pd.DataFrame(data) 
sales.columns = ['ShopId', 'Year2010', 'Year2011', 'Year2012'] 
print sales 

    ShopId Year2010 Year2011 Year2012 
0  99  2000  3000  4000 
1  88  2500  3500  4500 

それから私は、データフレームを反復しながら、カスタムExcelシートとの.pdfレポートを作成するためのxlsxwriterreportlab Pythonパッケージを使用しています。すべてが素晴らしく、指定されたすべてのパッケージは本当にうまく機能します。

私の関心は、しかし、私は私のコードは、私は複数の呼び出しで同じデータフレームの列を複数回アクセスする必要があるとして維持するのは難しいなっていることを感じていることです。

は、私は私のコードは、呼び出しのこの種で満たされた年2010年に1500以上の売上高を持っていた店を担当するマネージャー名を取得する必要が言う:

managers[managers['ShopId'].isin(
    sales[sales['Year2010'] > 1500]['ShopId'])]['ManagerName'].values 
>>> array(['Rob', 'John'], dtype=object) 

私は見えにくいと思いますこのコード行を読んでいる間、何が起こっているのですか?私は複数の中間変数を作成することができますが、これは複数行のコードを追加します。

それはデータベースの正規化のイデオロギーを犠牲にし、より保守コードを取得するために単一のデータフレームにすべてのピースをマージする方法が一般的ですか?後で必要とされる可能性のある他のデータフレームをマージしようとすると、混乱を招く可能性があるため、単一のデータフレームを持つことは明らかです。それらをマージすると、同じマネージャーを複数のショップに割り当てることができるため、データの冗長性がもたらされます。

df = managers.merge(sales, how='left', on='ShopId'). 
    merge(shops, how='left', on='ShopId') 
print df 

    ManagerId ManagerName ShopId Year2010 Year2011 Year2012 ShopName 
0  112233   Rob  99  2000  3000  4000 Shop1 
1  445566  John  88  2500  3500  4500 Shop2 

少なくとも、この呼び出しが小さくなる:たぶん

df[df['Year2010'] > 1500]['ManagerName'].values 
>>> array(['Rob', 'John'], dtype=object) 

パンダは、ジョブのこの種の間違ったツールですか?

私のオフィスでは、開発者がぼんやりして、クラスを使用するように教えていますが、その後、get_manager_sales(managerid)などの方法を使用します。レポート用のクラスインスタンスを反復することは、ソートやインデックス作成(私はpandasで無料)を実装する必要があるため、面倒です。

辞書は動作しますが、それは、それはまた難しいはるかに良いのいずれかを取得しないマージなどの構文やって、既存のデータを修正することができます。

data_dict = df.to_dict('records') 
[{'ManagerId': 112233L, 
    'ManagerName': 'Rob', 
    'ShopId': 99L, 
    'ShopName': 'Shop1', 
    'Year2010': 2000L, 
    'Year2011': 3000L, 
    'Year2012': 4000L}, 
{'ManagerId': 445566L, 
    'ManagerName': 'John', 
    'ShopId': 88L, 
    'ShopName': 'Shop2', 
    'Year2010': 2500L, 
    'Year2011': 3500L, 
    'Year2012': 4500L}] 
年に1500以上の私はで動作データとこの特定のケースでは、2010年

[row['ManagerName'] for row in data_dict if row['Year2010'] > 1500] 
>>> ['Rob', 'John'] 

を販売していた店を担当する

取得マネージャーの名前は、私はすべての道を行く必要がありますpandasを使用するか、またはpandasの力を利用しながらクリーナーコードを書く別の方法がありますか?

答えて

3

それははるかに高速ですので、私は優秀で、非常に豊富なAPIを持って、ソースコード等、非常にクリーンで良く見える、パンダを選ぶだろう

はところで次の行を簡単に書き換えることができます:として

managers[managers['ShopId'].isin(sales[sales['Year2010'] > 1500]['ShopId'])]['ManagerName'].values 

ShopIds = sales.ix[sales['Year2010'] > 1500, 'ShopId'] 
managers.query('ShopId in @ShopIds')['ManagerName'].values 

をIMOそれはまた、あなたのデータを保存したい場合があり

PSを読み、理解することは非常に簡単ですSQL-capableデータベースでSQLを使用するか、またはHDF Storeに格納してwhereパラメータを使用します。どちらの場合も、「検索」c

+0

答えに感謝して、レポートプログラムを書くためのパンダを選ぶことは正しいことだと確信しました。常に複数のフレームを相互参照するのを避けるために、すべてのcsvファイルのデータフレームを1つのデータフレームにマージすることも検討してください。 –

+0

@AlexTereshenkov、あなたはあなたのテーブルを非正規化し、すべてのものを1つのフラットDFに入れることができますが、[可能性のある落とし穴]に注意してください(http://stackoverflow.com/questions/40002355/pandas-left-join-why-more)。 -results/40002535#40002535) – MaxU

2

データフレームで動作するクラスを作成することはお勧めできません。データフレームを使用しているという事実を隠してしまい、非常に悪い決定をすることになります。 forループ)。

解決策1:データを非正規化します。 データを通常の形式に保つ必要はありません。通常のフォームは、データベース全体でエントリの一貫性を保つ必要がある場合に優先されます。これはデータベースではなく、定数の挿入、更新、削除は行いません。だから、それをデノーマライズし、大規模なデータフレーム1つで作業することは、はるかに便利であり、ニーズに合っています。

解決策2:データベースを使用します。 SQLiteデータベースにデータをダンプすることができます(pandasにはそのための機能が組み込まれています)。そして、あらゆる種類のクレイジークエリを実行します。私の個人的な意見では、SQLクエリはあなたが投稿したものよりはるかに読みやすくなっています。 この種の分析を定期的に行い、データ構造が変わらない場合は、これが好ましいソリューションになる可能性があります。 db内のデータをダンプし、SQLAlchemyを使用して処理することができます。

解決方法3.独自のデータ型を作成します。 pandas.DataFrameから継承し、カスタムメソッドを追加できます。しかし、それらの方法を実装する方法については、pandasの勇気を掘り下げて調べる必要があります。このようにして、たとえば、データフレームの特定の部分にアクセスするカスタムメソッドを作成できます。

パンダが本当にうまくいないのであれば、私は解決策1または2に行きます。柔軟性が必要で、データの操作が毎回異なる場合は、1を使用します。毎回ほぼ同じ分析を実行する必要がある場合2を使用します(特に、データ解析コードがより大きなアプリケーションの一部である場合)。

また、「コードの行を追加する」が悪い理由はわかりません。巨大な1行を多くの式に分割することで、の実際のサイズはにはならず、という複雑さが軽減されます。たぶん、あなたのコードをリファクタリングするだけで、いくつかの操作を再利用可能な関数にパックするだけです。

+0

フィードバックをいただきありがとうございます。非常に役に立ちます。 '1'クラスについて言えば、私はpandasに基づいていないクラスで、csvファイル(例えばcsv dictreaderのようなもの)から構築できるクラスを意味していました。 '2.'は、いくつかの操作を再利用可能な関数にパックしますか?get_manager_shops() 'や' get_shops_totalsale() 'のような関数をいくつか追加して別々のモジュールに入れると、私の人生が楽になるかもしれません(しかし、内部ではまだデータを呼び出しますフレーム、右?) –

+1

はい、あなたはそれらの呼び出しを隠すだけです。 'pandas'の多くの操作がしばしばデータフレームのビューを返すという問題もあります。 'get_shops_totalsale(df)'関数を呼び出すときは、これは明白ではありません。だから、あなたはこの種のことを念頭に置いておく必要があります。これはコードを理解しにくくするでしょう。これを忘れると、予期せぬ副作用が「魔法」になる可能性があります。 –

関連する問題