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

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

ただいまの
回答率

88.77%

groupbyを使った集計

解決済

回答 4

投稿

  • 評価
  • クリップ 0
  • VIEW 369

kumer1

score 26

前提・実現したいこと

groupby機能を使って同じキーワードで巻数が付いているのものをまとめたいです。
例えば、このようなCSVがあった場合、

作品名|著者|売上
愛してる(1)|もぎ|100
愛してる(1)|もぎ|200
愛してる(2)|もぎ|300
愛してる(2)|もぎ|400
愛してる(3)|もぎ|500
愛してる(3)|もぎ|600

作品名|著者|売上
愛してる|もぎ|2100

としたいです。

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

ここまではできますがこれ以上はできない。。
作品名|著者|売上
愛してる(1)|もぎ|300
愛してる(2)|もぎ|700
愛してる(3)|もぎ|1100

該当のソースコード

import pandas as pd
import csv,json

df = pd.read_csv("xxx.csv", encoding="shift-jis")
df = df.groupby("作品名", as_index=None).sum()
print(df)

試したこと

上記ソースコードでエラーに記載したような部分まではできるのですが、(1)、(2)と(3)をまとめるスキルがありませんのでご教授ください。

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

MAC OS High Sierra
ver.10.13.6
Python 3.4.3
ここにより詳細な情報を記載してください。

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • hayataka2049

    2019/05/23 23:10

    巻数のフォーマットは定まっていますか?
    そのフォーマットだけならやりようはあると思いますけど、「愛してる1」とか「愛してる 一」とか「愛してる壱」とか出てきたときに収拾がつかなくなる可能性が高いです。

    キャンセル

  • kumer1

    2019/05/23 23:11

    はい。前提としてフォーマットは(1)・・・で続いていく形になります。

    キャンセル

回答 4

checkベストアンサー

+2

素直に"作品名"と"巻数"を分離したDataFrameに変換しておくと良いかと思います。

import pandas as pd
import io

s = '''作品名|著者|売上
愛してる(1)|もぎ|100
愛してる(1)|もぎ|200
愛してる(2)|もぎ|300
愛してる(2)|もぎ|400
愛してる(3)|もぎ|500
愛してる(3)|もぎ|600'''
df = pd.read_csv(io.StringIO(s), encoding="utf-8", sep='\|||')

df = df["作品名"].str.extract('(\D*)\((\d+)\)', expand=False).rename(columns={0:'作品名',1:'巻数'}).join(df.drop('作品名', axis=1))
#    作品名 巻数  著者   売上
#0  愛してる  1  もぎ  100
#1  愛してる  1  もぎ  200
#2  愛してる  2  もぎ  300
#3  愛してる  2  もぎ  400
#4  愛してる  3  もぎ  500
#5  愛してる  3  もぎ  600

ret = df.groupby(['作品名','著者']).agg({'売上':'sum'}).reset_index()
#    作品名  著者    売上
#0  愛してる  もぎ  2100

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/05/24 23:56

    ありがとうございます。sepの部分が|||でエラーが出てしまいます。また'(\D*)\((\d+)\)'の正規表現の意味を知りたいです。

    キャンセル

  • 2019/05/25 10:09

    まず正規表現ですが、"\D*"は数字以外(0文字以上)、”\d+”は数字(1文字以上)に対応し、"\(" および "\)" はそのまま括弧に対応しておりますので'\D*\(\d+\)' にて元の作品名にマッチします。
    で、今回はそのうちの タイトル部 "\D*" と巻数 "\d+" の部分を列として抜き出したいわけですので、その部分をさらに括弧 "()" で囲うことでグループ化しております。で結果 "(\D*)\((\d+)\)" となります。

    キャンセル

  • 2019/05/25 10:20

    今回のCSVファイルの区切り文字ですが、質問のサンプルでは何故か全角の "|" と半角の "|" が混在しております。これが混在していないのであれば単に sep="|" や sep="|" などで動作するのですが、区切り文字が2つあるので正規表現の or('|') を使って "\|" or('|') "|" としているわけです。
    私の環境では上記で動作しているのですが、もし動作しないのであれば、engine='python' パラメータを指定してみてください。(できるのであれば、区切り文字を1種類に統一する方が良いかとおもいますが。)

    キャンセル

0

アラビア数字になっていればなんとかしてくれる方法は誰かが教えてくれそうなので、
アラビア数字に変換する方法が記されているリンクを提示いたします。

https://qiita.com/dosec/items/c6aef40fae6977fd89ab


ちなみに数字部分だけが異なるのであれば、正規表現を使うとよいです。


import pandas as pd
import io

s = '''作品名|著者|売上
愛してる(1)|もぎ|100
愛してる(1)|もぎ|200
愛してる(2)|もぎ|300
愛してる(2)|もぎ|400
愛してる(3)|もぎ|500
愛してる(3)|もぎ|600'''
s = s.replace('|', ',')
s = s.replace('|', ',')

df = pd.read_csv(io.StringIO(s), encoding="utf-8")

df = df.groupby(df["作品名"].str.extract('(\D*)\(\d+\)', expand=False), axis=0).sum()
print(df)

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

もう少しスマートな方法もあるかもしれませんが、とりあえずこれで。

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

import io
import pandas as pd

txt = """
作品名,著者,売上
愛してる(1),もぎ,100
愛してる(1),もぎ,200
愛してる(2),もぎ,300
愛してる(2),もぎ,400
愛してる(3),もぎ,500
愛してる(3),もぎ,600
"""

df = pd.read_csv(io.StringIO(txt), sep=",")
df = df.groupby(df["作品名"].str.replace(r"\(\d+\)", ""), as_index=None).sum()
print(df)
""" =>
     売上
0  2100
"""

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/05/23 23:42

    ただ売上以外の列が消えると困るなぁ、どうやって直そ

    キャンセル

0

これで

import pandas as pd
import csv,json

df = pd.read_csv("xxx.csv", encoding="shift-jis")
df = df.replace('\(\d+\)','', regex=True)
df = df.groupby("作品名", as_index=None).sum()
print(df)

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

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

  • ただいまの回答率 88.77%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る