Spotify APIを用いた、印象語による楽曲検索(距離計算編)

https://qiita.com/minato-bb/items/9a3c2c5a1aa9ae73a76c

上の続きです
![スクリーンショット 2021-06-10 10.17.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/649181/173f9dbb-51d2-ff24-95f2-10bee50214cd.png)




今回はimpressionのテーブルの定義とmain.pyの部分を記事にします
シェルスクリプトで関数を実行するために以下の記事を参考にしました

https://qiita.com/kenichi-hamaguchi/items/dda5532f3b218142e7c9

main.pyの中身はこうなっています

```python:main.py
import argparse
import norm

#距離計算
# python main.py music_impression -i '{印象語}'

def music_impression(name):
    norm.distance(name)

if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument('function_name',
                        type=str,
                        help='set fuction name in this file')
    parser.add_argument('-i', '--func_args',
                        nargs='*',
                        help='args in function',
                        default=[])
    args = parser.parse_args()

    # このファイル内の関数を取得
    func_dict = {k: v for k, v in locals().items() if callable(v)}
    # 引数のうち，数値として解釈できる要素はfloatにcastする
    func_args = [float(x) if x.isnumeric() else x for x in args.func_args]
    # 関数実行
    ret = func_dict[args.function_name](*func_args)
```

今回中にあるのはnorm.py(距離計算)だけです

実行環境
macOS Catlina 10.15.7
Python 3.7.5

# impressionテーブル
main.pyはimpressionテーブル(以下impression)とmusicテーブル(以下music)の距離計算で上位10曲を表示するというものになっています
musicはSpotify APIを用いているのでimpressionの正確さが結果の正確さに直結します

ここに客観性かつ正確性を持たせるために現在思案中です
とりあえずは25人にそれぞれの印象に当てはまる曲を挙げてもらい、平均を出しました

```
fc=# select * from impression;
  word   | danceability | acousticness |  energy  | liveness | loudness  | speechiness |   tempo    | valence
---------+--------------+--------------+----------+----------+-----------+-------------+------------+----------
 excited |     0.559412 |     0.238991 | 0.753471 | 0.177212 | -6.361706 |      0.1073 | 128.399882 | 0.565765
 cool    |     0.533333 |     0.176618 | 0.796208 | 0.214154 | -5.769667 |      0.0718 | 124.457208 | 0.456937
 relax   |       0.5335 |     0.420415 | 0.604963 | 0.161387 | -7.346125 |    0.069258 | 121.235208 | 0.504838
 sad     |        0.509 |     0.403961 | 0.593177 | 0.183709 | -6.792652 |    0.046196 | 119.219565 | 0.408422
 fierce  |      0.53716 |     0.136491 | 0.823628 |   0.1822 |   -5.7808 |    0.099324 |  132.39152 | 0.505112
```

# 距離計算
```python:norm.py
import psycopg2

def distance(name):
    conn = psycopg2.connect("host=" + "localhost" +
                            " dbname=" + {データベース名} +
                            " user=" + {自分のmacのユーザーネーム} +
                            " password=" + "")
    cur = conn.cursor()
    cur.execute("SELECT * FROM music")
    m = cur.fetchall()
    conn.commit()
    print("The number of music is ", len(m))
    conn.commit()
    cur.execute("SELECT music.name, music.artist, distance(music.danceability, music.acousticness, music.energy, music.liveness, music.loudness, music.speechiness, music.tempo, music.valence, impression.danceability, impression.acousticness, impression.energy, impression.liveness, impression.loudness, impression.speechiness, impression.tempo, impression.valence) AS score FROM music, impression WHERE impression.word = '{}' ORDER BY score ASC FETCH FIRST 10 ROWS ONLY".format(name))
    n = cur.fetchall()
    conn.commit()
    print()
    print(name)
    for n_ in n:
        print(n_)
    print()
    cur.close()
    conn.close()

    return
```
distanceという関数をsqlで定義しています
これは距離計算をする関数です

```sql:norm.sql
CREATE FUNCTION distance(float, float, float, float, float, float, float, float, float, float, float, float, float, float, float, float) RETURNS float 
AS 'SELECT sqrt(($1 - $9)^2 + ($2 - $10)^2 + ($3 - $11)^2 + ($4 - $12)^2 + ($5 - $13)^2 + ($6 - $14)^2 + ($7 - $15)^2 + ($8 - $16)^2 ) AS distance'
LANGUAGE 'sql';
```
# 実行結果(fierce)
こんな感じに結果が出てきます

```
~/music2imp$ python main.py music_impression -i 'fierce' 
The number of music is  2849

fierce
('Fxxker', 'CHANMINA', 0.4662540877118465)
('よー、そこの若いの', 'Takehara Pistol', 0.484637866437422)
('Tik Tik Tok (Rhythm of the Clock) - Original Mix', 'Kid Alina', 0.4947239347393736)
('Dark Horse', 'Katy Perry', 0.6637707380602147)
('ダンシング・ヒーロー(Eat You Up)', 'Yoko Oginome', 0.7221408093890002)
('インフルエンサー 〜off vocal ver.〜 - Off Vocal Version', 'Nogizaka46', 0.7878546612066344)
('pov', 'Ariana Grande', 0.7881882205317551)
('ONLY ONE', 'SPiCYSOL', 0.800737013372686)
('格好悪いふられ方', 'Senri Oe', 0.8075263077974683)
('19 GROWING UP -ode to my buddy-', 'PRINCESS PRINCESS', 0.8426145755830627)
```