Удаление верхнего заголовка из Dataframe

я хотел бы прочитать таблицу со следующей страницы: Страны по ВВП

Я попробовал команду pandas read_html и получил следующий результат:

import requests

    from bs4 import BeautifulSoup
    import pandas as pd
    data =pd.DataFrame(pd.read_html("https://en.wikipedia.org/wiki/List_of_countries_by_GDP_(nominal)")[2])
    print(data.head())
  Country/Territory UN Region  ... United Nations[15]           
  Country/Territory UN Region  ...           Estimate       Year
0             World         —  ...           85328323       2020
1     United States  Americas  ...           20893746       2020
2             China      Asia  ...           14722801  [n 1]2020
3             Japan      Asia  ...            5057759       2020
4           Germany    Europe  ...            3846414       2020

вопрос: как я могу удалить первый контент? например, мы можем перебрать все строки:

for index, row  in data.iterrows():
    print(index,row)

и создайте пустой фрейм данных и все элементы, начиная с индекса один (поэтому удалите первый индекс и сохраните остальные в пустом фрейме данных), но я уверен, что существует более профессиональный способ (может быть, нам нужна небольшая помощь от регулярного выражения? или BeautifulSoup?) заранее спасибо

Отредактировано

с помощью отличного человека я решил эту проблему, но есть еще одна проблема, пожалуйста, посмотрите на таблицу ниже:

Country/Territory UN Region   Estimate  ...       Year  Estimate       Year
0             World         —  101560901  ...       2021  85328323       2020
1     United States  Americas   25035164  ...       2021  20893746       2020
2             China      Asia   18321197  ...  [n 3]2021  14722801  [n 1]2020
3             Japan      Asia    4300621  ...       2021   5057759       2020
4           Germany    Europe    4031149  ...       2021   3846414       2020

вы можете видеть дополнительные ненужные символы [n 1] перед теми же данными, возможно, из-за NaN или чего-то подобного, мы можем просто отфильтровать такие данные? а остальные оставить?

Отредактировано: я попытался создать одну общую функцию, а затем применить ко всему столбцу Year, вот очень простой пример: если мы извлекаем только первый элемент:

result =data.loc[2,"Year"][0]

что равно: [n 1]2022

тогда, конечно, я могу разделить его:

print(result.split("]")[1])

сейчас: 2022, на основе этой информации я создал следующую функцию:

def  split_column(text):
   if  len(text)==4:
       return int(text)
   else:
       return int(text.split("]")[1])

логика заключается в том, что если len(text)==4 означает, что у нас есть строка, состоящая только из 4 цифр (например, 2020), и, следовательно, напрямую преобразуется в число, в противном случае применяется логика, упомянутая в предыдущем примере, но когда я запускаю:

data['Year'] =data['Year'].apply(split_column,axis=1)

это дает мне ошибку:

AttributeError: 'Series' object has no attribute 'split'. Did you mean: 'plot'?

не странно? заранее спасибо

Решено

наконец, это решается с помощью данного кода:

def  split_column(text):
   if  len(text)==4:
       return int(text)
   elif text= = "—":
       return 0
   else:
       return int(text.split("]")[1])

вот полный код:

import requests
from bs4 import BeautifulSoup
import pandas as pd
wiki_link = "https://en.wikipedia.org/wiki/List_of_countries_by_GDP_(nominal)"
def  split_column(text):
   if  len(text)==4:
       return int(text)
   elif text= = "—":
       return 0
   else:
       return int(text.split("]")[1])
data = pd.DataFrame(pd.read_html(wiki_link)[2]).droplevel(0, axis=1).loc[:, lambda x: ~x.columns.duplicated()]
data.dropna(inplace=True)
print(data['Year'].value_counts())
print(data['Year'])
# data['Year'] =data['Year'].map(split_column)
# for col in data.columns:
#     print(col)
#     # if col=='Year':
#     #     data[col] =data[col].map(split_column)
data['Year'] =data['Year'].map(split_column)
print(data.head())
# result =data.loc[2,"Year"][0]
# print(result.split("]")[1])
# print(result)
# print(data.head())
# print(data.columns)
# print(data['Year'].loc[2,:][0].split("]")[1])
# print(len(data['Year'].iloc[0,0]))

