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

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

新規登録して質問してみよう
ただいま回答率
85.48%
Python 3.x

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

Q&A

解決済

1回答

3205閲覧

フォルダ内のファイルを、ファイル名のルールに従ってグループ分けしたい

H.K2

総合スコア88

Python 3.x

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

0グッド

1クリップ

投稿2019/03/04 13:35

前提・実現したいこと

 pythonで、実行ファイル直下のフォルダ(たとえば、csvdata)に入れているcsvデータを読み取って、
一定のルールでグループ分けしてlistやdictに格納したいと考えています。
(ファイル名のフォーマット)識別子1_id_適当な番号_日付(yymmdd)_時間(hhmmss).csv
→これを、日付が同じで、時間が5分未満の差のものを一つのグループに分けて保存したい。
(例) aaa_1_1_20190302_110504.csv
aab_3_5_20190302_110911.csv
acb_2_4_20190302_111003.csv
cbz_2_6_20190303_111004.csv

とあった場合、1番目と2番目、3番目で一つのグループ、4番目で一つのグループ、
のような形で分けたいと考えています。グループは、連番でもいいと思っているので、
たとえば、{1:[aaa_1_1_20190302_110504.csv, aab_3_5_20190302_110911.csv, acb_2_4_20190302_111003.csv],
2:[cbz_2_6_20190303_111004.csv]}
のような形に分けられたら良いと思っています。

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

pathlibを使って、フォルダ全体を取得し、splitで分解するところまでは作れたのですが、
以下2点について伺いたく思います。

①条件に合うものをリストに入れることはできたのですが、これをグループ分け(別のリストもしくは辞書)
する方法が分かりません。(辞書の中にリストを入れる?)
②下記のコードでやっている方法はいまいちスマートではないような気がしますので、もしほかに良い方法などありましたら
ご教示いただければ幸いです。

該当のソースコード

python

1import pathlib 2import glob 3import pprint 4 5p_temp = pathlib.Path("csvdata") 6pprint.pprint(list(p_temp.glob('*.csv'))) 7 8csvs = p_temp.glob('*.csv') 9lst_csvs = [] 10dict_csvs = {} 11group_no = 1 12temp_ymd, temp_time = None, None 13 14for i in csvs: 15 _, id, pos, _, ymd, time = str(i).split('_')[:] 16 print(pos, ymd, time[0:7]) 17 18 if( (temp_ymd == ymd) and (abs(temp_time - int(time[0:7]))<5000 )): 19 lst_csvs.append(str(i)) 20 else: 21 temp_ymd, temp_time = ymd, int(time[0:7]) 22 print(temp_ymd, temp_time) 23 24print(lst_csvs)

試したこと

関連ライブラリの情報を検索した。
jupyterでサンプルコードを作って試行錯誤した。

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

magichan

2019/03/04 23:48

『5分未満の差』の箇所の仕様について確認したいのですが、例えば [0:00:00,0:04:59,0:05:00,0:05:01,0:05:02] とデータがあった場合、2番目の 0:04:59 は最初の 0:00:00 とグループ化するのが正解という認識で合ってますか?(グループの先頭から5分未満であれば同じグループに属する)
H.K2

2019/03/05 13:24

ご質問ありがとうございます。ご指摘の認識であっています。
guest

回答1

0

ベストアンサー

  1. ファイル名から日時部分を正規表現で抽出し、datetime オブジェクトを作る。
  2. pandas の DataFrame に変換し、5分単位でグループ化する。
  3. groupby オブジェクトから必要な情報をとりだし、以下の結果を得る。
[[日時, ファイルパスのリスト], [日時, ファイルパスのリスト], ... ]

python

