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

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

ただいまの
回答率

91.35%

  • Python 3.x

    2424questions

    Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

  • pandas

    203questions

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

Pandas Dataframe で column毎に indexを設定してグラフ化したい

解決済

回答 1

投稿 2017/12/01 01:13 ・編集 2017/12/02 02:16

  • 評価
  • クリップ 1
  • VIEW 99

Ruthird

score 3

前提・実現したいこと

任意の波形を組み合わせて 比較分析する際、データの検索や表示がエクセルでは重くなりすぎて扱いづらく、
Python・Pandas で解決できないか考えています。

具体的には、
データフレーム形式になっている多数のcsvファイルの中から
1列ずつ読み込んで任意の組み合わせで別のデータフレームを組み上げ、
最後にpandasのプロット機能で1つのグラフにしたい。

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

現在は1つのファイルの中から 欲しいカラムを1つずつ数字入力で選択することで
必要なデータだけデータフレームに格納して グラフ化するところまで完成している。

読み込む多数のcsvファイルが現在はすべて同じindexの値・個数となっているので今は問題ないが、
今後はファイルによって異なるindexを持つ場合に対応した形にしたい。

【 追記 】
異なるindexの説明が不足していたので追記します。

例えば
csv_A index_A column_A1,A2,A3,・・・
csv_B index_B column_B1,B2,B3,・・・
という2つのファイルから欲しいカラムを合わせたデータフレームを作ると、

df_A+B index_A+B column_A1,A2,B1,B2

のようになるとします。この状態でグラフ化すると index_A+B を すべてのカラムが参照することになってしまいますが、
A1,A2 は index_A を参照
B1,B2 は index_B を参照
するようにしたいのです。

実際のcsvファイルのindex_AとB は 実数の物理値で、
今扱っているデータだと Aのインデックス2つに対して Bのインデックスが1つとなっており、
しかも index_A2 (A2n) = index_B1 (Bn) のような関係でもあるので、
普通に結合して出来上がった データフレームは
colum_An で2個存在したのち、column_Bn の数値が1つ交互に格納されます。

このデータフレームをプロットすると以下のような状態になってしまいます。
column_An は 歯抜け        (3回に1回データが存在しない)
column_Bn は 前半のプロットがない (前半は3回に2回データが存在しないので 線にならない)
![イメージ説明](55397fb76cb42ff99b676593eed988b4.png)

このような問題に Pandas あるいは Dataframe に良い解法はありますでしょうか?

【 追記2 】

イメージですみませんが、それぞれの中身の一例を示します。
A~D : csv_A の 中身
F~I : csv_B の 中身
K~Q : df_A+B の 中身
K列 が index_A+B です。

今回の場合は index_A の 2個目と index_B の 1個目 が 完全同一のため index_A+B は

5,10,15,20,25,30,・・・ 

となりましたが、小数点以下が異なる場合、

5(A), 10(A), 10(B), 15(A), 20(A), 20(B), 25(A), 30(A), 30(B), ・・・

(A):元index_A、 (B):元index_B です。
のようになってしまうこともあります。

分かりづらくて申し訳ありません。

イメージ説明

該当のソースコード

# -*- coding: utf-8 -*-
import pandas as pd
import matplotlib.pyplot as plt

# 読み込む CSVファイル を選択して データフレーム化する
df1 = pd.read_csv('sample1.csv', index_col=0)

# 繰り返し処理内変数 を 定義する
mode = 1        # 処理状態
wcount = 0      # 処理回数

paned = pd.Panel({})

# CSVから取得した データフレーム から 必要なデータのみ選択して
# 空のデータフレーム に 記載・追記する 繰り返し処理
while mode > 0:

    # 処理回数をアップさせる
    wcount = wcount + 1

    # 取得した CSV から グラフ化したい 列(カラム)を 1つずつ 数値入力する
    print('指定カラムは?')
    innum = int(input()) - 1

    # カウントが1のときのみ、取得カラムのインデックスを 空のインデックスに入力する
    # これだとカウント2以降でインデックスが変わる場合に対応できないため、暫定処理
    if wcount == 1:
        df2 = pd.DataFrame(index=[df1.index], columns=[])
        print(df2)
        print('')
    else:
        pass

    # データフレームに 選択したカラムとバリューを入力する
    # データフレームの追加処理、左辺でカラム名を、右辺でカラム名を除いたバリューを記載する
    df2[df1.columns[innum]] = df1.values[:,int(innum)]

    # データフレームにカラム・バリューを追記する処理 から 抜けるか、
    # もう1回カラム・バリューを追加するかを選択する
    print('終了? ⇒ 0 継続? ⇒ 1')
    inmode = int(input())

    # 選択結果から モードの値 を書き換える
    # 現状は 同じ CSV から 別のカラムを指定する場合のみ
    # CSVファイルを変える、CSVファイルのディレクトリを変える、などの処理を追加のこと
    if inmode == 0:
        mode = 0
    else:
        mode = 1


df2.plot()

# # グラフタイトレイアウト
plt.tight_layout()

plt.savefig("sample.png")
plt.show()

試したこと

