pythonでデータ操作を行う時の作業用コードメモ


pythonでデータ操作を行う時のコードメモです。
コードスニペット的な感じで作業時にコピペして使うようなのであんまり説明とか入れないです。
緩めに不定期更新します。

# 日付操作

### 色々な日付の取得

```python

# ライブラリ読み込み
from datetime import datetime, date, timedelta

# 本日を取得
today = datetime.today()

# 前日を取得（形式を'%Y-%m-%d'に変更）する
yesterday = (today - timedelta(days=1)).strftime('%Y-%m-%d')

# 本日の日付からその日付を引くことで、先月末日を算出
last_month_day = today - timedelta(days=today.day)

# 先月末日の年月情報のみを取得
last_month = last_month_day.strftime("%Y-%m")

# 本日と先月末までの日数差分を取得
diff_days = today - last_month_day

# 日数差分はtimedelta型になる為、日数情報を抽出するには、daysをつける
diff_days.days

```


# pandasでのデータ操作

```python

# ライブラリ読み込み
import pandas as pd 

```

### リスト型のデータ(スプレッドシートやDBから取得した値)をデータ抽出の為に、pandasのデータフレームに変換する

```python

# pandasのDataFrameで、 dataというリスト型のデータの１行目をヘッダーにして、２行目以降をデータにする
df = pd.DataFrame(data[1:], columns = data[0])

```


### dfから指定した項目を取り出す（複数項目）

```python

### 処理必要な項目に絞る(dfの中に色々な項目が入っていて、以下ではタスク、状態、完了日の３項目を抽出する
df_select = df[['タスク','状態','完了日']]

```

### 項目の中からデータ内容を指定して抽出する(queryを利用）

```python

# 状態に”済”が入っているデータのみを抽出する
df_finish_task = df_select.query('状態 == ["済"]')

```

### データを明示的にコピーする（dfに項目追加などを行う時に、参照渡しのワーニングが出る場合がある為、回避用に明示的にデータをコピーしておく）

```python

df_copy = df_finish_task.copy()

```

### 項目追加する（文字列型の日付情報を日付型にして追加）

```python

# 日付操作用に日付項目を追加(以下コードでは完了日から、完了年月というDATE項目を追加している)
df_copy['完了年月'] = pd.to_datetime(df_copy['完了日'], format='%Y-%m-%d').dt.strftime('%Y-%m')

```

### 項目変換する

```python

# 項目名を変更したいときに利用する
df = df.rename(columns={'タスク': 'Task'})


```


### 対象データをソートしてから、抽出データを絞る(SQLで言うところの order by 項目名 limit 5 的な使い方）

```python

# sort_valuesで完了年月を昇順にして5件分のデータを抽出
df_sort5 = df_copy.sort_values('完了年月')[0:4]

```

### 対象データに特定の文字が含まれるデータのみ抽出する

```python

# str型のみ対応しているので、項目をastype(str)で変換してから、抽出する
# 以下では、完了年月をstr型に変換してから、30という数字が含まれる情報を取り出している
df[df['完了年月'].astype(str).str.contains('30')]

```



### データフレームをリスト型に戻す

```python

# pandasのDataFrameからリストに戻す
df_list = df_sort5.values.tolist()

```

### データの結合

```python

# 同一レイアウトのデータフレーム２つを１つに結合する(SQLのUNION的な）
df = pd.concat([df1, df2])

# 複数レイアウトのデータフレームをKEYを基にして結合する（SQLのJOIN的な）
# df1とdf2にある、idという項目が一致しているものがあれば、JOINして1つのdfを作成する。
# その際に、suffixesを指定することで、df1とdf2に同じ項目名があれば、１つ目の項目に_df1をつける、2つ目の項目に_df2をつける
df = pd.merge(df1, df2, how='left', on='id', suffixes=['_df1','_df2'])

```

### カラムの削除

```python

# 削除したい項目を指定する
del df['完了年月']

```


### オープンデータを読み込む

※厚生省のオープンデータのレイアウトが変更されたようなので、コードなどを更新しました(2021/12/17時点)

```python

# 厚生労働省のオープンデータ（コロナ感染者数）のURLを指定
url = 'https://covid19.mhlw.go.jp/public/opendata/newly_confirmed_cases_daily.csv'

# pandasのread_csvを利用して、データをdfに格納する
df = pd.read_csv(
    url, # URLを指定
    encoding="utf-8" # 文字コードをutf-8で取得
    )  

# 取得したデータから必要項目のみを抽出
df = df[['Date', 'ALL', 'Tokyo', 'Kanagawa']]

# 取得したデータの表示
df.tail()

```

