【问题标题】:In python, reading multiple CSV's, with different headers, into one dataframe在python中,将具有不同标题的多个CSV读取到一个数据帧中
【发布时间】:2017-03-22 12:46:31
【问题描述】:

我有几十个带有相似(但并不总是完全相同)标题的 csv 文件。例如,有一个:

Year Month Day Hour Minute Direct Diffuse D_Global D_IR Zenith Test_Site

一个有:

Year Month Day Hour Minute Direct Diffuse2 D_Global D_IR U_Global U_IR Zenith Test_Site

(注意一个缺少“U_Global”和“U_IR”,另一个有“Diffuse2”而不是“Diffuse”)

我知道如何将多个 csv 传递到我的脚本中,但是如何让 csv 仅将值传递给它们当前具有值的列?并且可能将“Nan”传递给该行中的所有其他列。

理想情况下,我会有类似的东西:

'Year','Month','Day','Hour','Minute','Direct','Diffuse','Diffuse2','D_Global','D_IR','U_Global','U_IR','Zenith','Test_Site'
1992,1,1,0,3,-999.00,-999.00,"Nan",-999.00,-999.00,"Nan","Nan",122.517,"BER"
2013,5,30,15,55,812.84,270.62,"Nan",1078.06,-999.00,"Nan","Nan",11.542,"BER"
2004,9,1,0,1,1.04,79.40,"Nan",78.67,303.58,61.06,310.95,85.142,"ALT"
2014,12,1,0,1,0.00,0.00,"Nan",-999.00,226.95,0.00,230.16,115.410,"ALT"

另一个需要注意的是,需要附加此数据帧。当多个 csv 文件传入其中时,它需要保留。我想我可能会在最后把它写到它自己的 csv 中(它最终会写入 NETCDF4)。

