Извлеките числа из "dd.dd AAA dd.dd BBB" или "AAA dd.dd BBB dd.dd" - PullRequest
2 голосов
/ 17 мая 2019

Я пытаюсь извлечь два значения из произвольного текста, отформатированного различными способами. Эти два значения различны, и я хочу различить их на основе ближайшей строки, скажем, «ДДТ» и «ЭЭГ». Вот несколько примеров того, как строки могут быть отформатированы.

This contains 42.121% DDT and 2.1% EEG

Now with DDT: 12% EEG: 23.2%

47 DDT 22 EEG

EEG N/A DDT 43

5% EEG 20% DDT and more

По сути, мне нужно иметь возможность выбрать оба значения, перед которыми стоит их идентификатор, а затем

Я использовал | между двумя селекторами, чтобы захватить оба «случая» для каждого значения, но у меня возникли проблемы. Я хочу запретить регулярному выражению выбирать "12% ЭЭГ" во второй строке примера. Я пытаюсь использовать негативные взгляды и позитивные взгляды, но не могу заставить его работать.

Вот регулярное выражение для выбора просто ддт

(?<=eeg)(\d{1,3}\.?\d{1,6}).{,10}?ddt|ddt(?!.*eeg).{,10}?(\d{1,3}\.?\d{1,6})

Это самое близкое, что я получил, но все равно он не работает правильно. Эта версия не соответствует «20% ДДТ».

Мое оригинальное регулярное выражение не использовало lookbehinds, но в некоторых случаях также не работает.

(?:(?:(\d{1,3}\.?\d*)[^(?:eeg)]{0,10}?ddt)|(?:ddt[^(?:eeg)]{0,10}?(\d{1,3}\.?\d*)))

Мой оригинальный подход не распознает 23,2% строки ЭЭГ, отформатированные следующим образом. «ДДТ: 12% ЭЭГ: 23,2%»

Я не уверен, возможен ли этот тип селектора с регулярным выражением, но я хочу использовать регулярное выражение для векторизации этого извлечения. У меня есть функция, которая хорошо характеризует эти строки, но она очень медленная на больших наборах данных (~ 1 миллион записей). Регулярное выражение работает быстро и его легко применять к векторам, поэтому я хочу использовать его. Если есть другие предложения по решению этой проблемы с помощью функций NLP или numpy / pandas, я также открыт для них.

1 Ответ

0 голосов
/ 17 мая 2019

Вы можете попробовать следующее, по крайней мере, для этих случаев:

1 / выработка, которая является первой ЭЭГ или ДДТ:

In [11]: s.str.extract("(DDT|EEG)")
Out[11]:
     0
0  DDT
1  DDT
2  DDT
3  EEG
4  EEG

2 / вытащить все цифры:

In [12]: s.str.extract("(\d+\.?\d*|N/A).*?(\d+\.?\d*|N/A)")
Out[12]:
        0     1
0  42.121   2.1
1      12  23.2
2      47    22
3     N/A    43
4       5    20

Чтобы избавиться от N / A, вы можете применить to_numeric:

In [13]: res = s.str.extract("(\d+\.?\d*|N/A).*?(\d+\.?\d*|N/A)").apply(pd.to_numeric, errors='coerce', axis=1)

In [14]: res
Out[14]:
        0     1
0  42.121   2.1
1  12.000  23.2
2  47.000  22.0
3     NaN  43.0
4   5.000  20.0

Теперь вам нужно переставить эти столбцы, чтобы они соответствовали их соответствующим ДДТ / ЭЭГ:

In [15]: pd.DataFrame({
           "DDT": res[0].where(s.str.extract("(DDT|EEG)")[0] == 'DDT', res[1]),
           "EEG": res[1].where(s.str.extract("(DDT|EEG)")[0] == 'DDT', res[0])
         })
Out[15]:
      DDT   EEG
0  42.121   2.1
1  12.000  23.2
2  47.000  22.0
3  43.000   NaN
4  20.000   5.0

Здесь s - оригинальная серия / столбец:

In [21]: s
Out[21]:
0    This contains 42.121% DDT and 2.1% EEG
1              Now with DDT: 12% EEG: 23.2%
2                             47 DDT 22 EEG
3                            EEG N/A DDT 43
4                   5% EEG 20% DDT and more
dtype: object

Предполагается, что присутствуют как ДДТ, так и ЭЭГ, возможно, вам придется отключить строки, где это не так (в которых есть только один из ДДТ / ЭЭГ) ...

...