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

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

ただいまの
回答率

90.40%

  • Python 3.x

    10684questions

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

  • pandas

    974questions

    Pandasは、PythonでRにおけるデータフレームに似た型を持たせることができるライブラリです。 行列計算の負担が大幅に軽減されるため、Rで行っていた集計作業をPythonでも比較的簡単に行えます。 データ構造を変更したりデータ分析したりするときにも便利です。

時系列DataFrameで特定列に含まれるキーワードにより行を抽出

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 66

Higomon

score 19

  • 最終目標
    Python, Pandasでlogファイルの時系列解析  

  • 実現したいこと
    時系列DataFrameにおいて、特定列に含まれるキーワードにより行を抽出
    具体的には、列名"Refid"に"PPS"というキーワードが含まれれば、その行を抽出

質問者背景
・Python初学者
・開発経験 Excel VBAのみ 

(Original) logデータ

refclocks.log

(前処理後) logデータ

前処理は最下部記載のコードをご参照。

Date Time(UTC) Refid Raw offset Cooked offset Disp.
0 2019-05-25 16:51:22.999972 PPSx 2.731100e-05 0.000027 1.000000e-09
1 2019-05-25 16:51:22.323771 NMEA -3.237718e-01 0.176228 1.000000e-03
2 2019-05-25 16:51:23.999975 PPS 2.434500e-05 0.000024 1.000000e-09
3 2019-05-25 16:51:23.999975 PPSx 2.434500e-05 0.000024 1.000000e-09
4 2019-05-25 16:51:23.324379 NMEA -3.243791e-01 0.175621 1.000000e-03
5 2019-05-25 16:51:24.999973 PPS 2.658800e-05 0.000027 1.000000e-09
6 2019-05-25 16:51:24.999973 PPSx 2.658800e-05 0.000027 1.000000e-09

 各列の型

In[]: df.dtypes


Out[]: 
Date Time(UTC)    datetime64[ns]
Refid                 object
Raw offset         float64
Cooked offset     float64
Disp.                 float64
dtype: object

【理想】抽出後のDataFrame 

Date Time(UTC) Refid Raw offset Cooked offset Disp.
2 2019-05-25 16:51:23.999975 PPS 2.434500e-05 0.000024 1.000000e-09
5 2019-05-25 16:51:24.999973 PPS 2.658800e-05 0.000027 1.000000e-09

【現状】抽出失敗したDataFrame 

  •  試したこと1(→ 正常動作を確認)
    DataFrameに時系列を含まなければ、上記の理想通りとなるが、
    時系列を含むと以下のようなる。
In[]: df[df['Refid'] == 'PPS']


Out[]: 

Date Time(UTC) Refid Raw offset Cooked offset Disp.
0 NaT NaN NaN NaN NaN
1 NaT NaN NaN NaN NaN
2 NaT PPS NaN NaN NaN
3 NaT NaN NaN NaN NaN
4 NaT NaN NaN NaN NaN
5 NaT PPS NaN NaN NaN
6 NaT NaN NaN NaN NaN

↑logファイル前処理のバグが原因だった


  •  試したこと2(→ 正常動作を確認)
In[]: df.query('Refid' == 'PPS')


Out[]: 
...
ValueError: expr must be a string to be evaluated, <class 'bool'> given
 ↑logファイル前処理のバグが原因だった

【解決済】Code

import numpy as np
import pandas as pd
import re             #正規表現

path = "D:\\refclocks.log"

# 列名の取得
#    logファイル先頭3行から抽出
def get_Header(f):
    c = 0
    for a in f:
        if '=' not in a:
            a = a.lstrip(' ') #文字列先頭の半角スペースを削除
            s = re.sub(r" +", ",", a)
            s = s.replace("Date,(UTC),Time,", "Date Time(UTC),") #1列目と2列目を結合
            s = s.replace("Raw,offset,", "Raw offset,")
            s = s.replace("Cooked,offset,", "Cooked offset,")
            s = s.replace("\n", "")       #改行コードの除去
            s = s.split(",")
            del s[2:5]                         #不要な列の削除

        c += 1
        if c == 3:
            break

    return s

def get_Body(f, body):
# ファイル先頭以外に定期的に含まれる列名(3行連続)は無視
    for a in f:
        if '=' not in a:
            if a[0] != ' ':
                s = re.sub(r" +", ",", a) #複数半角スペース → 1つの半角スペース                
                s = s.replace("\n", "")   #改行コードの除去
                s = s.split(",")
                tmp = s[0] + ' ' + s[1] #1列目と2列目を結合
                s[0] = tmp
                del s[1]                       #不要な列の削除
                del s[2:5]
                body.append(s)

    return body

def main():
    f = open(path, mode='rt') 

