#python #vowpalwabbit
#python #vowpalwabbit
Вопрос:
Я пытаюсь преобразовать csv (с 10 столбцами) в файл формата ввода vowpal wabbit txt. Некоторые столбцы csv содержат целочисленные значения, а некоторые — строки (например: com.12346.xyz). Например, если мои столбцы csv выглядят так:
loss weight SSD_id weight label imp feat_val
0.693147 0.693147 1 1.0 -1.0000 0.0000 com.12346.xyz
0.419189 0.145231 2 2.0 1.0000 -1.8559 com.12346.xyz
0.235457 0.051725 4 4.0 -1.0000 -2.7588 com.12356.xyz
6.371911 12.508365 8 8.0 -1.0000 -3.7784 com.12346.xyz
3.485084 0.598258 16 16.0 1.0000 -2.2767 com.12346.xyz
1.765249 0.045413 32 32.0 -1.0000 -2.8924 com.1236.xyz
1.017911 0.270573 64 64.0 -1.0000 -3.0438 com.12236.xyz
0.611419 0.204927 128 128.0 1.0000 -3.1539 com.16746.xyz
0.469127 0.326834 256 256.0 -1.0000 -1.6101 com.1946.xyz
0.403473 0.337820 512 512.0 1.0000 -2.8843 com.126.xyz
0.337348 0.271222 1024 1024.0 -1.0000 -2.5209 com.1346.xyz
0.328909 0.320471 2048 2048.0 1.0000 -2.0732 com.1234.xyz
0.309401 0.289892 4096 4096.0 1.0000 -2.7639 com.12396.xyz
и формат ввода vowpal wabbit выглядит следующим образом:
label weight |i imp SSD_id loss |c feat_val
и внутри значений файла vowpal wabbit txt должно быть:
-1 0.051725 |i imp:-2.7588 SSD_id:4 loss:0.235457 |c feat_val=com.12356.xyz
1 0.598258 |i imp:-2.7588 SSD_id:4 loss:3.485034 |c feat_val=com.12346.xyz
… и так далее… для всех значений строк. У меня есть огромное количество строк в файле csv, которые я хочу преобразовать в указанный выше формат и сохранить их все в одном файле txt. Я начал с этой небольшой функции, приведенной ниже:
def to_new_format(document, label=None):
return str(label or '') ' |i ' ' '.join(re.findall('w{3,}', document.lower())) 'n'
to_new_format(str(text_train[1])
но теперь я полностью потерян после многих попыток с фреймом данных, форматированием csv и попытками выполнения функций. Может кто-нибудь дать мне какое-то указание, как я могу добиться этого за минимальные строки кода.
Ответ №1:
Это проще сделать, чем может показаться, из-за некоторых удобных способов, которыми Pandas позволяет обрабатывать последовательности почти так же, как отдельные значения в Python.
Сначала мы импортируем ваш CSV-файл, обрабатывая все значения как строки, чтобы упростить форматирование:
import pandas as pd
df = pd.read_csv('test_data.txt', dtype=pd.StringDtype())
Ваш label
столбец записывается так же, как 1.0000
в вашем файле, но вы не хотите, чтобы в вашем выводе были десятичные числа или нули. Мы можем исправить это с помощью str.replace
метода Pandas.
df.label = df.label.str.replace('.0000', '', regex=False)
И вот волшебная часть: мы можем объединить их так же, как если бы они были отдельными строками!
formatted = (
df.label ' ' df.weight
' |i imp:' df.imp
' SSD_id: ' df.SSD_id
' loss:' df.loss
' |c feat_val=' df.feat_val
'n'
)
Этот код выглядит так, будто он создает строку, но из-за того, как он включает столбцы фрейма данных (каждый из которых представляет собой последовательность Pandas), результатом также является последовательность:
print(formatted)
0 -1 0.693147 |i imp:0.0000 SSD_id: 1 loss:0.693...
1 1 0.145231 |i imp:-1.8559 SSD_id: 2 loss:0.419...
2 -1 0.051725 |i imp:-2.7588 SSD_id: 4 loss:0.23...
3 -1 12.508365 |i imp:-3.7784 SSD_id: 8 loss:6.3...
4 1 0.598258 |i imp:-2.2767 SSD_id: 16 loss:3.48...
5 -1 0.045413 |i imp:-2.8924 SSD_id: 32 loss:1.7...
6 -1 0.270573 |i imp:-3.0438 SSD_id: 64 loss:1.0...
7 1 0.204927 |i imp:-3.1539 SSD_id: 128 loss:0.6...
8 -1 0.326834 |i imp:-1.6101 SSD_id: 256 loss:0....
9 1 0.337820 |i imp:-2.8843 SSD_id: 512 loss:0.4...
10 -1 0.271222 |i imp:-2.5209 SSD_id: 1024 loss:0...
11 1 0.320471 |i imp:-2.0732 SSD_id: 2048 loss:0....
12 1 0.289892 |i imp:-2.7639 SSD_id: 4096 loss:0....
При такой печати каждая строка усекается, но все это есть. Например:
print(formatted[0])
-1 0.693147 |i imp:0.0000 SSD_id: 1 loss:0.693147 |c feat_val=com.12346.xyz
Все, что осталось, это сохранить его в файл:
with open('out.txt', 'w') as f:
f.writelines(formatted)
Комментарии:
1. ваше решение очень чистое, выдающееся и простое для понимания. Я узнал кое-что новое. Я пробовал это с одной недели. Да, вы правы, это выглядит сложно, но просто реализовать, если все сделано правильно. Если данные поступают в формате json, будет ли это все еще действительным?
2. Рад, что это помогает! Честно говоря, я сейчас тоже изучаю Pandas, и ответ на этот вопрос был для меня познавательным. Так уж получилось, что у Pandas
read_json
тоже есть метод! Возможно, вам придется что-то изменить, в зависимости от того, как именно отформатирован ваш файл, но да, этот подход все равно должен работать.3. Я попробую с помощью read_json и опубликую здесь, если это сработает. Данные в основном поступают в формате json при отправке запроса, но для меня было слишком сложно найти какое-либо решение, поэтому я решил сначала попробовать с csv. Да, ваш подход к решению отлично работает с тем, что я пытался сделать с csv, и теперь попробую с json.
Ответ №2:
В последних версиях Vowpal Wabbit имеет модуль Python, который упрощает преобразование pandas DataFrame
в формат ввода Vowpal Wabbit.
Например, используя версию 8.11.0 и предполагая, что ваши типы столбцов следующие :
loss float64
weight float64
SSD_id int64
weight.1 float64
label int64
imp float64
feat_val object
dtype: object
вы могли бы использовать следующий код
from vowpalwabbit.DFtoVW import DFtoVW, SimpleLabel, Namespace, Feature
label = SimpleLabel(label="label", weight="weight")
namespaces = [
Namespace(features=[Feature(col) for col in ["imp", "SSD_id", "loss"]], name="i"),
Namespace(features=Feature("feat_val"), name="c")
]
converter = DFtoVW(df=dat, label=label, namespaces=namespaces)
затем вызовите метод convert_df
для получения выходных данных
examples = converter.convert_df()
print(examples)
['-1 0.693147 |i imp:0.0 SSD_id:1 loss:0.693147 |c feat_val=com.12346.xyz',
'1 0.145231 |i imp:-1.8559 SSD_id:2 loss:0.419189 |c feat_val=com.12346.xyz',
'-1 0.051725 |i imp:-2.7588 SSD_id:4 loss:0.235457 |c feat_val=com.12356.xyz',
'-1 12.508365 |i imp:-3.7784 SSD_id:8 loss:6.371911 |c feat_val=com.12346.xyz',
'1 0.598258 |i imp:-2.2767 SSD_id:16 loss:3.485084 |c feat_val=com.12346.xyz',
'-1 0.045413 |i imp:-2.8924 SSD_id:32 loss:1.765249 |c feat_val=com.1236.xyz',
'-1 0.270573 |i imp:-3.0438 SSD_id:64 loss:1.017911 |c feat_val=com.12236.xyz',
'1 0.204927 |i imp:-3.1539 SSD_id:128 loss:0.611419 |c feat_val=com.16746.xyz',
'-1 0.326834 |i imp:-1.6101 SSD_id:256 loss:0.469127 |c feat_val=com.1946.xyz',
'1 0.33782 |i imp:-2.8843 SSD_id:512 loss:0.403473 |c feat_val=com.126.xyz',
'-1 0.271222 |i imp:-2.5209 SSD_id:1024 loss:0.337348 |c feat_val=com.1346.xyz',
'1 0.320471 |i imp:-2.0732 SSD_id:2048 loss:0.328909 |c feat_val=com.1234.xyz',
'1 0.289892 |i imp:-2.7639 SSD_id:4096 loss:0.309401 |c feat_val=com.12396.xyz']
и записать его в файл
with open("test.dat", "w") as f:
for example in examples:
f.writelines(example "n")