上記を実行するとこんな感じでのデータが取得されます。
![スクリーンショット 2021-12-17 18.37.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/242038/955031d6-2f38-a074-d016-9e837552238d.png)


### Pandasデーターフレームのセル値を取り出す方法

```python

# dfにある１行目のデータのcountという項目を取得する。
df.iloc[0]['count']

# dfにある最終行のデータのcountという項目を取得する。
df[-1:].iloc[0]['count']

```

データフレーム使い始めの時はデータ取得方法どうだったっけ？って結構悩んだりしましたが、これで解決！
また時間たったら使い方忘れると思うので、その時はここを見て思い出します。


### データフレームから項目を指定削除する 

```python

# 分析に不要な項目を削除する
df.drop(['column_name1', 'column_name2'], axis=1, inplace=True)

```

### 項目から重複するリストを取得する

```python

### unique関数を利用して一意な項目を出力する
df['項目名'].unique()

### nunique関数を利用して、一意な項目数を出力する 
df['項目名'].nunique()

```






# 例外処理

### python実行時のパラメータ入力値が特定の値でないときにエラー出力する

```python

# argsでパラメータを取得する
import sys

# 実行時のパラメータを変数として取得する
args = sys.argv

if args[1] not in ['apple', 'orange']: 
    raise Exception('入力値が「apple」と「orange」以外の為、処理を中断しました:入力値 {}'.format(args[1])) 

```

### warningを非表示にする

```python

import warnings
warnings.filterwarnings('ignore')

```



# 繰り返し処理

## for文(単一項目）

```python

names = ['信長', '家康', '秀吉', '信玄']

for name in names:
    print(f'{name}さん')

```

**実行結果**
信長さん
家康さん
秀吉さん
信玄さん


## for文(zip:複数項目）


```python

first_names = ['信長', '家康', '秀吉', '信玄']
last_names = ['織田', '徳川', '豊臣', '武田']

for last_name, first_name in zip(last_names, first_names):
    print(f'{last_name}{first_name}さん')

```

**実行結果**
織田信長さん
徳川家康さん
豊臣秀吉さん
武田信玄さん

## for文(enumerate:インデックス付き項目）


```python

last_names = ['織田', '徳川', '豊臣', '武田']

for i, last_name in enumerate(last_names):
    print(f'インデックス番号{i}番目の{last_name}さん')

```

**実行結果**
インデックス番号0番目の織田さん
インデックス番号1番目の徳川さん
インデックス番号2番目の豊臣さん
インデックス番号3番目の武田さん

# 条件分岐

### IF文

```python

# rateの値によって、当てはまる範囲を表示する。
if rate >= 1.0:
    text = '比率は、1.0以上です'
elif 0.5 <= rate < 1.0:
    text = '比率は、0.5~1.0の範囲です'
else:
    text = '比率は、0.5未満です'

print(text)

```




# 集計関数


### 時系列（日別）のデータを週別、月別、年別などで集計する

```python

# 週別に集計（平均）
df.resample("W").mean()

# 月別に集計（平均）
df.resample("M").mean()

# ４半期(3ヶ月）単位で集計（平均）
df.resample("3M").mean()

# 年別で集計（平均）
df.resample("Y").mean()

```

### 日付に曜日を追加して集計する方法

```python

# 日付(target_date)から曜日を算出して、dfに曜日を追加する
df["曜日"] = df.target_date.strftime("%A")

# 曜日ごとに集計を行う
df.groupby("曜日"）.mean()

```

### 小数点以下の四捨五入を行う方法

```python

a = 8793
b = 15997

# aをbで割ると
print(a / b)
> 0.54966556229293

# aをbで割った結果に、round関数を使って小数点２桁に四捨五入する
print(a / b).round(2)
> 0.55 

```

### リストの長さを出す

```python

len(a)

```


# 型変換

### キャスト関数

```python

# 文字列を数字型に変換する
a = int('1')

# 文字列を不動小数点型に変換する
b = float('1.5')

# 数字を文字列に変換する
c = str(2)


```

# フォーマット変換

### 数値３桁ごとにカンマを入れる

