python - 重複 - 冗長なnanを持つカテゴリーを持つPandas groupby




pandas 重複 数える (4)

Pandas 0.23.0以降、 groupbyメソッドは、 True設定されている場合(デフォルトではFalse)、この問題を解決するパラメータをgroupbyできるようになりました。 下記は、オブザobserved=True追加observed=Trueれた質問とまったく同じコードです。

import pandas as pd

group_cols = ['Group1', 'Group2', 'Group3']

df = pd.DataFrame([['A', 'B', 'C', 54.34],
                   ['A', 'B', 'D', 61.34],
                   ['B', 'A', 'C', 514.5],
                   ['B', 'A', 'A', 765.4],
                   ['A', 'B', 'D', 765.4]],
                  columns=(group_cols+['Value']))

for col in group_cols:
    df[col] = df[col].astype('category')

df.groupby(group_cols, as_index=False, observed=True).sum()

カテゴリカルデータを持つパンダグループを使用して問題があります。 理論的には、これは非常に効率的なはずです。文字列ではなく整数を使用してグループ化とインデックス付けをしているのです。 ただし、複数のカテゴリでグループ化する場合は、カテゴリのすべての組み合わせを考慮する必要があると主張しています。

一般的な文字列の密度が低い場合でも、カテゴリを使用することがあります。これらの文字列は長く、メモリを節約し、パフォーマンスを向上させるためです。 各列に何千ものカテゴリがある場合があります。 3列でグループ化するとき、 pandasは1000 ^ 3グループの結果を保持するように強制します。

私の質問:この厄介な振る舞いを避けながら、 groupbyをカテゴリとともに使用する便利な方法はありますか。 私はこれらの解決策のどれも探していません:

  • numpyを介してすべての機能を再作成します。
  • groupby前に継続的に文字列/コードに変換し、後でカテゴリに戻します。
  • グループ列からタプル列を作成し、そのタプル列でグループ化します。

私はこの特定のpandas特異性だけを修正する方法があることを願っています。 簡単な例を以下に示します。 出力に必要な4つのカテゴリの代わりに、12になります。

import pandas as pd

group_cols = ['Group1', 'Group2', 'Group3']

df = pd.DataFrame([['A', 'B', 'C', 54.34],
                   ['A', 'B', 'D', 61.34],
                   ['B', 'A', 'C', 514.5],
                   ['B', 'A', 'A', 765.4],
                   ['A', 'B', 'D', 765.4]],
                  columns=(group_cols+['Value']))

for col in group_cols:
    df[col] = df[col].astype('category')

df.groupby(group_cols, as_index=False).sum()

Group1  Group2  Group3  Value
#   A   A   A   NaN
#   A   A   C   NaN
#   A   A   D   NaN
#   A   B   A   NaN
#   A   B   C   54.34
#   A   B   D   826.74
#   B   A   A   765.40
#   B   A   C   514.50
#   B   A   D   NaN
#   B   B   A   NaN
#   B   B   C   NaN
#   B   B   D   NaN

賞金の更新

この問題はパンダ開発チーム(cf github.com/pandas-dev/pandas/issues/17594 )によってあまり解決されていません。 したがって、私は次のいずれかに対処する回答を探しています。

  1. なぜ、パンダのソースコードを参照しても、グループ化された操作ではカテゴリカルデータの扱いが異なるのでしょうか。
  2. なぜ現在の実装が好まれるのでしょうか。 これは主観的なものですが、この質問に対する答えを見つけるのに苦労しています。 現在の振る舞いは、面倒で、潜在的に高価な、回避策なしでは多くの状況で法外なものです。
  3. groupby操作でカテゴリデータのパンダ処理を無効にするための明確な解決策はありますか? 3つのno-goルートに注意してください(おかしなところへのドロップ、コードとの間の変換、タプル列による作成とグループ化)。 他のパンダカテゴリ機能の損失を最小化/回避するために、「パンダ準拠」のソリューションをお勧めします。
  4. 既存の治療法を支持し明確化するためのパンダ開発チームからの回答。 また、すべてのカテゴリの組み合わせを考慮することがブール値パラメータとして設定できないのはなぜでしょうか。

バウンティアップデート#2

明確にするために、私は上記の4つの質問すべてへの答えを期待していません。 私が尋ねている主な質問は、カテゴリーがgroupby / set_index操作を容易にするように扱われるようにpandasライブラリメソッドを上書きすることが可能であるか、それとも推奨されるかどうかです。


カテゴリカルデータの操作のセクションに記載されているものと同様の動作が見つかりました。

特に、

In [121]: cats2 = pd.Categorical(["a","a","b","b"], categories=["a","b","c"])

In [122]: df2 = pd.DataFrame({"cats":cats2,"B":["c","d","c","d"], "values":[1,2,3,4]})