# /// 前処理 ///
    #列名(リスト)の取得
    header = get_Header(f) 

    #ファイルボディの取得
    body = []
    get_Body(f, body)

    f.close()

    #List --> Pandas DataFrameに変換
    df = pd.DataFrame(body, dtype=float)
    df.columns = header  #columnsの指定 (← get_Header関数を修正)

    #Cast
    df['Date Time(UTC)'] = pd.to_datetime(df['Date Time(UTC)'])
    df['Raw offset'] = df['Disp.'].astype(float)


# /// 行の抽出 ///
    #試したこと1 ←正常動作
    print(df[df['Refid'] == 'PPS'])

    #試したこと2 ←正常動作
    print(df.query("Refid == 'PPS'"))

if __name__ == '__main__':
    main()

環境

Windows 10
Anaconda (default, Apr 24 2019, 15:29:51) [MSC v.1915 64 bit (AMD64)]
Python: 3.7.3, Pandas: 0.24.2
Jupyter Notebook

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

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

  • can110

    2019/07/10 16:18

    報告のみ。以下の当方環境では正常に動作します。提示コードに問題はなさそうです。
    Win10
    Python 3.5.5 |Anaconda custom (64-bit)| (default, Apr 7 2018, 04:52:34) [MSC v.1900 64 bit (AMD64)] on win32
    pandas:0.23.0
    コンソール上で実行

    キャンセル

  • Higomon

    2019/07/10 17:14

    ご検証、ありがとうござます。
    お使いの環境だと正常動作するのですね。。。

    Pandasではなく、Numpyの話ですが、先日取得したAnaconda(Anaconda3-2019.03)で
    Numpyのimportが出来ず、悪戦苦闘しました。
    以下のサイトを参考に、Numpyのimport問題は解決しましたが、
    上記Pandasの問題は解決に至っていません。
    https://teratail.com/questions/149566

    取り急ぎ、お礼申し上げます。

    キャンセル

回答 2

checkベストアンサー

+1

コードの詳細内容は把握していませんが、***部分を修正することにより動作しました。

# 略

def main():
    f = open(path, mode='rt') 

# /// 前処理 ///
    #列名の取得
    header = []
    get_Header(f, header)

    #ファイルボディの取得
    body = []
    get_Body(f, body)

    f.close()

    #List --> Pandas DataFrameに変換
    df = pd.DataFrame(body, dtype=float)
    df.columns = header[0]  #columnsの指定 ***2重リストになっているので[0]を渡す

    print(df.columns)
    print(df.head())

    #Cast
    df['Date Time(UTC)'] = pd.to_datetime(df['Date Time(UTC)']) # ***最後の「,」を除く
    df['Raw offset'] = df['Disp.'].astype(float)

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2019/07/12 16:40

    早急にバグを見つけて頂き、誠にありがとうございました。
    感動しました!

    キャンセル

+1

-コメントを受けて-

一応、自分が状況再現に用いたコードを載せておきます。これがうまく動作するかどうかも試してもらえると、回答時の参考になります。

import pandas as pd
import datetime

##logf.logの中身(メモ帳で作ってlog拡張子で保存)

#Date Time(UTC),Refid,Raw offset,Cooked offset,Disp.
#2019-05-25 16:51:22.999972,PPSx,2.73E-05,0.000027,1.00E-09
#2019-05-25 16:51:22.323771,NMEA,-3.24E-01,0.176228,1.00E-03
#2019-05-25 16:51:23.999975,PPS,2.43E-05,0.000024,1.00E-09
#2019-05-25 16:51:23.999975,PPSx,2.43E-05,0.000024,1.00E-09
#2019-05-25 16:51:23.324379,NMEA,-3.24E-01,0.175621,1.00E-03
#2019-05-25 16:51:24.999973,PPS,2.66E-05,0.000027,1.00E-09
#2019-05-25 16:51:24.999973,PPSx,2.66E-05,0.000027,1.00E-09

#logファイルの読み込み
df=pd.read_csv('logf.log')

#読み込み時点ではDate Time(UTC)のdtypeがobjectなのでdatetime64[ns]に変える
df['Date Time(UTC)']=pd.to_datetime(df['Date Time(UTC)'])

#データ抽出(どちらのコードでもうまくいった)
df[df['Refid'] == 'PPS']
df.query("Refid == 'PPS'")

試したこと2について、以下のように修正した場合はどうでしょう。
※コードにミスが有ったので修正しました。

#修正前
df.query('Refid' == 'PPS')

#修正後(等式全体を””で囲み、'Refid'をRefidに変える)
df.query("Refid == 'PPS'")

