【问题标题】:Appending CSV files, matching unordered columns附加 CSV 文件,匹配无序列
【发布时间】:2015-03-10 19:34:27
【问题描述】:

问题:在附加 CSV 文件时匹配列

我有 50 个 .csv 文件,其中每一列是一个单词,每一行是一天中的一个时间,每个文件包含一天中的所有单词。它们看起来像这样:

Date  Time Aword Bword Cword Dword
Date1 t1   0     1     0     12
Date1 t2   0     6     3     0

Date  Time Eword Fword Gword Hword Bword
Date2 t1   0     0     1     0     3
Date2 t2   2     0     0     19    0

我想追加文件,以便在新列中添加新词时匹配具有相同单词的任何列(如本例中的 Bword):

Date  Time Aword Bword Cword Dword Eword Fword Gword Hword
Date1 t1   0     1     0     12                       
Date1 t2   0     6     3     0                        
Date2 t1         3                 0     0     1     0   
Date2 t2         0                 2     0     0     19

我将 csv 文件作为数据框打开以对其进行操作并使用 dataframe.append 添加新文件,如下所示:

Date  Time Aword Bword Cword Dword
Date1 t1   0     1     0     12
Date1 t2   0     6     3     0
Date  Time Eword Fword Gword Hword Bword
Date2 t1   0     0     1     0     3
Dat2e t2   2     0     0     19    0

是否有其他方法可以在追加时对齐匹配的列?即不遍历每一列并检查匹配项。

如果这个问题太含糊,我深表歉意,我是 python 新手,仍然很难知道我何时以非 Python 方式思考以及何时使用错误的工具。 p>

编辑:更多信息
1) 我需要多次执行此任务,每五批 csvs 执行一次
2) 这些文件都有 25 行,但有 5 到 294 列
3) 行的顺序很重要 Day1(t1, t2...tn) 然后 Day2(t1, t2...tn)
4) 列的顺序并不重要

【问题讨论】:

  • 对此有多种解决方案,哪种最好取决于几件事。 (1.) 这是一次性任务还是要重复运行的任务(如果是后者,在什么情况下?) (2.) 文件有多大?
  • 1) 我需要多次执行此任务,五批 csv 中的每批执行一次。 2) 这些文件都有 25 行,但有 5 到 294 列。

标签: python csv pandas


【解决方案1】:

IIUC,你可以简单地使用pd.concat,它会自动在列上对齐:

>>> csvs = glob.glob("*.csv")
>>> dfs = [pd.read_csv(csv) for csv in csvs]
>>> df_merged = pd.concat(dfs).fillna("")
>>> df_merged
  Aword  Bword Cword   Date Dword Eword Fword Gword Hword Time
0     0      1     0  Date1    12                           t1
1     0      6     3  Date1     0                           t2
0            3        Date2           0     0     1     0   t1
1            0        Date2           2     0     0    19   t2

(虽然我建议fillna(0) 或将其保留为nan;如果您填充一个空字符串以看起来像您想要的输出,则该列必须具有 object dtype 并且这些比 int 慢得多或浮动。)

如果你真的对列顺序很讲究,你可以作弊并使用(re)set_index

>>> df_merged.set_index(["Date", "Time"]).reset_index()
    Date Time Aword  Bword Cword Dword Eword Fword Gword Hword
0  Date1   t1     0      1     0    12                        
1  Date1   t2     0      6     3     0                        
2  Date2   t1            3                 0     0     1     0
3  Date2   t2            0                 2     0     0    19

【讨论】:

  • 非常感谢您的帮助。当我使用您的方法时,我会通过索引号而不是按列名找到列(例如,按 0、1、2、3 而不是 Aword、Bword 等)。有没有办法解决这个问题?
【解决方案2】:

我认为对于这种事情,您可能会发现使用 pandas 库会更容易一些。假设filelist 是一个文件名列表。

import pandas as pd

df = pd.concat([pd.read_csv(fl, index_col=[0,1]) for fl in filelist])

你就完成了!作为旁注,如果您想组合日期和时间列(取决于它们的格式),您可以尝试

df = pd.concat([pd.read_csv(fl, parse_dates=['Date','Time']) for fl in filelist]).drop('Date', axis=1)

【讨论】:

  • 哦,使用index_col 是个好主意,虽然我认为index_col=[0,1] 会更好。
  • 是的,好点,我也忘了如果需要你可以结合日期和时间列
【解决方案3】:

如果行和列的顺序不重要(如果是,你需要编辑你的Q来指定当文件之间的顺序不同时如何处理它!),没有冲突(相同的不同值列用于相同的日期和时间),并且数据适合内存——你更喜欢在 Python 中工作而不是在 Pandas 中工作(我注意到你没有用 pandas 标记你的 Q)——一种方法可能如下:

import collections
import csv

def merge_csvs(*filenames):
    result_dict = collections.defaultdict(dict)
    all_columns = set()
    for fn in filenames:
        with open(fn) as f:
            dr = csv.DictReader(f)
            update_cols = True
            for row in dr:
                date = row.pop('Date')
                time = row.pop('Time')
                result_dict[date, time].update(row)
                if update_cols:
                    all_columns.update(row)
                    update_cols = False
    for d in result_dict:
        missing_cols = all_columns.difference(d)
        d.update(dict.from_keys(missing_cols, '')
    return result_dict

这产生了一个字典,以(date, time) 对为键,字典的键是在任何输入 CSV 中找到的所有列,具有该日期和时间的相应值,或者如果该列则为空字符串从未找到该日期和时间。

现在你可以随心所欲地处理这个问题,例如

d = merge_csvs('a.csv', 'b.csv', 'c.csv')
for date, time in sorted(d):
    dd = d[date, time]
    outlist = [dd[c] for c in sorted(dd)]
    print(date, time, outlist)

当然,也可以将其写回不同的 CSV,等等。

【讨论】:

  • 谢谢,我会澄清更多:1)行的顺序很重要 Day1(t1, t2...tn) 然后 Day2(t1, t2...tn) 2) 顺序列数并不重要 3)我现在用熊猫标记问题,那是我的错误 然后我会运行你的答案以确保我理解它是如何工作的。谢谢。
  • 如果(date, time) 对要按升序排列,这正是for date, time in sorted(d): 在我回答末尾的sn-p 中所做的。如果以其他方式,则所述命令需要通过key= arg 到sorted,或者例如在读取CSVs 时单独记录在list 中,例如,如果想法是首先保持CSVs 中的任意顺序。请进一步编辑 Q 以准确指定行顺序必须是什么!
猜你喜欢
  • 1970-01-01
  • 2019-02-07
  • 2013-11-03
  • 2021-09-11
  • 1970-01-01
  • 2013-11-25
  • 1970-01-01
  • 2012-10-23
  • 1970-01-01
相关资源
最近更新 更多