在循环中创建多个数据框。

51
我有一个列表,每个条目都是一个公司名称。
companies = ['AA', 'AAPL', 'BA', ....., 'YHOO']

我想为列表中的每个条目创建一个新的数据框。

就像这样

(伪代码)

for c in companies:
     c = pd.DataFrame()

我已经搜索了一种方法来做这件事,但找不到。有什么想法吗?


1
你想让每个公司单独占据一列,还是所有公司都在一列中显示? - Scott
1
如果您想为每个公司创建一个DataFrame,那么每个DataFrame将包含哪些数据? - Alexander
6个回答

156

强调一下我对@maxymoo答案的评论,动态地向Python命名空间添加名称几乎总是一个坏主意(“code smell”)。原因有很多,其中最重要的是:

  1. 创建的名称可能会与逻辑中已经使用的变量发生冲突。

  2. 由于名称是动态创建的,您通常也会使用动态技术来检索数据。

这就是为什么字典被包含在语言中的原因。正确的做法是:

d = {}
for name in companies:
    d[name] = pd.DataFrame()

现在你可以编写一个单一的字典推导式表达式来做同样的事情,但有些人发现它不太易读:
d = {name: pd.DataFrame() for name in companies}

一旦创建了d,就可以通过d[x]检索公司xDataFrame,因此您可以轻松查找特定公司。要对所有公司进行操作,通常会使用类似以下循环:

for name, df in d.items():
    # operate on DataFrame 'df' for company 'name'

在Python 2中,你最好写成:
for name, df in d.iteritems():

因为这样可以避免在旧版本中实例化(name, df)元组列表的.items()创建。 尽管现在这主要是历史性的兴趣,但仍然会有一些Python 2应用程序存在并需要(希望偶尔的)维护。

6
好观点,我没有考虑过,但你完全是正确的。 - maxymoo
11
这个回答让我受益匪浅。 - Moondra
4
我不明白为什么另一个答案被接受了,而这个答案明显更好。 - Bowen Liu
5
原问题的提问者声望分数为67分,所以可能已经得到了他们想要的答案(也许在某个地方已经投入生产!),并且不再使用Stackoverflow。被接受的答案可能不太幸运地使用了exec,但从更大的方面来看,这只是小问题 - 虽然感谢您说这个更好。对我而言,Stackoverflow不是竞争,而是提供信息的一种可见需求方式。 - holdenweb

23

你可以这样做(尽管显然需要极度谨慎地使用 exec,如果这将是公开的面向代码)

for c in companies:
     exec('{} = pd.DataFrame()'.format(c))

在ipython笔记本中,我得到了以下错误: 文件 "<string>",第1行 S.1 = pd.DataFrame() ^ SyntaxError: 语法无效 - Luis Ibáñez Herrera
如果我不使用循环,只是执行带有随机c值的exec语句,例如format('test'),它就能够工作。 - Luis Ibáñez Herrera
1
错误信息显示“S.1”不是一个有效的变量名,因为变量不能包含标点符号。您可以尝试通过将代码更改为format(c.replace('.',''))来解决此问题。 - maxymoo
是的,我的一些公司名称中带有“.”。现在它起作用了!谢谢 :) - Luis Ibáñez Herrera
6
在Python命名空间中动态创建变量名称几乎总是不明智的做法。更合理的方法是使用字典d,并编写d[c] = pd.DataFrame()。例如,阅读这个答案,以开始理解为什么这是一个不好的想法。 - holdenweb
请注意,目前对于此类问题的规范回答在此处给出。 - holdenweb

7
以下是在循环中动态创建数据框的代码:
companies = ['AA', 'AAPL', 'BA', ....., 'YHOO']

for eachCompany in companies:
    #Dynamically create Data frames
    vars()[eachCompany] = pd.DataFrame()

关于vars()、locals()和globals()的区别,请参考以下链接:

What's the difference between globals(), locals(), and vars()?


6

除了以上优秀的答案外,如果您需要创建空数据帧,则以上内容将无缝运行,但是如果您需要基于某些过滤条件创建多个数据帧:

假设您得到的列表是某个数据帧的一列,并且您想为较大数据帧中的每个唯一公司创建多个数据帧:

  1. First take the unique names of the companies:-

    compuniquenames = df.company.unique()
    
  2. Create a data frame dictionary to store your data frames

    companydict = {elem : pd.DataFrame() for elem in compuniquenames}
    
上述两个已经在帖子中。
for key in DataFrameDict.keys():
    DataFrameDict[key] = df[:][df.company == key]

以上操作将为您提供一个数据框,其中包含所有具有匹配记录的唯一公司。

感谢@zx485的编辑。你能帮我回答一个问题吗:如何根据公司所有唯一名称将字典拆分回多个数据框? - ak3191
对不起,但我不是Python专家。 - zx485
2
我认为你的代码有问题。代码的最后一部分应该是:for key in companydict.keys(): companydict[key] = df[:][df.company == key]但无论如何,我并没有看到这个代码的确切输出。 - pink.slash
@pink.slash 对我来说,确切的代码可行,但如果有其他用例,我很乐意看一下。 - ak3191

2

以下是您可以采用的方法:

for xxx in yyy:
   globals()[f'dataframe_{xxx}'] = pd.Dataframe(xxx)

这是对上述讨论的解决方案的重要补充。 - undefined

1
以下是可重现的 -> 假设您有一个包含df/公司名称的列表:
companies = ['AA', 'AAPL', 'BA', 'YHOO']

你可能也有数据,大概也是一个列表?(或者更确切地说是列表的列表)像这样:

 content_of_lists = [
 [['a', '1'], ['b', '2']],
 [['c', '3'], ['d', '4']],
 [['e', '5'], ['f', '6']],
 [['g', '7'], ['h', '8']]
]

在这个特殊的例子中,df 应该非常相似,因此这不需要太复杂:
dic={}
for n,m in zip(companies, range(len(content_of_lists))):
   dic["df_{}".format(n)] = pd.DataFrame(content_of_lists[m]).rename(columns = {0: "col_1", 1:"col_2"}) 

这里你需要使用 dic["df_AA"] 来访问字典内的数据框。 但是如果你需要更多“独特”的数据框命名,我认为你需要使用例如if-conditions,如:

dic={}
    for n,m in zip(companies, range(len(content_of_lists))):
if n == 'AA':
    special_naming_1 = pd.DataFrame(content_of_lists[m]).rename(columns = {0:     
    "col_1", 1:"col_2"})
elif n == 'AAPL':
    special_naming_2 ...

这需要多付出一点努力,但它可以让你以更常规的方式获取数据框对象,只需编写special_naming_1而不是dic['df_AA'],并且如果数据框名称和列名很重要,它还可以让你更好地控制。


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