Pandas фреймы данных с многоуровневыми столбцами: переименуйте указанный уровень c столбца, чтобы он совпадал с другим уровнем - PullRequest
1 голос
/ 09 апреля 2020

Извините за, казалось бы, запутанный заголовок. Я читал данные Excel, используя Pandas. Однако исходные данные Excel содержат несколько строк для заголовка, и некоторые ячейки объединяются. Это выглядит примерно так:

excel

На моем ноутбуке Jupyter это выглядит так:

have1

Мой план состоит в том, чтобы использовать только 2-й уровень в качестве имен столбцов и опустить уровень0. Но исходные данные содержат около 15 столбцов, которые отображаются как «Безымянный ...». Интересно, смогу ли я их переименовать, прежде чем удалять имена столбцов level0.

Желаемый результат выглядит следующим образом:

output

Я могу сделать это несколько раз, чтобы сначала я не сохранял его как CSV, а затем прочитайте это в Pandas. Теперь я потратил больше времени, чем хотел бы признать на исправление имен столбцов. Интересно, есть ли способ сделать это с помощью функции вместо переименования каждого отдельного интересующего столбца.

Спасибо.

Ответы [ 2 ]

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

Я думаю, что здесь проще всего использовать понимание списка - получить значения MultiIndex, только если текст Unnamed отсутствует:

df.columns = [first if 'Unnamed' in second else second for first, second in df.columns]
print (df)
   Purchase/sell_time  Quantity  Price Side
0 2020-04-09 15:22:00        20     43    B
1 2020-04-09 16:22:00        30     56    S

Но если возможно большее количество уровней в реальных данных, некоторые столбцы следует дублировать, поэтому не может выбрать их (если выбрать по дублированному столбцу получить все столбцы, а не только один, например, df['dup_column_name']).

Вы можете проверить это:

print (df.columns[df.columns.duplicated(keep=False)])

Тогда я предлагаю объединить все неназванные уровни для предотвращения этого:

df.columns = ['_'.join(y for y in x if 'Unnamed' not in y) for x in df.columns]
print (df)
   Purchase/sell_time  Purchase/sell_time_Quantity  Purchase/sell_time_Price  \
0 2020-04-09 15:22:00                           20                        43   
1 2020-04-09 16:22:00                           30                        56   

  Side  
0    B  
1    S  
2 голосов
/ 09 апреля 2020

ваши столбцы многоиндексные, а индексы неизменны, то есть вы не можете изменить только часть из них. Вот почему я предлагаю извлечь оба уровня мультииндекса, затем создать массив с нужными вам столбцами и заменить столбец DataFrame следующим образом:

# First I reproduce your dataframe
df1 = pd.DataFrame({("Purchase/sell_time","Unnamed:"):  pd.date_range("2020-04-09 15:22:00", 
                                                        freq="H", periods = 2),
                    ("Purchase/sell_time", "Quantity"): [20,30],
                    ("Purchase/sell_time", "Price"): [43, 56],
                    ("Side", "Unnamed:") : ["B", "S"]})
df1 = df1.sort_index()

Это выглядит так:

 Purchase/sell_time                    Side
             Unnamed: Quantity Price Unnamed:
0 2020-04-09 15:22:00       20    43        B
1 2020-04-09 16:22:00       30    56        S

Как видите, столбец является многоиндексным:

MultiIndex([('Purchase/sell_time', 'Unnamed:'),
            ('Purchase/sell_time', 'Quantity'),
            ('Purchase/sell_time',    'Price'),
            (              'Side', 'Unnamed:')],
           )
# I retrieve the first and second level of the multiindex then create a array conditionnally 
# on the second level not starting with "Unnamed" 
first_header = df1.columns.get_level_values(0)
second_header = df1.columns.get_level_values(1)
merge_header = np.where(second_header.str.startswith("Unnamed:"),
                        first_header, second_header)
df1.columns = merge_header

Вот результат:

 Purchase/sell_time  Quantity  Price Side
0 2020-04-09 15:22:00        20     43    B
1 2020-04-09 16:22:00        30     56    S

Надеюсь, это поможет

...