pandas 如何用漂亮的汤刮一个透视表[已关闭]

p5cysglq  于 2023-02-17  发布在  其他
关注(0)|答案(1)|浏览(119)

**已关闭。**此问题不符合Stack Overflow guidelines。当前不接受答案。

我们不允许问题寻求有关书籍、工具、软件库等的推荐。你可以编辑问题,以便可以使用事实和引用来回答问题。
6天前关闭。
Improve this question
我试图使用Beautiful Soup来抓取一个复杂的Wikipedia表(我不确定用术语“透视表”来概括这样的表是否合适),希望在Pandas中重新创建一个更简单、更易于分析的版本。
JLPT "Applications and results" table on English Wikipedia
作为概述,从左侧开始:该表列出了JLPT举办的年份、当年开放的考试级别以及顶部列定义的统计数据。聚合列对我的目的来说并不重要,尽管如果有办法将其作为一个整体来抓取和重建,那就太好了。
这个表很难重构,因为它对行进行了分组(年份在'Year'列下),但是该年份的行与年份标题位于同一层次,而不是在下面。此外,不是在每一个<tr>行中有一个<th>标记的年份,它只出现在年份组的第一行中:
HTML structure of the table
另一个问题是,年份标题在其标记或属性中没有任何类型的定义标识符,因此我也不能只选取其中包含年份的行。
这些因素使得无法按年份对行进行分组。
到目前为止,我能够重建表的 * 一些 * 的唯一方法是:
1.刮擦整个table,
1.将每个<tr>元素附加到列表中,
1.因为每一年都有一个方括号内的引文:删除其中包含[的字符串的每个示例,从而使每行中的元素长度一致
1.将它们转换成Pandas Dataframe (手动添加列名,使用正则表达式删除剩余的HTML,等等),不带年份:
Row elements in a list
Processed dataframe (minus the years)
到目前为止,我意识到如果不手动地按年份对行进行分组仍然很困难。我想知道是否有一种更简单、更直接的方法,可以只使用BeautifulSoup本身来抓取类似复杂的表,而几乎不使用panda进行后处理。在这种情况下,如果无法以原始透视格式获取表,也没关系。我只想为每一行设置年份值,类似于:
Dataframe goal

f0brbegy

f0brbegy1#

你不需要使用BeautifulSoup来完成这个任务,相反,你可以直接使用pd.read_html来获取你所需要的。当你阅读维基百科的HTML时,它会把所有的表拉到一个列表中。如果你浏览这个列表,你会看到它是第10个 Dataframe 。

df = pd.read_html('https://en.wikipedia.org/wiki/Japanese-Language_Proficiency_Test')[10]

从这里开始,您将执行一些数据清理以创建所需的表。

# Convert multi-level column into single columns
df.columns = df.columns.map('_'.join)

#Fix column names
df = df.rename({'Year_Year': 'dummy_year',
                'Level_Level': 'level',
                'JLPT in Japan_Applicants': 'japan_applicants',
                'JLPT in Japan_Examinees': 'japan_examinees',
                'JLPT in Japan_Certified (%)': 'japan_certified',
                'JLPT overseas_Applicants': 'overseas_applicants',
                'JLPT overseas_Examinees': 'overseas_examinees',
                'JLPT overseas_Certified (%)': 'overseas_certified'},
               axis=1)

# Remove text in [], (). Remove commas. Convert to int.
df['japan_certified']    = df['japan_certified'].str.replace(r'\([^)]*\)', '', regex=True).str.replace(',', '').astype(int)
df['overseas_certified'] = df['overseas_certified'].str.replace(r'\([^)]*\)', '', regex=True).str.replace(',', '').astype(int)
df['dummy_year']         = df['dummy_year'].str.replace(r'\[.*?\]', '', regex=True)

输出:

dummy_year  level  ...  overseas_examinees  overseas_certified
0         2007  1 kyū  ...              110937               28550
1         2007  2 kyū  ...              152198               40975
2         2007  3 kyū  ...              113526               53806
3         2007  4 kyū  ...               53476               27767
4         2008  1 kyū  ...              116271               38988
..         ...    ...  ...                 ...                 ...
127     2022-1     N1  ...               49223               17282
128     2022-1     N2  ...               54542               25677
129     2022-1     N3  ...               41264               21058
130     2022-1     N4  ...               40120               19389
131     2022-1     N5  ...               30203               16132

相关问题