【问题标题】:Extracting text data into a meaningful table for analysis using Python (or R)使用 Python(或 R)将文本数据提取到有意义的表中以进行分析
【发布时间】:2019-09-10 03:56:37
【问题描述】:

我正在从事一个工程项目,我在该项目中使用来自存档的机器性能数据。机器大约每 5 秒产生一个数据集,然后这些数据在多个.txt 文件中按日期提供,每个文件包含以下格式的数据。下面显示的数据来自2013_04_17.txt 文件,该文件包含该特定日期的所有性能数据。

2013-04-27 00:00:05.011
V_1 100  V_2 26695  V_3 33197  V_4 c681  V_5  29532
V_6 4600  V_7 4606  V_8 4f55  V_9 5a  V_10  8063  V_11  4300  V_12  4700
V_13 4504  V_14 4400  V_15 4202  V_16 255  V_17  4300  V_18  91  V_19  6f
V_20 300  V_21 14784 
V_22 5.085  V_23 7.840  V_24 -8.061  V_25 36.961

2013-04-27 00:00:10.163
V_1 100  V_2 26695  V_3 33199  V_4 c681  V_5  29872
V_6 4600  V_7 4606  V_8 4f55  V_9 5a  V_10  8063  V_11  4300  V_12  4700
V_13 4504  V_14 4400  V_15 4202  V_16 255  V_17  4300  V_18  91  V_19  6f
V_20 300  V_21 14790 
V_22 5.085  V_23 7.840  V_24 -8.061  V_25 37.961

.......

我需要以表格格式或 CSV 格式查看这些数据,以便能够生成性能图并检测任何异常情况。但是,我没有足够的 Python 编程经验来解析这个文本文件。

我已经研究了 pandas 和正则表达式的一些想法,但未能达到预期的结果,我希望有一个表格形式的数据或一个带有标题作为变量日期、时间、 V_1V_2V_3等以及后续行作为每5s获取的所有值。

【问题讨论】:

  • 查看文件,您可以通过在空行上拆分(“\n\n\n”或类似)将文本拆分为多个部分,然后将结果列表中的每个元素用空格和/或换行符。

标签: python r database csv text


【解决方案1】:

您可以从文件中一次读取一个令牌开始:

with open('2013_04_17.txt') as infile:
    for line in infile:
        for token in line.split():
            print(token)

之后您只需要创建一个状态机来记住您所在的部分,并在找到结束时处理每个部分:

def process_record(timestamp, values):
    """print CSV format"""
    print(','.join([timestamp] + values))

with open('t.txt') as infile:
    timestamp = None
    values = []
    for line in infile:
        line = line.strip()
        if timestamp is None:
            timestamp = line
        elif not line: # blank line is separator
            process_record(timestamp, values)
            timestamp = None
            values = []
        else:
            values.extend(line.split()[1::2])
    if timestamp is not None: # process last record, no separator after it
        process_record(timestamp, values)

这会给你 CSV 输出:

2013-04-27 00:00:05.011,100,26695,33197,c681,29532,4600,4606,4f55,5a,8063,4300,4700,4504,4400,4202,255,4300,91,6f,300,14784,5.085,7.840,-8.061,36.961
2013-04-27 00:00:10.163,100,26695,33199,c681,29872,4600,4606,4f55,5a,8063,4300,4700,4504,4400,4202,255,4300,91,6f,300,14790,5.085,7.840,-8.061,37.961