Я не понимаю, почему вы хотите удалить первый уровень, так как источник другой. Может быть, вам следует агрегировать значения по средним значениям для источников МВФ, ВБ и ООН, нет?

Corralien 05.04.2023 09:47

если это две разные таблицы, как их разделить, чтобы не потерять важную информацию?

neural science 05.04.2023 10:10

Взгляните на мой ответ, пожалуйста.

Corralien 05.04.2023 10:32
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
2
3
74
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Похоже, столбцы являются MultiIndex, поэтому вы можете использовать droplevel :

wiki_link = "https://en.wikipedia.org/wiki/List_of_countries_by_GDP_(nominal)"
    ​
data = (
        pd.DataFrame(pd.read_html(wiki_link)[2])
            .droplevel(0, axis=1) # <- we drop here the top header
            .loc[:, lambda x: ~x.columns.duplicated()]
            .query(r'~Year.str.contains(r"\[")')
     )

​ Выход :

print(data)

    Country/Territory UN Region   Estimate  Year
0               World         —  101560901  2022
1       United States  Americas   25035164  2022
3               Japan      Asia    4300621  2022
..                ...       ...        ...   ...
214             Nauru   Oceania        134  2022
215        Montserrat  Americas          —     —
216            Tuvalu   Oceania         64  2022

[207 rows x 4 columns]

Обновлять :

Основываясь на комментарии @Corralien, похоже, вы хотите этого:

df = pd.DataFrame(pd.read_html(wiki_link)[2])
     
out = (
        df.iloc[:, :2].droplevel(0, axis=1)
            .join(df.iloc[:, 2:]
                  .pipe(lambda df_: df_.set_axis([f"{c2} ({c1.split('[')[0]})"
                        for c1,c2 in df_.columns], axis=1)))
            .replace(r"\[.*\]", "", regex=True)
    )

Выход :

 print(out)

    Country/Territory UN Region Estimate (IMF) Year (IMF)  \
0               World         —      101560901       2022   
1       United States  Americas       25035164       2022   
2               China      Asia       18321197       2022   
..                ...       ...            ...        ...   
214             Nauru   Oceania            134       2022   
215        Montserrat  Americas              —          —   
216            Tuvalu   Oceania             64       2022   

    Estimate (World Bank) Year (World Bank) Estimate (United Nations)  \
0                96513077              2021                  85328323   
1                22996100              2021                  20893746   
2                17734063              2021                  14722801   
..                    ...               ...                       ...   
214                   133              2021                       135   
215                     —                 —                        68   
216                    63              2021                        55   

    Year (United Nations)  
0                    2020  
1                    2020  
2                    2020  
..                    ...  
214                  2020  
215                  2020  
216                  2020  

[217 rows x 8 columns]

спасибо, сэр, я могу добавить здесь один вопрос: некоторые строки содержат такие данные: 2 China Asia 18321197 ... [n 3]2021 14722801 [n 1]2020 можно удалить [n 3] такую ​​ненужную часть из фрейма данных ? например просто бросить

neural science 05.04.2023 09:23

Привет, я обновил свой ответ, чтобы избавиться от этих строк, а также удалить повторяющиеся столбцы.

Timeless 05.04.2023 09:41

мы также должны использовать команду split, верно? я обновлю свою работу

neural science 05.04.2023 09:44

Вы пробовали мой обновленный код? Это должно дать вам то, что вы ожидаете. Но, как упомянул @Corralien в комментариях, таблица, кажется, содержит две разные таблицы/информацию, вы уверены в своих ожиданиях?

Timeless 05.04.2023 10:00

сэр, вы могли бы увидеть мой код? да, я видел твой, я просто хочу потренироваться, конечно, я соглашусь

neural science 05.04.2023 10:09

Я обновил свой ответ одним кадром данных, который сглаживает столбцы (ни один из столбцов или строк не удаляется). Если вам нужен красивый подход, вам лучше проверить ответ @Corralien.

Timeless 05.04.2023 10:40