【问题讨论】:

    标签: python csv pandas dataframe netcdf


    【解决方案1】:

    假设您有以下 CSV 文件:

    test1.csv:

    year,month,day,Direct 
    1992,1,1,11
    2013,5,30,11
    2004,9,1,11
    

    test2.csv:

    year,month,day,Direct,Direct2
    1992,1,1,21,201
    2013,5,30,21,202
    2004,9,1,21,203
    

    test3.csv:

    year,month,day,File3
    1992,1,1,text1
    2013,5,30,text2
    2004,9,1,text3
    2016,1,1,unmatching_date
    

    解决方案:

    import glob
    import pandas as pd
    
    files = glob.glob(r'd:/temp/test*.csv')
    
    def get_merged(files, **kwargs):
        df = pd.read_csv(files[0], **kwargs)
        for f in files[1:]:
            df = df.merge(pd.read_csv(f, **kwargs), how='outer')
        return df
    
    print(get_merged(files))
    

    输出:

       year  month  day  Direct   Direct  Direct2            File3
    0  1992      1    1     11.0    21.0    201.0            text1
    1  2013      5   30     11.0    21.0    202.0            text2
    2  2004      9    1     11.0    21.0    203.0            text3
    3  2016      1    1      NaN     NaN      NaN  unmatching_date
    

    更新:惯用的 pd.concat(list_of_dfs) 解决方案在这里不起作用,因为它是通过索引加入的:

    In [192]: pd.concat([pd.read_csv(f) for f in glob.glob(file_mask)], axis=0, ignore_index=True)
    Out[192]:
       Direct  Direct   Direct2            File3  day  month  year
    0     NaN     11.0      NaN              NaN    1      1  1992
    1     NaN     11.0      NaN              NaN   30      5  2013
    2     NaN     11.0      NaN              NaN    1      9  2004
    3    21.0      NaN    201.0              NaN    1      1  1992
    4    21.0      NaN    202.0              NaN   30      5  2013
    5    21.0      NaN    203.0              NaN    1      9  2004
    6     NaN      NaN      NaN            text1    1      1  1992
    7     NaN      NaN      NaN            text2   30      5  2013
    8     NaN      NaN      NaN            text3    1      9  2004
    9     NaN      NaN      NaN  unmatching_date    1      1  2016
    
    In [193]: pd.concat([pd.read_csv(f) for f in glob.glob(file_mask)], axis=1, ignore_index=True)
    Out[193]:
           0    1     2     3       4    5     6     7      8     9   10  11               12
    0  1992.0  1.0   1.0  11.0  1992.0  1.0   1.0  21.0  201.0  1992   1   1            text1
    1  2013.0  5.0  30.0  11.0  2013.0  5.0  30.0  21.0  202.0  2013   5  30            text2
    2  2004.0  9.0   1.0  11.0  2004.0  9.0   1.0  21.0  203.0  2004   9   1            text3
    3     NaN  NaN   NaN   NaN     NaN  NaN   NaN   NaN    NaN  2016   1   1  unmatching_date
    

    或明确使用index_col=None

    In [194]: pd.concat([pd.read_csv(f, index_col=None) for f in glob.glob(file_mask)], axis=0, ignore_index=True)
    Out[194]:
       Direct  Direct   Direct2            File3  day  month  year
    0     NaN     11.0      NaN              NaN    1      1  1992
    1     NaN     11.0      NaN              NaN   30      5  2013
    2     NaN     11.0      NaN              NaN    1      9  2004
    3    21.0      NaN    201.0              NaN    1      1  1992
    4    21.0      NaN    202.0              NaN   30      5  2013
    5    21.0      NaN    203.0              NaN    1      9  2004
    6     NaN      NaN      NaN            text1    1      1  1992
    7     NaN      NaN      NaN            text2   30      5  2013
    8     NaN      NaN      NaN            text3    1      9  2004
    9     NaN      NaN      NaN  unmatching_date    1      1  2016
    
    In [195]: pd.concat([pd.read_csv(f, index_col=None) for f in glob.glob(file_mask)], axis=1, ignore_index=True)
    Out[195]:
           0    1     2     3       4    5     6     7      8     9   10  11               12
    0  1992.0  1.0   1.0  11.0  1992.0  1.0   1.0  21.0  201.0  1992   1   1            text1
    1  2013.0  5.0  30.0  11.0  2013.0  5.0  30.0  21.0  202.0  2013   5  30            text2
    2  2004.0  9.0   1.0  11.0  2004.0  9.0   1.0  21.0  203.0  2004   9   1            text3
    3     NaN  NaN   NaN   NaN     NaN  NaN   NaN   NaN    NaN  2016   1   1  unmatching_date
    

    以下更惯用的解决方案有效,它改变了列和行/数据的原始顺序:

    In [224]: dfs = [pd.read_csv(f, index_col=None) for f in glob.glob(r'd:/temp/test*.csv')]
         ...:
         ...: common_cols = list(set.intersection(*[set(x.columns.tolist()) for x in dfs]))
         ...:
         ...: pd.concat((df.set_index(common_cols) for df in dfs), axis=1).reset_index()
         ...:
    Out[224]:
       month  day  year  Direct   Direct  Direct2            File3
    0      1    1  1992     11.0    21.0    201.0            text1
    1      1    1  2016      NaN     NaN      NaN  unmatching_date
    2      5   30  2013     11.0    21.0    202.0            text2
    3      9    1  2004     11.0    21.0    203.0            text3
    

    【讨论】:

    • 不要像这样使用合并在这里是非惯用和非性能 - 附加到列表和 concat 是模式
    • @Jeff,我将如何使用concat 合并公共列?
    • 试一试,根据定义,它将在非连续轴中联合;加入是不同的操作
    • 嗯,也许这是一个合并问题/我的快速浏览显示数据不相交;如果不是这样,那么合并就是答案
    • 就像解释器不必为了创建列表而将所有 csv 保存在内存中一样。如果迭代足够,生成器会更高效
    【解决方案2】:

    熊猫不能自动处理这个吗?

    http://pandas.pydata.org/pandas-docs/stable/merging.html#concatenating-using-append

    如果您的索引重叠,请不要忘记添加 'ignore_index=True'

    【讨论】:

    • 实际上,append 会以不同的方式合并 DF(与 OP 想要的相比)...
    【解决方案3】:

    首先,遍历所有文件以定义公共标头:

    csv_path = './csv_files'
    csv_separator = ','
    
    full_headers = []
    for fn in os.listdir(csv_path):
        with open(fn, 'r') as f:
            headers = f.readline().split(csv_separator)
            full_headers += full_headers + list(set(full_headers) - set(headers))
    

    然后将标题行写入输出文件,并再次运行所有文件以填充它。

    您可以使用:csv.DictReader(open('myfile.csv')) 来简单地将标题与其指定的列匹配。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-06-10
      • 2017-03-30
      • 1970-01-01
      • 2016-06-29
      • 2020-04-21
      • 1970-01-01
      • 1970-01-01
      • 2021-12-05
      相关资源
      最近更新 更多