使用pandas read_csv时,仅将分隔符限制为某些选项卡

时间:2016-01-07 14:56:18

标签: python regex pandas

我使用read_csv将一些制表符分隔的数据读入pandas Dataframe,但我在列数据中出现了标签,这意味着我无法使用" \ t"作为分隔符。具体来说,每行中的最后一个条目是一组制表符分隔的可选标记,它们匹配[A-Za-z] [A-Za-z0-9]:[A-Za-z] :. +没有任何保证将有多少标签或将存在哪些标签,并且不同的标签可以出现在不同的行上。示例数据如下所示(所有空格都是我数据中的选项卡):

C42TMACXX:5:2316:15161:76101    163 1   @<@DFFADDDF:DD  NH:i:1  HI:i:1  AS:i:200    nM:i:0
C42TMACXX:5:2316:15161:76101    83  1   CCCCCACDDDCB@B  NH:i:1  HI:i:1  nM:i:1
C42TMACXX:5:1305:26011:74469    163 1   CCCFFFFFHHHHGJ  NH:i:1  HI:i:1  AS:i:200    nM:i:0

我建议尝试将标签作为单个列读取,我想我可以通过传递分隔符的正则表达式来完成此操作,该分隔符排除了标签上下文中出现的标签。

关注http://www.rexegg.com/regex-best-trick.html我为此写了以下正则表达式:[A-Za-z] [A-Za-z0-9]:[A-Za-z]:[^ \ t] + \ t ..:|(\ t)。我在一个在线正则表达式测试器上测试它,它似乎只是匹配我想要的分隔符。

但是当我跑步时

df = pd.read_csv(myfile.txt, sep=r"[A-Za-z][A-Za-z0-9]:[A-Za-z]:[^\t]+\t..:|(\t)", 
                 header=None, engine="python")
print(df)

我得到以下数据输出:

                          0       1    2   3   4   5               6   7   8 \
0  C42TMACXX:5:2316:15161:76101  \t  163  \t   1  \t  @<@DFFADDDF:DD  \t NaN   
1  C42TMACXX:5:2316:15161:76101  \t   83  \t   1  \t  CCCCCACDDDCB@B  \t NaN   
2  C42TMACXX:5:1305:26011:74469  \t  163  \t   1  \t  CCCFFFFFHHHHGJ  \t NaN   

   9    10  11      12  13    14  
0 NaN  i:1  \t     NaN NaN   i:0  
1 NaN  i:1  \t  nM:i:1 NaN  None  
2 NaN  i:1  \t     NaN NaN   i:0  

我期待/想要的是:

                          0        1  2               3                      4
0  C42TMACXX:5:2316:15161:76101  163  1  @<@DFFADDDF:DD  NH:i:1 HI:i:1 AS:i:200 nM:i:0   
1  C42TMACXX:5:2316:15161:76101  83   1  CCCCCACDDDCB@B  NH:i:1 HI:i:1 nM:i:1   
2  C42TMACXX:5:1305:26011:74469  163  1  CCCFFFFFHHHHGJ  NH:i:1 HI:i:1 AS:i:200 nM:i:0

如何实现?

如果它是相关的,我使用pandas 0.17.1并且我的真实数据文件大约为1亿+行。

1 个答案:

答案 0 :(得分:1)

我快速浏览了一下pandas docs,看来用作分隔符的正则表达式不能使用组。

C42TMACXX:5:2316:15161:76101    163 1   @<@DFFADDDF:DD  NH:i:1  HI:i:1  AS:i:200    nM:i:0
C42TMACXX:5:2316:15161:76101    83  1   CCCCCACDDDCB@B  NH:i:1  HI:i:1  nM:i:1
C42TMACXX:5:1305:26011:74469    163 1   CCCFFFFFHHHHGJ  NH:i:1  HI:i:1  AS:i:200    nM:i:0
                              ^    ^  ^                ^           

您只需要匹配4个第一个标签,但不能不使用组。

解决方案是使用前瞻和后视来隔离所需的\t

这是一个应该有效的正则表达式:

(?<=\d)\t(?=\d)|\t(?=[A-Z@<:]{14})|(?<=[A-Z@<:]{14})\t

<强>解释

(?<=\d)\t(?=\d):一个标签前面有(?<=...)个数字,后跟(?=...)个数字

=&GT;匹配第一个和第二个选项卡

|

\t(?=[A-Z@<:]{14}):一个标签,后跟14个连续字符,设置为LETTER,@,&lt;或者:

=&GT;匹配第三个标签

|

(?<=[A-Z@<:]{14})\t:一个标签,前面有相同的14个字符集

=&GT;匹配第四个标签

Demo

  

注意

     

如果您需要在14个连续字符模式中允许更多字符,只需将它们添加到集合中即可。