質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.31%
Jupyter

Jupyter (旧IPython notebook)は、Notebook形式でドキュメント作成し、プログラムの記述・実行、その実行結果を記録するツールです。メモの作成や保存、共有、確認などもブラウザ上で行うことができます。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

pandas

Pandasは、PythonでRにおけるデータフレームに似た型を持たせることができるライブラリです。 行列計算の負担が大幅に軽減されるため、Rで行っていた集計作業をPythonでも比較的簡単に行えます。 データ構造を変更したりデータ分析したりするときにも便利です。

Q&A

解決済

2回答

811閲覧

PythonのPandasでのデータ集計、カラム名の一部の値を抽出し、groupbyで集計したい

more83

総合スコア1

Jupyter

Jupyter (旧IPython notebook)は、Notebook形式でドキュメント作成し、プログラムの記述・実行、その実行結果を記録するツールです。メモの作成や保存、共有、確認などもブラウザ上で行うことができます。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

pandas

Pandasは、PythonでRにおけるデータフレームに似た型を持たせることができるライブラリです。 行列計算の負担が大幅に軽減されるため、Rで行っていた集計作業をPythonでも比較的簡単に行えます。 データ構造を変更したりデータ分析したりするときにも便利です。

0グッド

0クリップ

投稿2023/07/05 21:39

実現したいこと

Python(Jupyter notebookを使っています)、Pandasでデータ集計をしています。
CSVで取り込んだデータのうち、カラム名の一部(先頭の2文字と、3つ目の_(アンダーバー)移行の文字)のみを抽出し、
それが共通する単位で値を合計したいです。
例では抽出する文字は、01_100m、01_1000m、02_100m、02_1000mで、それぞれ2列が共通になるため2列分の値は合計して表出するイメージです。

  • 元データイメージ説明
  • 実現したいことイメージ説明

前提

カラム名のルールに例外はなく、先頭の数字は必ず2文字、_は3つあります。

発生している問題・エラーメッセージ

調べたコードを書いてみましたが、カラム名は先頭文字と_が連続する形で表出されてしまいます。

例 01___、01___、02___、02___

エラーメッセージは出ていません

該当のソースコード

Python

1import pandas as pd 2 3# DataFrameの作成(サンプル) 4data = read.csv(ファイル名) 5df = pd.DataFrame(data) 6 7# カラム名の最初の2文字と3つ目の_以降の文字列を抜き出してrename 8new_columns = {col: col[:2] + '_' + col.split('_', 2)[-1] if '_' in col else col for col in df.columns} 9df.rename(columns=new_columns, inplace=True) 10 11#カラム名が共通する列をグループ化し、各グループの合計を計算 12summary = df.groupby(df.columns).sum() 13summary

試したこと

renameする方法はいくつか試してみましたが、どれもうまくいきません。最後の5文字を抜く方法でもやってみましたが、できませんでした。
また、Stack関数で一度縦持ちにして処理することも検討しましたが、縦持ちにした際にカラム名が空になり、どの列に対する処理なのかを指定する部分がうまくいきませんでした。

最終的なgroupbyもこれだけで集計できるのかはわかりません。。

補足情報(FW/ツールのバージョンなど)

体系的な学習をしたことがなく、独学で調べながらpythonを使っています。
初歩的なところの理解が足りていない可能性がありますが、教えていただけましたら幸いです。
よろしくお願いいたします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

meg_

2023/07/05 22:02 編集

> 調べたコードを書いてみましたが、カラム名は先頭文字と_が連続する形で表出されてしまいます。 > 例 01___、01___、02___、02___ 「該当のソースコード」でそうなりますか?「01_有効_100m」みたいになりませんか?
more83

2023/07/08 07:23

コメントありがとうございます、そうなってしまうのです、outputでファイルも確認したのですが… 他のコードが影響しているのでしょうか・・
meg_

2023/07/08 10:40

> 他のコードが影響しているのでしょうか・・ 「該当のソースコード」以外の事はこちらには分かりません。 「他のコード」と言われましても何も分かりません。
more83

2023/07/10 02:37

上記ではできませんでしたが、下記で回答いただいた方法で解消しました。ありがとうございました。
guest

回答2

0

ベストアンサー

pandas の groupby は axis=1 でカラム方向の集計ができます。
また、カラムを rename してから集計するのではなく、rename用の dict を groupby のキーに渡して集計することができます。

