使用python构建凌乱的数据

时间:2018-11-23 09:32:24

标签: python pandas dataframe

我有一组不是制表符或逗号分隔的数据。在记事本中打开时,其结构看起来如下图所示,但在Excel中打开时,其结构不正确

Tuesday 19-April-2010 00:01 CC  11   PQ 1.1  PS1.1 CS# 111 +1 RS113' SC 183 ZA 71
 IFJ   SC/LY     AB  CD?  EF  GH  IJK  LM  NO  PQR  ST  UV  WXY  ZA  BC  DEF GHI
 1234 SC 122      A  20?  31   1   4?  10   3   2?  19   9   5?   -       -?   30
 1234 SC 123  '   B  60?  11   2   3?  10   5   6?  19   9   4?  17   4   1?   30
 1234 SC 124      C  20?  21   2   2?  10   2   1?   9   9   0?   -       -?   34
 1234 SC 125 ^    1 100?   -       -?   0   3   3?   -       -?   -       -?   10
 1234 SC 226 *    5  60?   -       -?  14   4   3?   9   9   2?   7   3   3?   18
A=<43>  B=33  C=24
Tuesday 19-April-2010 00:03 CC  11   PQ 1.1  PS1.1 CS# 111 +1 RS113' SC 183 ZA 71
 IFJ   SC/LY     AB  CD?  EF  GH  IJK  LM  NO  PQR  ST  UV  WXY  ZA  BC  DEF GHI
 1234 SC 122      A  21?  31   5   4?  17   3   2?  19   9   1?   -       -?   31
 1234 SC 123  '   B  61?  11   2   3?  19   5   6?  19   9   4?  17   4   3?   32
 1234 SC 124      C  21?  21   5   2?  10   2   1?   9   9   0?   -       -?   33
 1234 SC 125 ^    1 101?   -       -?   7   3   3?   -       -?   -       -?   14
 0000 SC 226 *    5  61?   -       -?  14   4   3?   9   9   2?   7   3   3?   18

我是否可以使用熊猫处理此类数据以进行某些分析?

3 个答案:

答案 0 :(得分:1)

我建议您先使用脚本将数据转换为合适的CSV格式,然后使用Pandas可以毫无问题地加载它。

大多数数据似乎都采用固定宽度格式,因此可以对列位置进行硬编码,并应用strip()来删除任何空白。可以从时间戳记行中提取时间和日期,并将其添加到其中的每个条目的开头。

groupby()用于按块读取文件,这还具有跳过段之间不需要的行的效果。它的工作方式是一次读取一行文件,然后将每一行传递给key函数(使用lambda函数内联提供以节省空间)。如果函数的结果更改,groupby函数将返回具有相同返回值的行的列表。在这种情况下,它将测试行是否不以A=<字符开头。因此,您得到一个返回,其中keyTrue,其中包含以时间戳开头的行列表。然后是一行以A=<开头的行的列表(在本例中为一个)。这使得处理整个片段变得更加容易,而不必担心片段的完成位置。第一个条目是时间戳,然后是所有条目。

列表推导用于从行中提取每个单独的值并创建值rowpairwise()配方用于从cols读取固定的列位置,以获得滑动的startend列位置。这些用作字符串切片以提取每一列的字符。然后,该字符串已应用.strip()来删除所有周围的空格。

from itertools import groupby, tee
import csv

def pairwise(iterable):
    "s -> (s0,s1), (s1,s2), (s2, s3), ..."
    a, b = tee(iterable)
    next(b, None)
    return zip(a, b)

cols = [0, 5, 12, 15, 19, 24, 28, 32, 37, 41, 45, 50, 54, 58, 63, 68, 71, 76] # + rest
header = None

with open('data.txt') as f_input, open('output.csv', 'w', newline='') as f_output:
    csv_output = csv.writer(f_output)

    for key, group in groupby(f_input, lambda x: not x.startswith('A=<')):
        if key:
            # Extract the timestamp from the first returned line in the segment
            # Split the line on spaces and take the first 3 elements
            timestamp = next(group).split()[:3]
            block = []

            for line in group:
                row = [line[start:end].strip() for start, end in pairwise(cols)]
                row.append(line[cols[-1]:].strip())     # Add GHI column
                block.append(timestamp + row)

            if not header:
                header = block[0][3:]
                header[2] = 'Unknown'
                csv_output.writerow(['Day', 'Date', 'Time'] + header)

            csv_output.writerows(block[1:])

