#python #excel #pandas
Вопрос:
Мне нужно прочитать несколько больших файлов Excel, чтобы попытаться очистить данные.
Я дошел до последней проблемы, связанной с тем, что в некоторых ячейках есть несколько строк, или я предполагаю, что некоторые ячейки охватывают несколько строк.
Это что-то вроде этого:
Index Col1 Col2 Col3
1 row1 row1 row1
2 row1.1
3 row1.2
4 row2 row2 row3
Когда я использую Pandas.read_excel(имя файла) или Pandas.Выделите файл, затем sheet.parse(имя листа), он, конечно, читается в индексах 2 и 3 в основном пустыми строками.
Как бы я мог объединить индексы 2 и 3 в 1 на основе того, что охватывает Col1?
Чтобы прояснить мой вопрос: как я мог читать в файле excel и объединять строки на основе того, какие строки охватывает первый столбец? Возможно ли это вообще?
Спасибо
Комментарии:
1. Как ты мог догадаться? На самом деле, это злоупотребление Excel. В Excel есть возможность переносить длинные строки в одну ячейку, которые будут экспортироваться в виде длинной записи в одной ячейке. Как бы то ни было, если
Col1
бы они были расширены таким образом, как вы могли бы сказать, что это не дополнительные строки?2. Я не создавал файлы, но да, это моя проблема. Похоже, это может занять много часов ручной работы…..
Ответ №1:
Я не знаю, встроена ли эта функциональность в Pandas, так как, честно говоря, Excel не предназначен для такого использования, но люди все равно склонны злоупотреблять этим. Чувак, я ненавижу Excel….. но это тема для другой темы.
Я думаю, что лучше всего здесь определить пользовательскую функцию на основе логики, которая, как вы знаете, применима к этим файлам. Поскольку в настоящее время я нахожусь в середине проекта, связанного с разнообразными и плохо отформатированными файлами Excel, я слишком хорошо знаком с такого рода мусором.
Это мое предложение, основанное на моем понимании данных и того, о чем вы спрашиваете. Возможно, его потребуется изменить в зависимости от особенностей ваших файлов.
last_valid = None
check_cols = [] # if only need to check a subset of cols for validity, do it here
for i, s in df.iterrows(): # This is slow, but probably necessary in this case
""" If all the rows are valid, we want to keep it as a reference in case
the following rows are not """
if all(s[check_cols].notna()):
lvi, last_valid = i, s
# need to store index and series so we can go back and replace it
continue
else: # here is the critical part
extra_vals = s[s.notna()] # find cells in row that have actual values
for col in extra_vals.index:
""" I'm creating a list and appending here since I don't know
your values or how they need to be handled exactly"""
last_valid[col] = list(last_valid[col]).append(extra_vals[col])
# replace that row in the dataframe
df.iloc[lvi, :] = last_valid
# drop extra rows:
df = df.dropna(axis=0, subset=check_cols)
Надеюсь, это сработает для тебя!
Комментарии:
1. Когда я пытаюсь это сделать, я получаю объект «float», который не может быть повторен. Я попытался переключить все столбцы с плавающей точкой на str, но все равно понял. Это происходит по адресу last_valid[col] = список(last_valid[col]).добавить(дополнительные значения[col])
2. Ах, извините за это! Не был уверен в точном форматировании, но надеюсь, что вы смогли заставить его работать.
Ответ №2:
@LiamFiddler ответ правильный, но нуждался в некоторой корректировке, чтобы работать в моей ситуации, так как я объединяю числа в одной строке и буду выводить в csv в виде строк. Я публикую свой на случай, если это поможет кому-то, кто придет сюда
last_valid = None
check_cols = ['Col1'] # if only need to check a subset of cols for validity, do it here
df = df.astype(str) #convert all columns to strings as I have to combine numbers in the same cell
df = df.replace('nan','') #get rid of the nan created back to a blank string
for i, s in df.iterrows(): # This is slow, but probably necessary in this case
""" If all the rows are valid, we want to keep it as a reference in case
the following rows are not """
if all(s[check_cols] != ''):
lvi, last_valid = i, s
# need to store index and series so we can go back and replace it
continue
else: # here is the critical part
extra_vals = s[s != ''] # find cells in row that have actual values
for col in extra_vals.index:
""" I'm creating a list and appending here since I don't know
your values or how they need to be handled exactly"""
last_valid[col] = last_valid[col] "," extra_vals[col] #separate by whatever you wish, list was causing issues
# replace that row in the dataframe
df.iloc[lvi, :] = last_valid
# drop extra rows:
df = df[df['Col1'] != ''].reset_index(drop=True)