```python

a = 8793

"{:,}".format(a)
> '8,793'

```


# リスト処理

### リストの中身を結合して１つのテキストに変換する

```python

# リストの設定
rainfall_list = ['19時の降水確率: 10.0%', '20時の降水確率: 30.0%', '21時の降水確率: 50.0%']

# リストを結合して一つのテキストにする
'\n'.join(rainfall_list)
>19時の降水確率: 10.0%\n'20時の降水確率: 30.0%'\n21時の降水確率: 50.0%'

```



# ハッシュ変換

### ハッシュ値を算出する

```python

# ライブラリ読み込み
import hashlib

# ハッシュ作成元のdict型データを用意
data = {'x': 1, 'y': 2}

# ハッシュ値の作成(MD5)
hashlib.md5(str(data).encode()).hexdigest()

# 作成されたハッシュ値 => '43291a196ad76391a31ed17786a8fa8d'

# ハッシュ値の作成(sha256)
hashlib.sha256(str(data).encode()).hexdigest()

# 作成されたハッシュ値 => '9c46e802352d48ad1475a8dcb85856aa64e5cd676f70cc543db0dccfa621a606'

# ハッシュ値の作成(sha512)
hashlib.sha512(str(data).encode()).hexdigest()

# 作成されたハッシュ値 => '34fea2781b66b315f8c9f80e09e61091cc57b30d014fa2d14d8cc4c53b2abb6ebb8764327e891ab4fc16560169265770994b6fce9fcad34835b6cc179d2a81de'


```


# スクレイピング

### ニュース情報を取得する例

```python

# ライブラリ読み込み
import requests
from bs4 import BeautifulSoup

# 読み込むURLを指定する(以下ではyahooニュースのトップ情報を指定）
url = "https://news.yahoo.co.jp/topics/top-picks"

# requestsで指定したURLの情報を取得する
res = requests.get(url)

# 取得した情報の文字化けを修正する
res.encoding = res.apparent_encoding

# BeautifulSoupを活用して、文字を整形する
soup = BeautifulSoup(res.text, "html.parser") 

# 記事のタイトルを表示
soup.title

# 出力結果
> <title>主要トピックス一覧 - Yahoo!ニュース</title>

```

### サイトの文字コード確認

```python

import requests

# 読み込むURLを指定する(以下ではyahooニュースのトップ情報を指定）
url = "https://news.yahoo.co.jp/topics/top-picks"

res = requests.get(url)
res.apparent_encoding

# 出力結果
> utf-8

```

### RSSフィードのスクレイピング

```python

## feedparserのインストール
!pip3 install feedparser
 
import feedparser

# yahooニュースの主要トピックのRSSを利用
rss_url = "https://news.yahoo.co.jp/rss/topics/top-picks.xml"

feed = feedparser.parse(rss_url)

print("### yahooニュースの主要トピック一覧(URL付) ###")

for i, entry in enumerate(feed.entries):
  print(f"no.{i+1} : {entry.title}({entry.link})")

# 出力結果（例）
> 
### yahooニュースの主要トピック一覧(URL付) ###
no.1 : 戦後最長 麻生財務相が遺した物(https://news.yahoo.co.jp/pickup/6406579?source=rss)
no.2 : 林間学校で小学生ら83人食中毒(https://news.yahoo.co.jp/pickup/6406588?source=rss)

~ 省略　~

no.7 : 奮起促す?G原監督がノッカー役(https://news.yahoo.co.jp/pickup/6406583?source=rss)
no.8 : おぼんこぼん和解 参列者知らず(https://news.yahoo.co.jp/pickup/6406590?source=rss)

```

### wikipediaから設定したワードを取得する

