将pd.read_html返回的DataFrame列表转换为Pandas中的DataFrame。

4
有没有一种方法可以修改pd.read_html,使其返回一个数据框而不是数据框列表?
背景: 我正在尝试使用pandas read_html从网站导入表格。我了解到pd.read_html返回的是数据框列表而不是单个数据框。我一直通过将pd.read_html返回的列表中的第一个(也是唯一的)数据框分配给一个新变量来规避这个问题。但是,我想从不同的url存储多个数据框在主字典中(使用下面的代码),并希望值是数据框元素,而不是列表。
urls_dict = {
    '2017': 'https://postgrad.sgu.edu/ResidencyAppointmentDirectory.aspx?year=2017',
    '2016': 'https://postgrad.sgu.edu/ResidencyAppointmentDirectory.aspx?year=2016',
    '2015': 'https://postgrad.sgu.edu/ResidencyAppointmentDirectory.aspx?year=2015',
    '2014': 'https://postgrad.sgu.edu/ResidencyAppointmentDirectory.aspx?year=2014',
    '2013': 'https://postgrad.sgu.edu/ResidencyAppointmentDirectory.aspx?year=2013',
    '2012': 'https://postgrad.sgu.edu/ResidencyAppointmentDirectory.aspx?year=2012',
    '2011': 'https://postgrad.sgu.edu/ResidencyAppointmentDirectory.aspx?year=2011',
    '2010': 'https://postgrad.sgu.edu/ResidencyAppointmentDirectory.aspx?year=2010',
    '2009': 'https://postgrad.sgu.edu/ResidencyAppointmentDirectory.aspx?year=2009'        
}

dfs_dict = {}
for key, url in urls_dict.items():
   dfs_dict[key] = pd.read_html(url)
2个回答

3

pd.concat内使用列表推导式来连接每年的数据框(使用.assign(year=year)将相应年份添加为一列)。

请注意,pd.read_html(url)返回一个数据框列表。对于给定的url,列表的长度永远不会超过1,因此使用pd.read_html(url)[0]访问实际的数据框,然后分配年份作为一列。

dfs = pd.concat([pd.read_html(url)[0].assign(year=year) for year, url in urls_dict.items()])

请注意,您可以使用以下字典推导式和f-strings(Python 3.6中引入的格式化字符串字面量)一起创建urls_dict
years = range(2009, 2018)
urls_dict = {
    str(year): f'https://postgrad.sgu.edu/ResidencyAppointmentDirectory.aspx?year={year}' 
    for year in years
}

只是为了我理解所有这些。.assign(year = year) 将以年份(即我的 URL 字典中的键)作为列,并将年份分配为该列中的值?另外,为什么 pd.read_html(url)[0].assign(year=year) for year, url in urls_dict.items()] 要用方括号括起来?我是在创建要连接的 df 列表吗?感谢您的帮助! - gboge
1
考虑到你对@Datanovice发表的评论,你可能想将其更改为.assign(grad_year=year)。左侧是新列名(grad_year),右侧是要分配给该列的变量(根据urls_dict中的键给出的年份)。该表达式在方括号[...]中,因为它是一个列表推导式,生成一个数据框列表,这是传递给pd.concat函数的输入参数。 - Alexander

1
我理解为,我们可以轻微地编辑你的代码,并调用 pd.concat 来将你使用 pd.read_html 的所有调用连接起来。
dfs = {}  # initlaise the loop.
# acess the key and values of a dictionary.
# in {'2017' : [1,2,3]} 2017 is the key and [1,2,3] are the values. 
for key, url in urls_dict.items(): 
# for each unique item in your dict, read in the url and concat the list using pd.concat
    dfs[key] =(pd.concat(pd.read_html(url))) 
    dfs[key]['grad_year'] = key # if you want to assign the key to a column.
    dfs[key] = dfs[key].drop('PGY',axis=1) # drop PGY.

print(dfs['2017'].iloc[:5,:3])
   PGY         Type                       Name
0  PGY-1  Categorical       Van Denakker, Tayler
1  PGY-1  Preliminary  Bisharat-Kernizan, Jumana
2  PGY-1  Preliminary        Schiffenhaus, James
3  PGY-1  Categorical            Collins, Kelsey
4  PGY-1  Categorical             Saker, Erfanul

type(dfs['2017'])
pandas.core.frame.DataFrame

谢谢!现在我想从每个数据框中删除PGY列,并添加一个名为“grad_year”的新列,其中包含毕业年份(即键)。 - gboge
谢谢你!我是一个Python Pandas的新手,你能带我走一遍for循环吗? - gboge
@gboge,你非常受欢迎,我为你添加了一些注释 - 但是for循环是相当基础的,我建议你复习一下基本原理 :) - Umar.H
抱歉再次打扰,但是df[key]的目的是什么?我很难理解这部分。 - gboge
这是您初始字典中唯一的“key”,我们正在使用它来构建数据帧字典。@gboge,明白吗? - Umar.H
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接