对于您提供的数据,这将为您提供

Day,Date,Time,IFJ,SC/LY,Unknown,AB,CD?,EF,GH,IJK,LM,NO,PQR,ST,UV,WXY,ZA,BC,DEF,GHI
Tuesday,19-April-2010,00:01,1234,SC 122,,A,20?,31,1,4?,10,3,2?,19,9,5?,-,,-?,30
Tuesday,19-April-2010,00:01,1234,SC 123,',B,60?,11,2,3?,10,5,6?,19,9,4?,17,4,1?,30
Tuesday,19-April-2010,00:01,1234,SC 124,,C,20?,21,2,2?,10,2,1?,9,9,0?,-,,-?,34
Tuesday,19-April-2010,00:01,1234,SC 125,^,1,100?,-,,-?,0,3,3?,-,,-?,-,,-?,10
Tuesday,19-April-2010,00:01,1234,SC 226,*,5,60?,-,,-?,14,4,3?,9,9,2?,7,3,3?,18
Tuesday,19-April-2010,00:03,1234,SC 122,,A,21?,31,5,4?,17,3,2?,19,9,1?,-,,-?,31
Tuesday,19-April-2010,00:03,1234,SC 123,',B,61?,11,2,3?,19,5,6?,19,9,4?,17,4,3?,32
Tuesday,19-April-2010,00:03,1234,SC 124,,C,21?,21,5,2?,10,2,1?,9,9,0?,-,,-?,33
Tuesday,19-April-2010,00:03,1234,SC 125,^,1,101?,-,,-?,7,3,3?,-,,-?,-,,-?,14
Tuesday,19-April-2010,00:03,0000,SC 226,*,5,61?,-,,-?,14,4,3?,9,9,2?,7,3,3?,18

为了更好地了解脚本的实际工作方式,我建议您添加创建一个小的测试文件(分为两个部分),然后添加一些打印语句。

答案 1 :(得分:0)

您的第二行似乎是实际的标题。但随后,正如MEdwin指出的那样,它看起来并不正确。

通常,您可以尝试:

import pandas as pd

df = pd.read_csv(<your csv), skiprows=1, delim_whitespace=True)
print(df.head())

但是,由于CSV的结构不一致,因此无法正常工作。

答案 2 :(得分:0)

编辑:这是我能用正则表达式得到的最接近的东西。不幸的是,任何空白字段(例如列GH的第4&5行)都将无法正确处理,并且数据会出现偏差。

请注意,我使用的是iPhone,因此您需要替换所有双引号(“)。

正则表达式[^0-9A-Z\?\-]+会匹配所有不符合以下条件的字符:

  • 数字0-9
  • 大写字母
  • 问号
  • 连字符

对于一种或多种组合...

这将删除奇怪的特殊字符并处理多个空格分隔符。

最后,您将在开头添加一个空白列。您可以使用更多的正则表达式来解决这个问题,但是我会把它留给您来做一些家庭作业(悬停)。

SC/LY将被分为两部分。通过两个定界阶段(不使用熊猫开始),您就可以解决该问题。

>>> import re
>>> regex_string = r”[^0-9A-Z\?\-\/]+”
>>> p=re.compile(regex_string)
>>> header
' IFJ   SC/LY     AB  CD?  EF  GH  IJK  LM  NO  PQR  ST  UV  WXY  ZA  BC  DEF GHI'
>>> single_row
' 1234 SC 125 ^    1 101?   -       -?   7   3   3?   -       -?   -       -?   10'
>>> p.split(header)
['', 'IFJ', 'SC' , 'LY', 'AB', 'CD?', 'EF', 'GH', 'IJK', 'LM', 'NO', 'PQR', 'ST', 'UV', 'WXY', 'ZA', 'BC', 'DEF', 'GHI']
>>> p.split(single_row)
['', '1234', 'SC', '125', '1', '101?', '-', '-?', '7', '3', '3?', '-', '-?', '-', '-?', '10']

对于大熊猫,它看起来像:

>>> import pandas
>>> df = pandas.read_csv(filepath, skiprows=1, header=True, delimiter= r”[^0-9A-Z\?\-]+”, engine=“python”)