```python

# インストール
!pip install wikipedia
import wikipedia

# 日本語設定
wikipedia.set_lang("ja")

# 検索したいワードを設定
word = "呪術廻戦"

# データの取得
res = wikipedia.search(word)

# データの表示
print(res)
> ['呪術廻戦', '呪術廻戦 (アニメ)', 'King Gnu', 'ばかうけ', '毎日放送の深夜アニメ枠', '東潤一', '芥見下々', 'Eve (歌手)', '一途/逆夢', '廻廻奇譚']


# テキスト情報の表示
text = wikipedia.page(res[1]).content
text
> 『呪術廻戦』（じゅじゅつかいせん）は、芥見下々による同名の漫画を原作としたテレビアニメである。2020年10月3日から2021年3月27日まで毎日放送・TBS系列『スーパーアニメイズム』枠ほかにて放送された。
2021年12月24日には、『呪術廻戦 0 東京都立呪術高等専門学校』を原作とする劇場アニメ『劇場版 呪術廻戦 0』（げきじょうばん じゅじゅつかいせん ゼロ）が東宝の配給により、IMAX版とともに公開された。

~省略~

『呪術廻戦』アニメ公式 (@animejujutsu) - Twitter
『呪術廻戦』アニメ公式 (animejujutsu_official) - Instagram
TVアニメ『呪術廻戦』 - YouTubeプレイリスト

```




### 株価の値上がり率ランキング情報を取得する

```python

import pandas as pd

# Kabutanの株価上昇率ランキングのURLを指定
url = "https://kabutan.jp/warning/?mode=2_1"

# データを取得してpandasデータフレームを作成
df_pond = pd.read_html(url)

# 内容確認
df_pond[2].head()

# 出力結果（例）
> 
	コード	銘柄名	市場	Unnamed: 3	Unnamed: 4	株価	Unnamed: 6	前日比	前日比.1	出来高	ＰＥＲ	ＰＢＲ	利回り
0	7777	３ＤＭ	ＪＧ	NaN	NaN	382	S	+80	+26.49%	8891300	－	16.24	－
1	6335	東京機	東１	NaN	NaN	2018	S	+400	+24.72%	1639600	56.8	2.37	－
2	4673	川崎地質	ＪＱ	NaN	NaN	4940	S	+700	+16.51%	65800	12.5	1.13	1.01
3	6555	ＭＳコンサル	東１	NaN	NaN	712	S	+100	+16.34%	33700	21.7	1.13	－
4	7585	かんなん丸	ＪＱ	NaN	NaN	910	NaN	+125	+15.92%	1012300	－	2.94	－

```




# ファイル操作

## フォルダを作成する

```python

from pathlib import Path

# 作成するフォルダの名前を指定してmkdirする（同名のフォルダがない場合のみ作成、あれば何もしない）
output_folder = Path("text_folder")
output_folder.mkdir(exist_ok=True)

```

# 文字列操作

## 文字のクリーニング

```python

# ライブラリ読み込み
import re

# 文章の作成
text = '【Hello Python!】'

changed_text = re.sub(r'[【】]', ' ', text)  #【】を除外する
changed_text
> Hello Python!

```


# 欠損値処理

## 項目の欠損値と比率を確認

```python:項目の欠損値と比率を確認

# 欠損情報を確認したい項目を記入
check_col = "keyword"

# 欠損数を取得
total = df[check_col].isnull().sum()

# 欠損率を取得
percent = round(total/len(df[check_col])*100, 2)

# 欠損情報の表示
print(f'{check_col}の欠損値は{total}で、欠損率は{percent}%です')
> keywordの欠損値は1113で、欠損率は2.78%です

```

# 外部接続処理

## Googleドライブへの認証（接続）

以下のコードを実行した後に、
Enter your authorization code:
と認証のためのコードを求められるので、それぞれ表示されたURLへアクセスしてコードを入手して貼り付ける

```python

from google.colab import drive
drive.mount('/content/drive')

```

## bigqueryへの認証（接続）

```python

from google.colab import auth
auth.authenticate_user()

```


# サンプリング

## ランダムにデータを抽出する

```python

import random
random.sample(df, 10000)  # 抽出するデータと件数を指定(ここでは10000件ランダムサンプリングする)

```

# 処理時間計測

```python

import time

# 計測用のファンクションを設定
def func():
  for i in range(10):
    time.sleep(1)
  return

# 時間計測する
%timeit func()

```

%timeitでどんなことをしているのか？については、[こちらのブログ](https://blog.neko-ni-naritai.com/entry/2019/04/02/004538#timeit%E3%81%AE%E5%87%BA%E5%8A%9B%E3%81%AE%E6%84%8F%E5%91%B3)を参照すると理解が深まると思います。


# 特定パターンにマッチするファイルを取得する

```python

from glob import glob

pathsList = glob('input/*')

```

上記は、inputフォルダ内にあるファイルのpath情報をリストで取得してます。
ファイル名称をリストで取得して、for文でループさせて処理する場合などに利用します。便利。