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

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

ただいまの
回答率

90.51%

  • Python 3.x

    9799questions

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

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

解決済

回答 1

投稿

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

H.Ka2

score 22

前提・実現したいこと

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点について伺いたく思います。

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

該当のソースコード

import pathlib
import glob
import pprint

p_temp = pathlib.Path("csvdata")
pprint.pprint(list(p_temp.glob('*.csv')))

csvs = p_temp.glob('*.csv')
lst_csvs = []
dict_csvs = {}
group_no = 1
temp_ymd, temp_time = None, None

for i in csvs:
    _, id, pos, _, ymd, time = str(i).split('_')[:]
    print(pos, ymd, time[0:7])

    if( (temp_ymd == ymd) and (abs(temp_time - int(time[0:7]))<5000 )):
        lst_csvs.append(str(i))
    else:
        temp_ymd, temp_time = ymd, int(time[0:7])
        print(temp_ymd, temp_time)

print(lst_csvs)

試したこと

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

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

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

  • magichan

    2019/03/05 08: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.Ka2

    2019/03/05 22:24

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

    キャンセル

回答 1

checkベストアンサー

+2

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

dts, paths = [], []

for path in glob.glob('test/*.csv'):
    # ファイル名から必要な部分を正規表現で探して、datetime 型を作成する。
    basename = os.path.basename(path)
    match = re.search('(\d{4})(\d{2})(\d{2})_(\d{2})(\d{2})(\d{2}).csv', basename)
    if not match:
        print('not match', path)
        continue
    dt = datetime(*map(int, match.groups()))

    dts.append(dt)
    paths.append(path)

# データフレームに変換
df = pd.DataFrame(paths, columns=['path'], index=dts)
                       path                             
 2019-03-02 11:05:04   test\aaa_1_1_20190302_110504.csv 
 2019-03-02 11:09:11   test\aab_3_5_20190302_110911.csv 
 2019-03-02 11:10:03   test\acb_2_4_20190302_111003.csv 
 2019-03-03 11:10:04   test\cbz_2_6_20190303_111004.csv 
#  5分単位でグループ化
grouped_by_dt = df.resample('5min')['path']

result = []
for dt, path in grouped_by_dt:
    if not path.empty:
        result.append([dt.to_pydatetime(), path.tolist()])

from pprint import pprint
pprint(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)

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

import re
from datetime import datetime

filename = 'aaa_1_1_20190302_110504.csv'
match = re.search('(\d{4})(\d{2})(\d{2})_(\d{2})(\d{2})(\d{2}).csv', filename)

# 1. groups() で正規表現においてグループ化した部分の値をタプルで取得できる。
print(match.groups())  # ('2019', '03', '02', '11', '05', '04')

# 2. タプルの各値が str なので、map() で int に変換する。
args = tuple(map(int, match.groups()))
print(args)  # (2019, 3, 2, 11, 5, 4)

# datetime.datetime クラスのコンストラクタに以下のように引数をわたしてもよいが、、、
year, month, day, hour, minutes, second = args
dt = datetime(year, month, day, hour, minutes, second)
print(dt)  # 2019-03-02 11:05:04

# 3,4. タプル展開を利用するときれいにかける。
# datetime.datetime オブジェクトの位置引数の順序が year, month, day, hour, minute, second なので、タプルの0番目の要素は year、タプルの1番目の要素は month、... と渡してくれる。
dt = datetime(*args)

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2019/03/06 19:40

    ご回答ありがとうございますー!

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

    キャンセル

  • 2019/03/06 20:01

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

    キャンセル

  • 2019/03/06 21:21

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

    キャンセル

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

  • Python 3.x

    9799questions

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