In [123]: df2.groupby(["cats","B"]).mean()
Out[123]: 
        values
cats B        
a    c     1.0
     d     2.0
b    c     3.0
     d     4.0
c    c     NaN
     d     NaN

Seriesgroupby関連する動作を説明する他の単語。 セクションの最後にピボットテーブルの例もあります。

Series.min()、Series.max()およびSeries.mode()とは別に、次の操作がカテゴリカルデータで可能です。

Series.value_counts()のようなシリーズメソッドは、データにいくつかのカテゴリが存在しなくても、すべてのカテゴリを使用します。

Groupbyは「未使用」のカテゴリも表示します。

単語と例は、 カテゴリカルデータから引用されています


私はこの記事が似たようなものをデバッグしている間に見つけました。 非常に良い投稿です、そして私は本当に境界条件の包含が好きです!

これが最初の目的を達成するコードです。

r = df.groupby(group_cols, as_index=False).agg({'Value': 'sum'})

r.columns = ['_'.join(col).strip('_') for col in r.columns]

この解決策のマイナス面は、(特に複数の統計がある場合)フラット化したい階層列インデックスになることです。 上記のコードに列インデックスのフラット化を含めました。

インスタンスメソッドがなぜなのかわかりません。

df.groupby(group_cols).sum() 
df.groupby(group_cols).mean()
df.groupby(group_cols).stdev()

.agg()メソッドでは、カテゴリカル変数のすべての一意の組み合わせを使用します。

df.groupby(group_cols).agg(['count', 'sum', 'mean', 'std']) 

グループの未使用のレベルの組み合わせを無視します。 それは矛盾しているようです。 .agg()メソッドを使用でき、直交座標の組み合わせの爆発を心配する必要がないことを嬉しく思います。

また、デカルト積と比較して、固有のカーディナリティー数がはるかに少ないことが非常に一般的であると思います。 データに "State"、 "County"、 "Zip"などの列があるすべてのケースを考えてみてください。これらはすべてネストされた変数であり、多くのデータセットには高度なネスト変数があります。

我々の場合では、グループ化変数のデカルト積と自然発生的な組み合わせとの間の差は1000倍以上です(そして開始データセットは1,000,000行以上です)。

そのため、Observed = Trueをデフォルトの動作にすることに投票しました。


私は本当にうまくいくはずの解決策を得ることができました。 より良い説明を付けて私の投稿を編集します。 しかし、その間に、これはあなたにとってうまくいったのでしょうか?

import pandas as pd

group_cols = ['Group1', 'Group2', 'Group3']

df = pd.DataFrame([['A', 'B', 'C', 54.34],
                   ['A', 'B', 'D', 61.34],
                   ['B', 'A', 'C', 514.5],
                   ['B', 'A', 'A', 765.4],
                   ['A', 'B', 'D', 765.4]],
                  columns=(group_cols+['Value']))
for col in group_cols:
    df[col] = df[col].astype('category')


result = df.groupby([df[col].values.codes for col in group_cols]).sum()
result = result.reset_index()
level_to_column_name = {f"level_{i}":col for i,col in enumerate(group_cols)}
result = result.rename(columns=level_to_column_name)
for col in group_cols:
    result[col] = pd.Categorical.from_codes(result[col].values, categories=df[col].values.categories)
result

そのため、これに対する答えは、通常のPandasの質問よりも適切なプログラミングのように感じました。 ボンネットの下では、すべてのカテゴリカルシリーズは、カテゴリの名前にインデックス付けされた単なる数字の束です。 これらの基礎となる数値は、カテゴリー型の列と同じ問題がないため、グループ化しました。 これを行った後、私は列の名前を変更しなければなりませんでした。 その後、from_codesコンストラクタを使用して、整数のリストを効率的にカテゴリカル列に戻します。

Group1  Group2  Group3  Value
A       B       C       54.34
A       B       D       826.74
B       A       A       765.40
B       A       C       514.50

だから私はこれがまさにあなたの答えではないことを理解していますが、私は私の解決策を将来この問題を抱えている人々のための小さな機能にしました。

def categorical_groupby(df,group_cols,agg_fuction="sum"):
    "Does a groupby on a number of categorical columns"
    result = df.groupby([df[col].values.codes for col in group_cols]).agg(agg_fuction)
    result = result.reset_index()
    level_to_column_name = {f"level_{i}":col for i,col in enumerate(group_cols)}
    result = result.rename(columns=level_to_column_name)
    for col in group_cols:
        result[col] = pd.Categorical.from_codes(result[col].values, categories=df[col].values.categories)
    return result

このようにそれを呼ぶ:

df.pipe(categorical_groupby,group_cols)




pandas-groupby