https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.groupby.html

(質問のコードの col.split の引数は 2 ですが、正しくは 3 じゃないかと思います。)

python

1import pandas as pd 2 3df = pd.DataFrame( 4 [[0,1,0,0,0,0,2,1], 5 [0,3,1,3,0,1,0,3], 6 [1,0,0,2,1,3,0,1]], 7 index=[101,102,103], 8 columns=['01xx_aa_aa_100m','01xx_bb_bb_100m','02xx_aa_aa_100m','02xx_bb_bb_100m', 9 '01xx_aa_aa_1000m','01xx_bb_bb_1000m','02xx_aa_aa_1000m','02xx_bb_bb_1000m'] 10) 11 12new_columns = {col: col[:2] + '_' + col.split('_', 3)[-1] for col in df.columns} 13 14df_out = df.groupby(new_columns, axis=1, sort=False).sum() 15print(df_out) 16# 01_100m 02_100m 01_1000m 02_1000m 17# 101 1 0 0 3 18# 102 3 4 1 3 19# 103 1 2 4 1

投稿2023/07/06 00:13

bsdfan

総合スコア4899

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

more83

2023/07/08 07:41

早速ありがとうございました!!groupbyはaxis=1でカラム方向の集計ができるんですね…! 勉強不足でWebでもうまく調べられなかったのでとても助かりました、ありがとうございます。 >質問のコードの col.split の引数は 2 ですが、正しくは 3 じゃないかと思います。 引数は4でやりたいことができました。 非常に簡潔なコードで実現できる点が良かったのでベストアンサーにさせていただきます。 ありがとうございました。今後ともぜひよろしくお願いいたします。
guest

0

元データから作ったDataFrame を df とします。(ただしUIDdfのインデクスに使用するものとします。)

まず、'01男性_有効_有効_100m' という文字列から '01_100m' '01_100' という文字列を得る関数を作っておきます。

python

1import re 2 3def get_key(x): 4 return re.sub(r'^(\d{2})[^\d]+(\d+)m$', r'\1_\2', x)

この get_key(x) を使って列をグループ化し、同じキーとなる列を合計したSeriesを各列とするDataFarame total_df を作るには以下のようにします。

python

1from itertools import groupby 2 3col_groups = groupby(sorted(df.columns, key=get_key), key=get_key) 4total_df = pd.DataFrame( 5 {f'{key}m': df[cols].sum(axis=1) for key, cols in col_groups} 6)

追記1

以下の2点

  1. DataFrame.groupby メソッドを使うこと
  2. 最終的に得たい DataFrame のカラムの並び順を質問にあるように 01_100m, 01_1000m, 02_100m, 02_1000m とすること

が求められているのであれば、下記のようにします。(get_key関数は先述したものをそのまま使います)

python

1cols_map = {col: get_key(col) for col in df.columns} 2total_df = df.groupby(cols_map, axis=1, sort=True).sum().rename(columns=lambda col: f'{col}m')

上記のようにdf.groupby のキーワード引数 sort にTrueを指定しますが、このときに 上記の 2. のような列の並びを得るためには、get_key関数で得られる各列名のキーには末尾のm を含めないようにしておく必要があります。そのため集計してから、あらためて各列の末尾に m を付加しています。

上記の実行例:

イメージ説明

追記2

df.groupby の第1引数には、各列名に対応するグループ化するときのキーを得る関数をそのまま渡せるので、追記1に書いた2行

python

1cols_map = {col: get_key(col) for col in df.columns} 2total_df = df.groupby(cols_map, axis=1, sort=True).sum().rename(columns=lambda col: f'{col}m')

は、dict cols_map を作らずとも以下の1行で済むところでした。

python

1total_df = df.groupby(get_key, axis=1, sort=True).sum().rename(columns=lambda k: f'{k}m')

備考

さらにリファクタの思いつきですが、グループ化のキーに末尾の'm' を含めるか含まないかでソート結果が変わってしまうのを気にしたコードを書くのはやや煩雑なので

  • get_key関数は '01男性_有効_有効_100m' に対して ('01', 100) というタプルを返させるようにして、

  • 集計したDataFrameの列を rename するときの columns に、このタプルから '01_100m' を返すlambdaを指定する

というのもアリかなと思いました。

投稿2023/07/05 23:04

編集2023/07/06 06:41
退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.31%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問