2016-11-17 31 views
0

私はパンダにあるデータを再形成してクエリするときにメソッドチェインを使用していますDataFrames。インインデックス(行)および列の追加および不必要なレベルが作成されることがあります。そうであれば、例えば。インデックス(行軸)上で、これは容易DataFrame.reset_index()を使用することによって解決される:パンダの列レベルをドロップするメソッド連鎖解説

df.query('some query') 
    .apply(cool_func) 
    .reset_index('unwanted_index_level',drop=True) # <==== 
    .apply(another_cool_func) 

reset_index機能が一つの鎖の方法を継続し、DataFrameで働き続けることを可能にします。

それにもかかわらず、私はcolumn_axisと同等の解決策を見出すことはありませんでした。全くありますか?

+1

カラムを削除する '.drop'を探していますか? – James

+0

こんにちは - いいえ軸 'DataFrame.columns'の' MultiIndex'からレベルを削除したい – dmeu

+0

列インデックスレベルが削除された場合に発生する列名の重複をどのように処理したいですか? – James

答えて

3

あなただけstack列缶(インデックスに移動)し、ドロップ=真でreset_indexを呼び出し、またはあなたが出発点としてreset_index() 1を使用してreset_columns()方法を書くことができる(frame.py#のL2940を参照してください)

df.query('some query') 
    .apply(cool_func) 
    .stack(level='unwanted_col_level_name') 
    .reset_index('unwanted_col_level_name',drop=True) 
    .apply(another_cool_func) 

オルタナティブ:モンキーパッチソリューション

def drop_column_levels(self, level=None, inplace=False): 
     """ 
     For DataFrame with multi-level columns, drops one or more levels. 
     For a standard index, or if dropping all levels of the MultiIndex, will revert 
     back to using a classic RangeIndexer for column names. 

     Parameters 
     ---------- 
     level : int, str, tuple, or list, default None 
      Only remove the given levels from the index. Removes all levels by 
      default 
     inplace : boolean, default False 
      Modify the DataFrame in place (do not create a new object) 

     Returns 
     ------- 
     resetted : DataFrame 
     """ 
     if inplace: 
      new_obj = self 
     else: 
      new_obj = self.copy() 

     new_columns = pd.core.common._default_index(len(new_obj.columns)) 
     if isinstance(self.index, pd.MultiIndex): 
      if level is not None: 
       if not isinstance(level, (tuple, list)): 
        level = [level] 
       level = [self.index._get_level_number(lev) for lev in level] 
       if len(level) < len(self.columns.levels): 
        new_columns = self.columns.droplevel(level) 

     new_obj.columns = new_columns 
     if not inplace: 
      return new_obj 

# Monkey patch the DataFrame class 
pd.DataFrame.drop_column_levels = drop_column_levels 
+0

素晴らしい!私は 'stack'関数を知りませんでした!それは他のもののためにも便利になるかもしれません!それはうまく動作します – dmeu

0

続けドット・チェーンを許可するために1つのオプションは、新しいメソッドを定義することです列インデックスレベルを下げるpd.DataFrameクラスの場合これは猿パッチと呼ばれ、コードの移植性が低下します。

def reset_column_index(self, inplace=False): 
    if inplace: 
     self.columns = ['_'.join(tup) for tup in self.columns] 
    else: 
     c = self.copy() 
     c.columns = ['_'.join(tup) for tup in c.columns] 
     return c 

pd.DataFrame.reset_column_index = reset_column_index 

df.query('some query') 
    .apply(cool_func) 
    .reset_column_index() 
    .apply(another_cool_func) 

この方法を使用すると、複数のインデックスの列が1つのインデックスにフラット化され、名前がアンダースコアでマージされます。

#  foo   bar 
#  A  B  A  B 
# 0 17  2  0  3 
# 1  4 12  40 11 

# foo_A foo_B bar_A bar_B 
# 0 17  2  0  3 
# 1  4  12  40  11 
+0

あなたの提案をありがとう。私はそれが有効だと思う - しかし、私は互換性のために既に 'パッケージ化されている'オプションを選択する傾向があり、常に同じ機能を定義する必要はありません – dmeu

+0

私は完全に同意します。 @ジュリアンの答えはうまくいくようです。 – James

1

は、私はちょうどDataFrame.transpose()に相当DataFrame.Tフィールドを使用している別の解決策自分自身を見つけたなり。

df.query('some query') 
    .apply(cool_func) 
    .T.reset_index('unwanted_col_level_name',drop=True).T 
    .apply(another_cool_func) 
関連する問題