Объединить строки на основе значения (pandas для Excel - xlsxwriter) - PullRequest
1 голос
/ 15 апреля 2020

Я пытаюсь вывести Pandas фрейм данных в файл Excel, используя xlsxwriter. Однако я пытаюсь применить форматирование на основе правил; в частности, пытается объединить ячейки, которые имеют одинаковое значение, но не могут придумать, как написать l oop. (Новое для Python здесь!)

См. Ниже ожидаемый результат по сравнению с ожидаемым:

enter image description here

(Как вы можете видеть на основе от изображения выше я пытаюсь объединить ячейки в столбце Имя, когда они имеют одинаковые значения).

Вот то, что я имею до сих пор:

#This is the logic you use to merge cells in xlsxwriter (just an example)
worksheet.merge_range('A3:A4','value you want in merged cells', merge_format)

#Merge Car type Loop thought process...
#1.Loop through data frame where row n Name = row n -1 Name
#2.Get the length of the rows that have the same Name
#3.Based off the length run the merge_range function from xlsxwriter, worksheet.merge_range('range_found_from_loop','Name', merge_format)


for row_index in range(1,len(car_report)):
     if car_report.loc[row_index, 'Name'] == car_report.loc[row_index-1, 'Name'] 
     #find starting point based off index, then get range by adding number of rows to starting point. for example lets say rows 0-2 are similar I would get 'A0:A2' which I can then put in the code below
     #from there apply worksheet.merge_range('A0:A2','[input value]', merge_format)

Любая помощь очень ценится!

Спасибо!

1 Ответ

2 голосов
/ 15 апреля 2020

Ваша логика c почти верна, однако я подошел к вашей проблеме немного по-другому:

1) Сортируйте столбец, убедитесь, что все значения сгруппированы.

2) Сбросьте индекс (используя reset_index () и, возможно, передайте arg drop = True).

3) Затем мы должны захватить строки, в которых значение является новым. Для этого создайте список и добавьте первую строку 1, потому что оттуда мы обязательно начнем.

4) Затем начните итерацию по строкам этого списка и проверьте некоторые условия:

4a Если у нас только одна строка со значением, метод merge_range выдаст ошибку, потому что он не может объединить одну ячейку. В этом случае нам нужно заменить merge_range методом write.

4b) С этим алгоритмом вы получите ошибку индекса при попытке записать последнее значение в списке (потому что он сравнивает его с значение в следующей позиции индекса, и поскольку оно является последним значением в списке, следующей позиции индекса не существует). Поэтому нам нужно особо упомянуть, что если мы получим ошибку индекса (что означает, что мы проверяем последнее значение), мы хотим слить или записать до последней строки кадра данных.

4 c) Наконец, я не принимал во внимание, если столбец содержит пустые или нулевые ячейки. В этом случае код необходимо скорректировать.

Наконец, код может показаться немного запутанным, вы должны иметь в виду, что 1-я строка для pandas проиндексирована 0 (заголовки разделены), тогда как для заголовков xlsxwriter 0 индексируется, а первая строка индексируется 1.

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

import pandas as pd

# Create a test df
df = pd.DataFrame({'Name': ['Tesla','Tesla','Toyota','Ford','Ford','Ford'],
                   'Type': ['Model X','Model Y','Corolla','Bronco','Fiesta','Mustang']})

# Create the list where we 'll capture the cells that appear for 1st time,
# add the 1st row and we start checking from 2nd row until end of df
startCells = [1]
for row in range(2,len(df)+1):
    if (df.loc[row-1,'Name'] != df.loc[row-2,'Name']):
        startCells.append(row)


writer = pd.ExcelWriter('test.xlsx', engine='xlsxwriter')
df.to_excel(writer, sheet_name='Sheet1', index=False)
workbook = writer.book
worksheet = writer.sheets['Sheet1']
merge_format = workbook.add_format({'align': 'center', 'valign': 'vcenter', 'border': 2})


lastRow = len(df)

for row in startCells:
    try:
        endRow = startCells[startCells.index(row)+1]-1
        if row == endRow:
            worksheet.write(row, 0, df.loc[row-1,'Name'], merge_format)
        else:
            worksheet.merge_range(row, 0, endRow, 0, df.loc[row-1,'Name'], merge_format)
    except IndexError:
        if row == lastRow:
            worksheet.write(row, 0, df.loc[row-1,'Name'], merge_format)
        else:
            worksheet.merge_range(row, 0, lastRow, 0, df.loc[row-1,'Name'], merge_format)


writer.save()

Вывод:

enter image description here

...