Python Pandas:关于文本提取有什么想法吗?

Python Pandas: any ideas on text extraction?

我有几千个类似下面的txt文件(数值是编造的):

Date :  [ 2010-01-01 XX:XX:XX ]  Age :  [ 22 ]  Sex :  [ M ]   :  [ XXX ]
Height(cm) :  [ 145 ]  Weight(kg) :  [ 56.4 ]  Race :  [ Hispanic ]
Spirometry :  [ restrictive pattern ]
Treatment response :  [ Negative ]
Tissue volume :  [ Normal ]
Tissue volume
[ Normal RV ] 
Diffusing capacity :  [ Normal capacity ]
FVC Liters : [ 2.22 ] FVC Liters :  [ 67 ] FVC Liters :  [ 3.35 ] 
FEV1 Liters :  [ 1.96 ] FEV1 Liters :  [ 66 ] FEV1 Liters :  [ 2.06 ] 
FEV1 / FVC % :  [ 58 ] FEV1 / FVC % :  [ 62 ]
DLCO mL/mmHg/min :  [ 21.5 ] DLCO mL/mmHg/min :  [ 102 ]
DLCO Adj mL/mmHg/min :  [ 21.5 ] DLCO Adj mL/mmHg/min :  [ 102 ]
RV/TLC % :  [ 22 ]

我想以 csv 格式提取变量名称及其对应的值。幸运的是,正如您所注意到的,所有 txt 文件都具有类似的格式:

variable : [ value ]   
  1. 我的第一个问题是如何编写一个提取具有上述结构的数据的代码。

  2. 我的第二个问题是,我现在知道如何在一行中有多组“变量:[值]”时进行分隔。(它们不是逗号分隔的!)。

我只设法想出以下代码...但我现在正在兜圈子。有什么想法吗?

df = pd.read_csv(filename, sep='\n')
df = df[0].str.split(':', expand=True)

提前致谢

看来您需要正则表达式。让我们试试这个

首先,加载示例数据

text = \
"""Date :  [ 2010-01-01 XX:XX:XX ]  Age :  [ 22 ]  Sex :  [ M ]   :  [ XXX ]
Height(cm) :  [ 145 ]  Weight(kg) :  [ 56.4 ]  Race :  [ Hispanic ]
Spirometry :  [ restrictive pattern ]
Treatment response :  [ Negative ]
Tissue volume :  [ Normal ]
Tissue volume
[ Normal RV ] 
Diffusing capacity :  [ Normal capacity ]
FVC Liters : [ 2.22 ] FVC Liters :  [ 67 ] FVC Liters :  [ 3.35 ] 
FEV1 Liters :  [ 1.96 ] FEV1 Liters :  [ 66 ] FEV1 Liters :  [ 2.06 ] 
FEV1 / FVC % :  [ 58 ] FEV1 / FVC % :  [ 62 ]
DLCO mL/mmHg/min :  [ 21.5 ] DLCO mL/mmHg/min :  [ 102 ]
DLCO Adj mL/mmHg/min :  [ 21.5 ] DLCO Adj mL/mmHg/min :  [ 102 ]
RV/TLC % :  [ 22 ]
"""

接下来,使用正则表达式查找所有匹配的 'blah : [ blahblah ] ' 对,然后放入字典(strip 由 white space 编辑——本可以进入正则表达式但避免过于复杂的事情)

import re
parsed = re.findall('(.*?)\:\s*?\[(.*?)\]',text)
res = {g[0].strip() : g[1].strip() for g in parsed}
res

结果:

{'Date': '2010-01-01 XX:XX:XX',
 'Age': '22',
 'Sex': 'M',
 '': 'XXX',
 'Height(cm)': '145',
 'Weight(kg)': '56.4',
 'Race': 'Hispanic',
 'Spirometry': 'restrictive pattern',
 'Treatment response': 'Negative',
 'Tissue volume': 'Normal',
 'Diffusing capacity': 'Normal capacity',
 'FVC Liters': '3.35',
 'FEV1 Liters': '2.06',
 'FEV1 / FVC %': '62',
 'DLCO mL/mmHg/min': '102',
 'DLCO Adj mL/mmHg/min': '102',
 'RV/TLC %': '22'}

如果需要,您可以将其粘贴到数据框中:

df = pd.DataFrame.from_records([res])
df

获得

    Date                   Age  Sex           Height(cm)    Weight(kg)  Race      Spirometry           Treatment response    Tissue volume    Diffusing capacity      FVC Liters    FEV1 Liters    FEV1 / FVC %    DLCO mL/mmHg/min    DLCO Adj mL/mmHg/min    RV/TLC %
--  -------------------  -----  -----  ---  ------------  ------------  --------  -------------------  --------------------  ---------------  --------------------  ------------  -------------  --------------  ------------------  ----------------------  ----------
 0  2010-01-01 XX:XX:XX     22  M      XXX           145          56.4  Hispanic  restrictive pattern  Negative              Normal           Normal capacity               3.35           2.06              62                 102                     102          22

请注意,您提供的示例中有这一行朝向顶部 Sex : [ M ] : [ XXX ],这不符合模式,但代码通过使用空字符串 '' 作为键来处理它。我认为这是复制粘贴的问题,而不是原始数据中的问题,但如果你有很多这样的问题,你可能需要更小心地处理它们

对于示例数据,要获取没有前导空格和尾随空格的键和值,您可以使用 2 个捕获组。

([^\s:][^:]*)\s+\:\s+\[\s*([^][]*)\s+]
  • ( 捕获 组 1
    • [^\s:][^:]* 匹配除空白字符之外的任何字符或 : 后跟 :
    • 以外的可选字符
  • ) 关闭组 1
  • \s+\:\s+ 在左侧和右侧的 1 个或多个空白字符之间匹配 :
  • \[\s* 匹配 [ 和可选的空白字符
  • ( 捕获 第 2 组
    • [^][]* 匹配除 []
    • 之外的任何字符 0+ 次
  • ) 关闭组 2
  • \s+] Match 1+ whitespace chars and ]`

Regex demo | Python demo

输出

[('Date', '2010-01-01 XX:XX:XX'), ('Age', '22'), ('Sex', 'M'), ('Height(cm)', '145'), ('Weight(kg)', '56.4'), ('Race', 'Hispanic'), ('Spirometry', 'restrictive pattern'), ('Treatment response', 'Negative'), ('Tissue volume', 'Normal'), ('Diffusing capacity', 'Normal capacity'), ('FVC Liters', '2.22'), ('FVC Liters', '67'), ('FVC Liters', '3.35'), ('FEV1 Liters', '1.96'), ('FEV1 Liters', '66'), ('FEV1 Liters', '2.06'), ('FEV1 / FVC %', '58'), ('FEV1 / FVC %', '62'), ('DLCO mL/mmHg/min', '21.5'), ('DLCO mL/mmHg/min', '102'), ('DLCO Adj mL/mmHg/min', '21.5'), ('DLCO Adj mL/mmHg/min', '102'), ('RV/TLC %', '22')]