Вы должны вручную разобрать HTML-таблицу:

import pandas as pd
import numpy as np
import requests
import bs4
import re
import io

# Get HTML table
resp = requests.get('https://en.wikipedia.org/wiki/List_of_countries_by_GDP_(nominal)')
soup = bs4.BeautifulSoup(resp.text)
table = soup.find('caption', text=re.compile('GDP.*by country')).parent

# Create headers
header = pd.MultiIndex.from_product([['IMF', 'World Bank', 'United Nations'], ['Estimate', 'Year']], names=['Source', 'Data'])

# Parse data
data = {}
for row in table.find_all('tr', {'class': None}):
    cols = row.find_all('td')
    key = cols[0].text.strip(), cols[1].text.strip()
    data[key] = []
    for col in cols[2:]:
        if col.has_attr('colspan'):
            data[key].append(np.nan)  # Estimate
            data[key].append(pd.NA)   # Year
            continue
        val = int(re.sub('\[.*\]', '', col.text).strip().replace(',', ''))
        data[key].append(val)

df = pd.DataFrame.from_dict(data, orient='index', columns=header)
df.index = pd.MultiIndex.from_tuples(df.index, names=['Country', 'Territory'])

Выход:

>>> df
Source                          IMF        World Bank       United Nations      
Data                       Estimate  Year    Estimate  Year       Estimate  Year
Country       Territory                                                         
United States Americas   25035164.0  2022  22996100.0  2021     20893746.0  2020
China         Asia       18321197.0  2022  17734063.0  2021     14722801.0  2020
Japan         Asia        4300621.0  2022   4937422.0  2021      5057759.0  2020
Germany       Europe      4031149.0  2022   4223116.0  2021      3846414.0  2020
India         Asia        3468566.0  2022   3173398.0  2021      2664749.0  2020
...                             ...   ...         ...   ...            ...   ...
Palau         Oceania         226.0  2022       218.0  2021          264.0  2020
Kiribati      Oceania         207.0  2022       207.0  2021          181.0  2020
Nauru         Oceania         134.0  2022       133.0  2021          135.0  2020
Montserrat    Americas          NaN  <NA>         NaN  <NA>           68.0  2020
Tuvalu        Oceania          64.0  2022        63.0  2021           55.0  2020

[216 rows x 6 columns]

Теперь вы можете изменить форму вашего фрейма данных:

>>> pd.concat([df['IMF'], df['World Bank'], df['United Nations']], keys=df.columns.levels[0])

Data                                  Estimate  Year
Source     Country       Territory                  
IMF        United States Americas   25035164.0  2022
           China         Asia       18321197.0  2022
           Japan         Asia        4300621.0  2022
           Germany       Europe      4031149.0  2022
           India         Asia        3468566.0  2022
...                                        ...   ...
World Bank Palau         Oceania         264.0  2020
           Kiribati      Oceania         181.0  2020
           Nauru         Oceania         135.0  2020
           Montserrat    Americas         68.0  2020
           Tuvalu        Oceania          55.0  2020

[648 rows x 2 columns]

Совокупная оценка по среднему значению (территория, страна, год) из разных источников:

>>> (pd.concat([df['IMF'], df['World Bank'], df['United Nations']])
       .groupby(['Territory', 'Country', 'Year'])['Estimate'].mean())

Territory  Country  Year
Africa     Algeria  2020    147689.0
                    2021    167983.0
                    2022    187155.0
           Angola   2020     62307.0
                    2021     72547.0
                              ...   
Oceania    Tuvalu   2021        63.0
                    2022        64.0
           Vanuatu  2020       855.0
                    2021       984.0
                    2022       984.0
Name: Estimate, Length: 608, dtype: float64

BeautifulSoup для меня немного слабое место, я знаю некоторые детали, но недостаточно. Я должен изучать это все больше и больше.

neural science 05.04.2023 10:59

Да, но когда таблицы отформатированы человеком и не готовы к обработке данных, использование BeautifulSoup — лучший вариант. В моем ответе оценка является плавающей, поэтому вы можете использовать математическую операцию над ней.

Corralien 05.04.2023 11:05

Другие вопросы по теме