1つのカラムだけで1つのデータフレームにすればインデックスも任意にできるが、
この場合だと複数のデータフレームを持つことになり、1つのグラフにまとめて表示できなかった。

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

Python3.6、Pandas
Python歴2ヶ月で初質問のため、不作法などあるかもしれませんが ご容赦ください。

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

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

  • KojiDoi

    2017/12/01 04:09

    プログラムコードを示すときは、コードの前後の行に```を置いてください。特にpythonの場合インデントがちゃんと見えていないとチェックが困難です。

    キャンセル

  • Ruthird

    2017/12/01 08:57

    大変失礼いたしました。ご指摘ありがとうございます。

    キャンセル

  • KojiDoi

    2017/12/02 01:43

    すみませんが、追記された説明がサッパリ解りません。 csv_A, csv_B, df_A+B, index_A+B これらの実際の内容(一部でいいです)を示していただけませんか?

    キャンセル

  • Ruthird

    2017/12/02 02:17

    一例を追記しました。お手数ですがご確認ください。

    キャンセル

回答 1

checkベストアンサー

+3

とりあえず質問に挙げていただいたコードですが、カラム選択するたびにDataFrameに1列ずつ追加していくのではなく、選択されたカラム番号をリストに保持しておいて、最後にDataFrame.iloc() を使用してViewを生成すると、もう少しシンプルに記述できるかと思います。

こんな感じ

import pandas as pd
import matplotlib.pyplot as plt

# 読み込む CSVファイル を選択して データフレーム化する
df1 = pd.read_csv('sample1.csv', index_col=0)

selected_columns = []
while True:
    # 取得した CSV から グラフ化したい 列(カラム)を 1つずつ 数値入力する
    innum = int(input('指定カラムは?( 0 の場合は終了): '))

    # 終了の場合はデータを作成してループを抜ける
    if innum == 0:
        df2 = df1.iloc[:,selected_columns]
        break;

    # 選択されたインデックスをリストに追加
    selected_columns.append(innum - 1)

if not df2.empty:
    df2.plot()
    plt.tight_layout()
    plt.savefig("sample.png")
    plt.show()

次に質問にある複数ファイルから選択された列を結合する方法ですが、上記のループの外にもう一つファイル毎のループを作成する事になります。
で、ファイル毎で作成された新しいDataFrameは、順次リストに格納していき、最後にまとめて pandas.concat() を用いることで全てのDataFrameを結合することが出来ます。

この方法でしたら、各ファイル毎でIndex値に不整合があった場合でも問題ありません。データが無い箇所は NaNが入ることになります。

また、ファイルリストの作成ですが、globを使ってワイルドカードを使って指定する方法が簡単かと思います。

ということで、サンプルを書きましたので参考にしてください。

import pandas as pd
import matplotlib.pyplot as plt
import os
import glob

files = glob.glob('data/*.csv')
dfs = []
for file in files:
    basename = os.path.splitext(os.path.basename(file))[0]
    df = pd.read_csv(file, index_col=0)
    selected_columns = []
    while True:
        print('FILE : {}'.format(basename))
        innum = int(input('指定カラムは?( 0 の場合は次ファイル): '))

        # 終了の場合はデータを作成してループを抜ける
        if innum == 0:
            dfs.append(df.iloc[:,selected_columns].copy())
            break;

        # 選択されたインデックスをリストに追加
        selected_columns.append(innum - 1)

df2 = pd.concat(dfs, axis=1)
# 以下省略

投稿 2017/12/01 09:45

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/12/02 01:37

    ご回答ありがとうございます。
    カラム番号だけ保持してシンプル化し、データフレームの結合機能を扱うと とても分かりやすくなるのですね。

    ただ、自分の説明が不足しており、まだ解決には至っておりません。
    本当にやりたかったことは 異なる index を 結合後の DataFrame でも参照できるようにすることです。
    説明を追記してみましたので、もしこちらの内容で良きアイデアがあれば引き続きサポートをお願いします。

    キャンセル

  • 2017/12/02 12:21 編集

    Pandasではデータの無いセルを dropna() で削除することができますので、dropna()を適用した後で、plot() すると良いのではないでしょうか。
    ただ、df2 に dropna()を適用してしまうと、Nanを含む行全部を削除してしまうので、Column毎にループを回して、列単位で dropna().plot() を行ってみたらいかがでしょうか。
    こんな感じ(__ は スペースに読み替えてください)

    ax = plt.show()
    for name,col in df2.iteritems():
    __col.dropna().plot(ax=ax)
    plt.tight_layout()
    plt.savefig("sample.png")

    キャンセル

  • 2017/12/03 01:27 編集

    おかげさまで意図したことが実現できましたので、
    ベストアンサーにさせていただきました。

    列単位 で dropna().plot() という考え方はかなり盲点でした。
    こうすれば確かに index 自体が増えてしまっても 個々に plot できますね。
    いろいろ参考にさせていただきます。
    ありがとうございました。

    キャンセル

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

ただいまの回答率

91.35%

関連した質問

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

  • Python 3.x

    2424questions

    Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

  • pandas

    203questions

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