【讨论】:

    【解决方案2】:

    在 R 中,这将非常具体到您的情况,您可以尝试将所有 .txt 文件扔到一个新文件夹中,例如将其命名为 date_data。假设所有文件都采用相同的格式,请尝试运行它。

    library(purrr)
    library(tidyverse)
    
    setwd(./date_data)
    odd_file_reader <- function(x){
      as.data.frame(matrix(scan(x, what="character", sep=NULL), ncol = 52, byrow = TRUE)[,-seq(3,51,2)])
    }
    
    binded_data <- tibble(filenames = list.files()) %>%
      mutate(yearly_sat = map(filenames, odd_file_reader)) %>%
      unnest()
    

    【讨论】:

      【解决方案3】:

      有一个更简单的方法。假设此数据出现在 .txt 文件的列中(即数据采用 Fixed-Width 格式),您可以使用 pandas 函数 pandas.read_fwf() 并传入包含范围的元组每行的固定宽度字段。

      import pandas
      
      colspecs = [(0,10), (11, 23), (28,31), (37, 42), (48, 54), (59, 63), (70, 75), ...]
      data = pandas.read_fwf(TXT_PATH, colspecs = colspecs, header=None)
      data.columns = ['date', 'time', 'V_1', 'V_2', 'V_3', 'V_4', 'V_5', ...]
      print(data)
      
               date          time  V_1    V_2    V_3   V_4    V_5
      0  2013-04-27  00:00:05.011  100  26695  33197  c681  29532
      1  2013-04-27  00:00:10.163  100  26695  33199  c681  29872
      

      然后,您可以使用命令将格式化的数据保存到文件中

      data.to_csv('filename.csv', index=False)
      

      【讨论】:

        【解决方案4】:

        试试我的简单代码,我用的是 pandas

        import pandas as pd
        
        with open('2013_04_17.txt', 'r') as f:
            large_list = [word for line in f for word in line.split() if 'V_' not in word]
            print(large_list)
            col_titles = ('date','time','v1','v2','vN','vN','vN','vN','vN','vN','vN','vN'
                          ,'vN','vN','vN','vN','vN','vN','vN','vN','vN','vN','vN','vN','vN','vN','vN')
            data = pd.np.array(large_list).reshape((len(large_list) // 27, 27))
            pd.DataFrame(data, columns=col_titles).to_csv("output3.csv", index=False) 
        

        【讨论】:

          【解决方案5】:

          编辑: 您可以在没有正则表达式的情况下获得相同的结果,如下所示: 请注意,我们假设文件格式始终相同,因此我们期望文件开头的日期和时间

          # reading data from a file for example log.txt
          with open('log.txt', 'r') as f:
              data = f.read()
          
          data = string.split()
          v_readings = dict()
          v_readings['date'] = data.pop(0)
          v_readings['time' ]= data.pop(0)
          
          i=0
          while i < len(data):
              v_readings[data[i]] = data[i+1]
              i += 2
          

          导出为 csv 文件:

          csv = '\n'
          csv += ','.join(v_readings.keys())
          csv += '\n'
          csv += ','.join(v_readings.values())
          
          print(csv)
          with open('out.csv', 'w') as f:
              f.write(csv)
          

          输出:

          date,time,V_1,V_2,V_3,V_4,V_5,V_6,V_7,V_8,V_9,V_10,V_11,V_12,V_13,V_14,V_15,V_16,V_17,V_18,V_19,V_20,V_21,V_22,V_23,V_24,V_25
          2013-04-27,00:00:05.011,100,26695,33197,c681,29532,4600,4606,4f55,5a,8063,4300,4700,4504,4400,4202,255,4300,91,6f,300,14784,5.085,7.840,-8.061,36.961
          

          使用正则表达式: 这就是您在 python 中使用变量和字典中的正则表达式提取这些数据的方式

          这是一个起点,然后你可以对他们做任何你喜欢的事

          import re 
          
          string = """
          2013-04-27 00:00:05.011 V_1 100 V_2 26695 V_3 33197 V_4 c681 V_5 29532 V_6 4600 V_7 4606 V_8 4f55 V_9 5a V_10 8063 V_11 4300 V_12 4700 V_13 4504 V_14 4400 V_15 4202 V_16 255 V_17 4300 V_18 91 V_19 6f V_20 300 V_21 14784 V_22 5.085 V_23 7.840 V_24 -8.061 V_25 36.961
          """
          # extract date 
          match = re.search(r'\d{4}-\d\d-\d\d', string)
          my_date = match.group()
          
          # extract time
          match = re.search(r'\d\d:\d\d:\d\d\.\d+', string)
          my_time = match.group()
          
          #getting V's into a dictionary
          match = re.findall(r'V_\d+ \d+', string)
          v_readings = dict()
          for item in match:
              k, v = item.split()
              v_readings[k] = v
          
          # print output
          print(my_date)
          print(my_time)
          print(v_readings)
          

          输出:

          2013-04-27
          00:00:05.011
          {'V_1': '100', 'V_2': '26695', 'V_3': '33197', 'V_5': '29532', 'V_6': '4600', 'V_7': '4606', 'V_8': '4', 'V_9': '5', 'V_10': '8063', 'V_11': '4300', 'V_12': '4700', 'V_13': '4504', 'V_14': '4400', 'V_15': '4202', 'V_16': '255', 'V_17': '4300', 'V_18': '91', 'V_19': '6', 'V_20': '300', 'V_21': '14784', 'V_22': '5', 'V_23': '7', 'V_25': '36'}
          

          【讨论】:

            猜你喜欢
            • 2015-03-10
            • 2014-08-18
            • 2014-03-25
            • 2018-08-25
            • 2014-04-28
            • 1970-01-01
            • 1970-01-01
            • 2011-05-14
            • 2020-09-18
            相关资源
            最近更新 更多