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

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

ただいまの
回答率

87.61%

pythonでpostgreSQL(psycopg2)とpandasを使い変数を配列で取得するにはどうしたら良いのでしょうか?

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 1,913
退会済みユーザー

退会済みユーザー

下記のようなテーブル(prices)からcodeを配列で取得するにはどうしたら良いのでしょうか?

code(text) date(text) price(integer)

111    2018-01-30    89    
111    2018-01-31    89    
111    2018-02-01    88    
111    2018-02-02    88    
222    2018-01-30    89    
222    2018-01-31    89    
222    2018-02-01    88
222    2018-02-02    88
333    2018-01-30    89    
333    2018-01-31    89    
333    2018-02-01    88    
333    2018-02-02    88


まずは下記のような関数を定義しました。

import pandas as pd
import psycopg2

def get_price(code):

    con = psycopg2.connect(
        host='localhost',
        port = '****',
        database='****',
        user='****',
        password='****'
    )

    return pd.read_sql('SELECT date, price '
                       'FROM prices '
                       'WHERE code = %s '
                       'ORDER BY date',
                       con,
                       params=(code),
                       parse_dates=('date',),
                       index_col='date')

そして、以下のようにすれば動的にデータが取り出せるかと思います。

a = get_price(111)
b = get_price(222)
c = get_price(333)


しかし、これだと取り出したいcodeの数だけコードを書かなければならないため、

prices = [111,222,333]

上記のように配列で記述し、データを取得するにはどのようにしたら良いでしょうか?
ちなみに、取り出した後は

prices = pd.concat([a, b, c], axis=1)

と言ったように横方向に結合し、使用します。

何方かアドバイスお願いします。

最終的には以下のようなデータを取得したいです。

date       111  222  333

2019-01-01   10.0    NaN    NaN
2019-01-02    NaN   20.0    NaN
2019-01-03    NaN    NaN   30.0

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

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

  • 退会済みユーザー

    退会済みユーザー

    2019/02/01 17:26

    can様
    確かにおっしゃる通りです!
    最終的に取り出したい形を質問本文に追加したのですが、いかがでしょうか?

    キャンセル

  • can110

    2019/02/01 17:31

    列名を変更するように回答コード修正しました。

    キャンセル

  • 退会済みユーザー

    退会済みユーザー

    2019/02/01 18:02

    ご丁寧にありがとうございます!
    今外出先なので、家に帰りましたらすぐに試してみます!
    本当にありがとうございました!

    キャンセル

回答 2

checkベストアンサー

+1

DB接続はcode毎のままで非効率ですが、以下のように書けばループで処理できます。

import sqlite3
import pandas as pd

# sqlite3用にSQLなど修正しています
def get_price(code):
    con = sqlite3.connect('test.db')

    return pd.read_sql('SELECT date, price '
                       'FROM prices '
                       'WHERE code = ? '
                       'ORDER BY date',
                       con,
                       params=[code],
                       parse_dates=('date',),
                       index_col='date')

codes = [111,222,333]
dfs = [get_price(code) for code in codes]
prices = pd.concat(dfs, axis=1)
prices.columns = map(str,codes) # 列名を変更
print(prices)
"""
             111   222   333
date
2019-01-01  10.0   NaN   NaN
2019-01-02   NaN  20.0   NaN
2019-01-03   NaN   NaN  30.0
"""

ついでに

ふつうに複数のcodeで絞った結果を返したい場合は以下のように書けます。

import sqlite3
import pandas as pd

def get_prices(codes):
    con = sqlite3.connect('test.db')
    where = ','.join(map(str,codes)) # codeを直埋め
    sql = 'SELECT date, price FROM prices WHERE code in ({}) ORDER BY date'.format(where)
    print(sql) # SELECT date, price FROM prices WHERE code in (111,222,333) ORDER BY date
    return pd.read_sql(sql, con,
                       parse_dates=('date',),
                       index_col='date')

prices = get_prices([111,222,333])
print(prices)
"""
            price
date
2019-01-01     10
2019-01-02     20
2019-01-03     30
"""

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

0

これだと取り出したいcodeの数だけコードを書かなければならないため

この問題の根本は、get_priceで発行しているSQLにあると思います。

SELECT date, price FROM prices ORDER BY date


などのように無制限(もしくは日付で上限をつけるなど)にし、もともと表形式のデータが抽出できるように路線変更すべきではないかと思います。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2019/02/01 17:01

    papinianus様
    コメントありがとうございます!
    ご指摘の通り、これだと問題があるかとは思いますが、実際はwhereで期間を絞り込む予定です。
    それを踏まえた上で回答頂けると嬉しいです。
    よろしくお願いします!

    キャンセル

  • 2019/02/01 17:17

    where句にcodeをかかないだけのことです。やろうとしていることからすると、なぜ一旦whereで絞ったのか、またpythonでのリスト処理においてあらかじめ、111や222などといったコード値が、プログラミングの段階で把握でき確定できているというのは状況として理解しにくいです(そのコードは全製品にあらかじめ与えられ、集計対象は確定しているのでしょうか?)

    キャンセル

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

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

関連した質問

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

  • トップ
  • Pythonに関する質問
  • pythonでpostgreSQL(psycopg2)とpandasを使い変数を配列で取得するにはどうしたら良いのでしょうか?