1import glob 2import os 3import re 4from datetime import datetime 5import pandas as pd 6 7dts, paths = [], [] 8 9for path in glob.glob('test/*.csv'): 10 # ファイル名から必要な部分を正規表現で探して、datetime 型を作成する。 11 basename = os.path.basename(path) 12 match = re.search('(\d{4})(\d{2})(\d{2})_(\d{2})(\d{2})(\d{2}).csv', basename) 13 if not match: 14 print('not match', path) 15 continue 16 dt = datetime(*map(int, match.groups())) 17 18 dts.append(dt) 19 paths.append(path) 20 21# データフレームに変換 22df = pd.DataFrame(paths, columns=['path'], index=dts)
path
2019-03-02 11:05:04test\aaa_1_1_20190302_110504.csv
2019-03-02 11:09:11test\aab_3_5_20190302_110911.csv
2019-03-02 11:10:03test\acb_2_4_20190302_111003.csv
2019-03-03 11:10:04test\cbz_2_6_20190303_111004.csv

python

1# 5分単位でグループ化 2grouped_by_dt = df.resample('5min')['path'] 3 4result = [] 5for dt, path in grouped_by_dt: 6 if not path.empty: 7 result.append([dt.to_pydatetime(), path.tolist()]) 8 9from pprint import pprint 10pprint(result)
[[datetime.datetime(2019, 3, 2, 11, 5), ['test\aaa_1_1_20190302_110504.csv', 'test\aab_3_5_20190302_110911.csv']], [datetime.datetime(2019, 3, 2, 11, 10), ['test\acb_2_4_20190302_111003.csv']], [datetime.datetime(2019, 3, 3, 11, 10), ['test\cbz_2_6_20190303_111004.csv']]]

追記

「dt = datetime(*map(int, match.groups()))」の部分は同いう意味なのでしょうか。

理解するのに必要な項目

  1. 正規表現のグループ化と re.search()、その返り値の Match オブジェクトの使い方

re --- 正規表現操作 — Python 3.7.2 ドキュメント
2. map() の使い方
Python の mapと filter ってなに? | Mastering Python
3. * でタプル展開して、タプルの各要素を関数の引数としてわたす。
Pythonで関数の引数にリスト、タプル、辞書を展開して渡す | note.nkmk.me
4. datetime.datetime オブジェクトのコンストラクタ引数
datetime --- 基本的な日付型および時間型 — Python 3.7.2 ドキュメント

class datetime.datetime(year, month, day, hour, minute, second)

その部分をわかりやすくしたコード

python

1import re 2from datetime import datetime 3 4filename = 'aaa_1_1_20190302_110504.csv' 5match = re.search('(\d{4})(\d{2})(\d{2})_(\d{2})(\d{2})(\d{2}).csv', filename) 6 7# 1. groups() で正規表現においてグループ化した部分の値をタプルで取得できる。 8print(match.groups()) # ('2019', '03', '02', '11', '05', '04') 9 10# 2. タプルの各値が str なので、map() で int に変換する。 11args = tuple(map(int, match.groups())) 12print(args) # (2019, 3, 2, 11, 5, 4) 13 14# datetime.datetime クラスのコンストラクタに以下のように引数をわたしてもよいが、、、 15year, month, day, hour, minutes, second = args 16dt = datetime(year, month, day, hour, minutes, second) 17print(dt) # 2019-03-02 11:05:04 18 19# 3,4. タプル展開を利用するときれいにかける。 20# datetime.datetime オブジェクトの位置引数の順序が year, month, day, hour, minute, second なので、タプルの0番目の要素は year、タプルの1番目の要素は month、... と渡してくれる。 21dt = datetime(*args)

投稿2019/03/04 16:03

編集2019/03/06 11:03
tiitoi

総合スコア21956

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

H.K2

2019/03/06 10:40

ご回答ありがとうございますー! 1点ご確認させていただきたいのですが、 「dt = datetime(*map(int, match.groups()))」 の部分は同いう意味なのでしょうか。 (mapの前についてるアスタリスクがどういう解釈をされているのかがよくわからなくて・・・)
tiitoi

2019/03/06 11:01

タプル展開です。追記に説明を書きました。
H.K2

2019/03/06 12:21

ありがとうございます! すごくわかりやすかったです! そうか、mapなどにも*つけたらタプルを展開するという処理になるんですね。勉強になりました!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問