Разделение столбца на несколько столбцов в Python - PullRequest
0 голосов
/ 03 октября 2018

У меня есть код, который выводится на очень простом уровне:

Name
Workplace
And a abstract

Это повторяется снова и снова.Итак:

NameA
WorkplaceA
And a abstractA
NameB
WorkplaceB
And a abstractB
etc...

Мне нужно разделить это на три столбца:

NameCol  WorkplaceCol  AbstractCol

NameA    WorkplaceA    AbstractA
NameB    WorkplaceB    AbstractB
NameC    WorkplaceC    AbstractC
etc...

Мой код возвращается к началу, когда находит тег <h1>.Однако я не отображаю этот тег.Итак, одна запись - это имя, рабочее место и аннотация, пока не встретится новый тег <h1>.

Вот код, который у меня есть:

headernum = 0
i = 0
x = soup.find_all("h1")

for i in range(len(x)):
    header = soup.find_all('h1')[headernum]
    name = header.find_all_next('p')[1]
    print(name.text)
    workplace = name.find_all_next('i')[0]
    print(workplace.text)
    abstract = []
    for elem in name.next_siblings:
        if elem.name == 'h1':
            break
        if elem.name != 'p':
            continue
        abstract.append(elem.get_text())
    x = " ".join(abstract).replace("\n", " ").encode('utf-8')
    print(x)
    i += 1
    headernum += 1

Я пытаюсь разделить этои вставьте столбцы.

Ответы [ 2 ]

0 голосов
/ 03 октября 2018

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

Идея:

  • Написать функцию-генератор, которая перебирает текст и возвращает каждый полныйстрока в форме словаря.

  • Соберите их все

  • Когда вы отметили свой вопрос "pandas", переместите результат в кадр данных pandas

Вот рабочий пример.

import pandas as pd

example_text="""NameA
WorkplaceA
And a abstractA
NameB
WorkplaceB
And a abstractB
<h1>
NameC
WorkplaceC
And a abstractC"""

def next_name(mystr):
    lines = iter(mystr.split('\n'))
    while True:
        n = {'NameCol':None,
         'WorkplaceCol':None,
         'AbstractCol':None
        }
        try:
            n['NameCol'] = next(lines)
            if n['NameCol'] == '<h1>':
                continue
            n['WorkplaceCol'] = next(lines)
            if n['WorkplaceCol'] == '<h1>':
                continue
            n['AbstractCol'] = next(lines)
            if n['AbstractCol'] == '<h1>':
                continue
            yield n 
        except StopIteration:
            break

df = pd.DataFrame(next_name(example_text), columns=['NameCol','WorkplaceCol','AbstractCol'])
print(df)

Фрейм данных печатается как

  NameCol WorkplaceCol      AbstractCol
0   NameA   WorkplaceA  And a abstractA
1   NameB   WorkplaceB  And a abstractB
2   NameC   WorkplaceC  And a abstractC

Если вам нужно распечатать фрейм данных точно как ваш пример,Вот пример кода.

print(''.join(f'{x}\t' for x in df.columns))
print()
for row in df.iterrows():
    print(''.join(f'{x}\t' for x in row[1]))

Вывод

NameCol WorkplaceCol    AbstractCol 

NameA   WorkplaceA  And a abstractA 
NameB   WorkplaceB  And a abstractB 
NameC   WorkplaceC  And a abstractC 

Примечание: я использую Python 3.6, если вы используете более старую версию, вам нужно изменить команду печати.

Для сравнения, работа с пандами может выглядеть так (используя пример из кода выше)

df = pd.DataFrame(example_text.split('\n'))
df = df[df[0] != '<h1>'].reset_index().copy()
df['row'] = df.index // 3
result = df.groupby('row').agg(lambda x: list(x))[0].values

print('\t'.join(["NameCol", "WorkplaceCol", "AbstractCol"]))
print('')
print('\n'.join(['\t'.join(x) for x in result]))

, который выдает то же самое.

NameCol WorkplaceCol    AbstractCol

NameA   WorkplaceA  And a abstractA
NameB   WorkplaceB  And a abstractB
NameC   WorkplaceC  And a abstractC
0 голосов
/ 03 октября 2018

Предполагая, что у вас есть df как это:

col1
NameA
WorkplaceA
AbstractA
NameB
WorkplaceB
AbstractB

Вы можете сделать:

import numpy as np

# Set the same number for each 3 lines
df['index'] = df.index / 3
df['index'] = df['index'].apply(np.floor)

# Set 0 for Names, 1 for Workplaces and 2 for Abstract
df["type_id"] = df.index % 3

# Rename 0, 1 and 2 by a label
df["type_label"] = df["type_id"].map({0: "Name", 1: "Workplace", 2: "Abstract"})

# Pivot the table
df = df.pivot(index='index', columns='type_label', values='col1')
print(df)

Это даст вам:

type_label   Abstract   Name   Workplace
index
0.0         AbstractA  NameA  WorkplaceA
1.0         AbstractB  NameB  WorkplaceB
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...