【问题标题】:Restrict separator to only some tabs when using pandas read_csv使用 pandas read_csv 时将分隔符限制为仅某些选项卡
【发布时间】:2016-04-12 00:38:13
【问题描述】:

我正在使用 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 亿多行。

【问题讨论】:

  • 有什么理由不能使用read_fwf()
  • 有一些可变宽度的列 - 我删除了以简化示例 - 所以我认为我不能使用 read_fwf()

标签: python regex pandas


【解决方案1】:

我快速浏览了一下 pandas 文档,似乎用作分隔符的正则表达式不能使用组。

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

这是一个应该可以工作的正则表达式:

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

说明

(?&lt;=\d)\t(?=\d) : 一个制表符,前面是 (?&lt;=...) 一个数字,后面是 (?=...) 一个数字

=> 匹配第一个和第二个标签

|

\t(?=[A-Z@&lt;:]{14}) : 一个制表符,后跟 14 个连续字符出现在集合 LETTER、@、

=> 匹配第三个标签

|

(?&lt;=[A-Z@&lt;:]{14})\t : 一个制表符,前面有相同的 14 个字符集

=> 匹配第 4 个标签

Demo

注意

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

【讨论】:

  • 我需要签入 pandas,因为您生成的正则表达式肯定会拆分数据,但这实际上并不是 pandas 需要的。我会尽快检查。
  • @smiley 我没有正确理解你的问题。我已经改变了答案。希望对您有所帮助。
  • 太棒了,可以完成这项工作。谢谢 - 也解释了为什么我所做的没有工作。
猜你喜欢
  • 2017-10-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-06-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-09-20
相关资源
最近更新 更多