参考:note.nkmk.me - pandas.DataFrameの行を条件で抽出するquery

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2019/07/11 09:58 編集

    ご提案、ありがとうございます。

    df.query("Refid == 'PPS'")を試しましたが、以下のエラーを吐いています。
    #1 質問時とは異なり、環境をAnaconda → Minicondaとしましたが、
     インストールしたPythonおよびPandasのバージョンは変更してません。
     質問したPandas問題も未解決のままです。

    #2 列名 Refidは設定しているはずですが、
      下記最下部のError: name 'Refid' is not definedの意味が理解できてません。

    ---
    KeyError Traceback (most recent call last)
    ~\Miniconda3\lib\site-packages\pandas\core\computation\scope.py in resolve(self, key, is_local)
    180 if self.has_resolvers:
    --> 181 return self.resolvers[key]
    182

    ~\Miniconda3\lib\collections\__init__.py in __getitem__(self, key)
    913 pass
    --> 914 return self.__missing__(key) # support subclasses that define __missing__
    915

    ~\Miniconda3\lib\collections\__init__.py in __missing__(self, key)
    905 def __missing__(self, key):
    --> 906 raise KeyError(key)
    907

    KeyError: 'Refid'

    During handling of the above exception, another exception occurred:

    KeyError Traceback (most recent call last)
    ~\Miniconda3\lib\site-packages\pandas\core\computation\scope.py in resolve(self, key, is_local)
    191 # e.g., df[df > 0]
    --> 192 return self.temps[key]
    193 except KeyError:

    KeyError: 'Refid'

    During handling of the above exception, another exception occurred:

    UndefinedVariableError Traceback (most recent call last)
    <ipython-input-3-f108e38e0600> in <module>
    ----> 1 df.query("Refid == 'PPS'")

    ~\Miniconda3\lib\site-packages\pandas\core\frame.py in query(self, expr, inplace, **kwargs)
    3086 kwargs['level'] = kwargs.pop('level', 0) + 1
    3087 kwargs['target'] = None
    -> 3088 res = self.eval(expr, **kwargs)
    3089
    3090 try:

    ~\Miniconda3\lib\site-packages\pandas\core\frame.py in eval(self, expr, inplace, **kwargs)
    3201 kwargs['target'] = self
    3202 kwargs['resolvers'] = kwargs.get('resolvers', ()) + tuple(resolvers)
    -> 3203 return _eval(expr, inplace=inplace, **kwargs)
    3204
    3205 def select_dtypes(self, include=None, exclude=None):

    ~\Miniconda3\lib\site-packages\pandas\core\computation\eval.py in eval(expr, parser, engine, truediv, local_dict, global_dict, resolvers, level, target, inplace)
    292
    293 parsed_expr = Expr(expr, engine=engine, parser=parser, env=env,
    --> 294 truediv=truediv)
    295
    296 # construct the engine and evaluate the parsed expression

    ~\Miniconda3\lib\site-packages\pandas\core\computation\expr.py in __init__(self, expr, engine, parser, env, truediv, level)
    747 self.env.scope['truediv'] = truediv
    748 self._visitor = _parsers[parser](self.env, self.engine, self.parser)
    --> 749 self.terms = self.parse()
    750
    751 @property

    ~\Miniconda3\lib\site-packages\pandas\core\computation\expr.py in parse(self)
    764 def parse(self):
    765 """Parse an expression"""
    --> 766 return self._visitor.visit(self.expr)
    767
    768 @property

    ~\Miniconda3\lib\site-packages\pandas\core\computation\expr.py in visit(self, node, **kwargs)
    329 method = 'visit_' + node.__class__.__name__
    330 visitor = getattr(self, method)
    --> 331 return visitor(node, **kwargs)
    332
    333 def visit_Module(self, node, **kwargs):

    ~\Miniconda3\lib\site-packages\pandas\core\computation\expr.py in visit_Module(self, node, **kwargs)
    335 raise SyntaxError('only a single expression is allowed')
    336 expr = node.body[0]
    --> 337 return self.visit(expr, **kwargs)
    338
    339 def visit_Expr(self, node, **kwargs):

    ~\Miniconda3\lib\site-packages\pandas\core\computation\expr.py in visit(self, node, **kwargs)
    329 method = 'visit_' + node.__class__.__name__
    330 visitor = getattr(self, method)
    --> 331 return visitor(node, **kwargs)
    332
    333 def visit_Module(self, node, **kwargs):

    ~\Miniconda3\lib\site-packages\pandas\core\computation\expr.py in visit_Expr(self, node, **kwargs)
    338
    339 def visit_Expr(self, node, **kwargs):
    --> 340 return self.visit(node.value, **kwargs)
    341
    342 def _rewrite_membership_op(self, node, left, right):

    ~\Miniconda3\lib\site-packages\pandas\core\computation\expr.py in visit(self, node, **kwargs)
    329 method = 'visit_' + node.__class__.__name__
    330 visitor = getattr(self, method)
    --> 331 return visitor(node, **kwargs)
    332
    333 def visit_Module(self, node, **kwargs):

    ~\Miniconda3\lib\site-packages\pandas\core\computation\expr.py in visit_Compare(self, node, **kwargs)
    664 op = self.translate_In(ops[0])
    665 binop = ast.BinOp(op=op, left=node.left, right=comps[0])
    --> 666 return self.visit(binop)
    667
    668 # recursive case: we have a chained comparison, a CMP b CMP c, etc.

    ~\Miniconda3\lib\site-packages\pandas\core\computation\expr.py in visit(self, node, **kwargs)
    329 method = 'visit_' + node.__class__.__name__
    330 visitor = getattr(self, method)
    --> 331 return visitor(node, **kwargs)
    332
    333 def visit_Module(self, node, **kwargs):

    ~\Miniconda3\lib\site-packages\pandas\core\computation\expr.py in visit_BinOp(self, node, **kwargs)
    433
    434 def visit_BinOp(self, node, **kwargs):
    --> 435 op, op_class, left, right = self._maybe_transform_eq_ne(node)
    436 left, right = self._maybe_downcast_constants(left, right)
    437 return self._maybe_evaluate_binop(op, op_class, left, right)

    ~\Miniconda3\lib\site-packages\pandas\core\computation\expr.py in _maybe_transform_eq_ne(self, node, left, right)
    370 def _maybe_transform_eq_ne(self, node, left=None, right=None):
    371 if left is None:
    --> 372 left = self.visit(node.left, side='left')
    373 if right is None:
    374 right = self.visit(node.right, side='right')

    ~\Miniconda3\lib\site-packages\pandas\core\computation\expr.py in visit(self, node, **kwargs)
    329 method = 'visit_' + node.__class__.__name__
    330 visitor = getattr(self, method)
    --> 331 return visitor(node, **kwargs)
    332
    333 def visit_Module(self, node, **kwargs):

    ~\Miniconda3\lib\site-packages\pandas\core\computation\expr.py in visit_Name(self, node, **kwargs)
    447
    448 def visit_Name(self, node, **kwargs):
    --> 449 return self.term_type(node.id, self.env, **kwargs)
    450
    451 def visit_NameConstant(self, node, **kwargs):

    ~\Miniconda3\lib\site-packages\pandas\core\computation\ops.py in __init__(self, name, env, side, encoding)
    62 self.is_local = (tname.startswith(_LOCAL_TAG) or
    63 tname in _DEFAULT_GLOBALS)
    ---> 64 self._value = self._resolve_name()
    65 self.encoding = encoding
    66

    ~\Miniconda3\lib\site-packages\pandas\core\computation\ops.py in _resolve_name(self)
    79
    80 def _resolve_name(self):
    ---> 81 res = self.env.resolve(self.local_name, is_local=self.is_local)
    82 self.update(res)
    83

    ~\Miniconda3\lib\site-packages\pandas\core\computation\scope.py in resolve(self, key, is_local)
    192 return self.temps[key]
    193 except KeyError:
    --> 194 raise compu.ops.UndefinedVariableError(key, is_local)
    195
    196 def swapkey(self, old_key, new_key, new_value=None):

    UndefinedVariableError: name 'Refid' is not defined

    キャンセル

  • 2019/07/12 12:00

    質問にある表をもとに作ったdataframeを使った場合では問題なく動作したので、入力ファイル(logファイル)の問題かもしれません。
    ※環境はPython: 3.7.1, Pandas: 0.23.4,Jupyter Notebook

    logファイル自体もしくはファイルの中身(コンマのついたテキスト形式になっているはず)を提示できないでしょうか。

    キャンセル

  • 2019/07/12 16:21

    ご丁寧に検証頂き、ありがとうございます。

    質問の簡単化のため記載しておりませんでしたが、
    logファイル(original)と前処理も含めたPython codeすべてを記載しました。
    改めてご参照くださいませ。

    PythonのバージョンやOSを変えても正常に動かないので、前処理部分がおかしいはずですが、
    恥ずかしながら、経験不足のため、何がおかしいのか未だ発見できていません。

    キャンセル

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

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

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

  • Python 3.x

    10684questions

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

  • pandas

    974questions

    Pandasは、PythonでRにおけるデータフレームに似た型を持たせることができるライブラリです。 行列計算の負担が大幅に軽減されるため、Rで行っていた集計作業をPythonでも比較的簡単に行えます。 データ構造を変更したりデータ分析したりするときにも便利です。