读取多个txt,并使用原始文件中的名称为每个文件创建df

时间:2019-07-04 19:51:28

标签: python-3.x pandas csv

文件夹有五个或六个.csv文件。我想使用pd.read_csv()一次读取所有这些文件,然后将每个df保存为jupyter中的变量,该变量特定于文件名,而没有任何路径或文件类型。

例如,说这是两个文件:

'../main/data/csv_files/file_1.csv'
'../main/data/csv_files/file_2.csv'

我可以对每个人执行此操作

file_1 = pd.read_csv('../main/data/csv_files/file_1.csv')
file_2 = pd.read_csv('../main/data/csv_files/file_2.csv')

但是,我的问题是,如何在保持文件名命名约定的情况下,对循环或对所有文件立即执行所有操作?

我可以使用glob或其他方式来获取csv文件的所有文件路径的列表。然后,我可以创建一个字典将它们全部放入,但是它将使用它们的完整文件路径作为名称。

path = r'../main/data/csv_files'
files = glob.glob(path + '/*.csv')

dfs = {}
for x in files:
    dfs[x] = pd.read_csv(x)

这可行,但完整路径的命名并不理想。

2 个答案:

答案 0 :(得分:0)

如果您的文件名不是来自网络等不受信任的来源,请使用exec运行python命令。

import ntpath

for x in files:
    # /a/b/c.csv => c.csv
    file_without_path = ntpath.basename(x) 

    # c.csv => c
    file_without_extension = file_without_path[:-4] 

    # execute "c = pd.readcsv('a/b/c.csv')"
    exec("{} = pd.read_csv('{}')".format(file_without_extension, x))

如果不能信任文件名,则不要执行此操作,因为将执行文件名中的任何代码。

答案 1 :(得分:0)

您要尝试做的事情-创建与文件同名的动态局部变量是一种我很少遇到的模式,并且可能会出现问题,但是我已经展示了一种方法下面也是如此。相反,您应该尝试直接使用dict键。您可以创建一个dict子类,在其中您可以将键作为属性访问,类似于pandas允许作为属性或使用常规dict __getitem__机制访问列的方式。例如

  class AttributeDict(dict):
      """Access keys as attributes."""

      @classmethod
      def _forbidden(cls, key):
          """Key not allowed if it matches a class (not instance) attribute."""
          return key in dir(cls)

      def __setitem__(self, key, val):
          """Regular dict setitem + attribute set."""
          # key must be a regular python identifier, in order to be accesible as
          # an attribute.
          if not str.isidentifier(key):
              raise ValueError("'%s' it not a valid Python identifier. "
                               "Cannot set attribute." % key)

          # Prevent accidentally overwriting an important class attribute.
          if self._forbidden(key):
              raise ValueError("Key '%s' is a class attribute" % key)

          super().__setitem__(key, val)
          setattr(self, key, val)

      def __delitem__(self, key):
          """Regular dict delitem + attribute removal."""
          super().__delitem__(key)
          delattr(self, key)

该类尚未完成,因为它不会阻止直接设置属性,而该属性可能会使dict键值不同步。

In [4]: x = AttributeDict()                                                                                                                                        
In [5]: x['A'] = 1                                                                                                                                                 
In [6]: x['2A'] = 1                                                                                                                                                

ValueError: '2A' it not a valid Python identifier. Cannot set attribute.

In [7]: x['B'] = 2                                                                                                                                                 
In [8]: x.A                                                                                                                                                        
Out[8]: 1
In [9]: x.B                                                                                                                                                        
Out[9]: 2

您的特定用例如下:

dfs = AttributeDict()
for x in files:
    dfs[x] = pd.read_csv(x)

dfs.file1
dfs.file2

现在,要回答原始问题,您可以使用locals()

for x in files:
    if not str.isidentifier(x):
        raise ValueError("'%s' not a valid identifier." % x)
    locals()[x] = pd.read_csv(x)

文件名是有效的标识符,但与重要的本地变量冲突将造成严重破坏!例如,如果您正在IPython会话中并且执行locals()['exit'] = None,则可以再使用exit命令!