【问题标题】:Transform CSV file into a 'flat file" for pandas将 CSV 文件转换为 pandas 的“平面文件”
【发布时间】:2020-03-06 06:02:33
【问题描述】:

我有不包含标题的 CSV 文件,每行仅包含 2 列(时间和数据名称),这些列始终包含数据,其余行的列数取决于数据。

我已成功将“普通”CSV 文件导入具有一致列数的 pandas。它工作得非常好,但我在文档中看到了处理这种当前情况的任何内容。

这是相关 CSV 文件的 sn-p

1573081480.942000, /eeg, 843.3333, 854.61536, 851.79486, 849.3773, 863.0769
1573081480.942000, /eeg, 844.1392, 857.4359, 849.3773, 861.8681, 890.07324
1573081480.943000, /eeg, 853.8095, 853.8095, 850.989, 866.30035, 854.61536
1573081480.944000, /eeg, 855.42126, 855.0183, 846.1539, 852.1978, 846.9597
1573081480.947000, /eeg, 844.1392, 853.8095, 846.55676, 842.52747, 873.5531
1573081480.947000, /eeg, 848.97437, 853.00366, 851.79486, 853.00366, 856.2271
1573081480.948000, /eeg, 859.0476, 852.6007, 850.18317, 863.8828, 826.0073
1573081480.950000, /eeg, 859.0476, 851.79486, 853.00366, 866.30035, 819.5604
1573081480.950000, /eeg, 851.79486, 852.1978, 846.9597, 854.61536, 859.45056
1573081480.951000, /eeg, 856.63007, 853.00366, 846.55676, 840.9158, 854.21246
1573081480.960000, /elements/alpha_absolute, 0.48463312
1573081480.960000, /elements/beta_absolute, 0.061746284
1573081480.961000, /elements/gamma_absolute, 0.7263172
1573081480.961000, /elements/theta_absolute, 0.7263172
1573081480.961000, /elements/delta_absolute, 0.7263172

我需要的结果是这样的

time, eeg_0, eeg_1, eeg_2, eeg_3, delta, theta, alpha, beta, gamma  
1573081480.942000, 844.1392, 857.4359, 849.3773, 861.8681,,,,,  
1573081480.947000, 844.1392, 853.8095, 846.55676, 842.52747, 873.5531,,,,,  
1573081480.947000, 848.97437, 853.00366, 851.79486, 853.00366, 856.2271,,,,,  
1573081480.948000, 859.0476, 852.6007, 850.18317, 863.8828, 826.0073,,,,,  
1573081480.960000,,,,,,,0.48463312,,  
1573081480.960000,,,,,,,,0.061746284,  
1573081480.961000,,,,,0.7263172,,,,  
1573081480.961000,,,,,0.52961296,,,  
1573081480.962000,,,,,,,,-0.26484978  

如您所见,值的数量可能会根据所存储的数据而变化。

我希望导入过程与“普通”CSV 文件一样简单高效。

这是我希望避免的,它非常冗长且效率低下:

d = {
    'time': [0.], 
    'eeg0': [0.],'eeg1': [0.],'eeg2': [0.],'eeg3': [0.],'eeg4': [0.], 
    'delta_absolute': [0.], 'theta_absolute': [0], 'alpha_absolute': [0], 'beta_absolute': [0], 'alpha_absolute': [0],
    'acc0': [0], 'acc1': [0], 'acc2': [0], 'gyro0': [0], 'gyro1': [0], 'gyro2': [0], 
    'concentration': [0],'mellow': [0] 
      }

df_new_data = pd.DataFrame(data=d)

csvfile = open(fname) 
csv_reader = csv.reader(csvfile, delimiter=',')
csv_data = list(csv_reader)
row_count = len(csv_data)

for row in csv_data:
    if row[1] == ' /muse/acc':
        df_new_data = df_new_data.append({'acc0' : row[2], 'acc1' : row[3], 'acc2' : row[4]}, ignore_index=True)
    if row[1] == ' /muse/gyro':
        df_new_data = df_new_data.append({'gyro0' : row[2], 'gyro1' : row[3], 'gyro2' : row[4]}, ignore_index=True)

编辑:

我发现如果 CSV 文件的第一行包含较少的字段,那么任何后续行 read_csv() 都会失败。上面的 CSV 数据示例有效,但这个无效:

573081480.960000, /elements/alpha_absolute, 0.48463312
1573081480.960000, /elements/beta_absolute, 0.061746284
1573081480.961000, /elements/gamma_absolute, 0.7263172
1573081480.961000, /elements/theta_absolute, 0.7263172
1573081480.961000, /elements/delta_absolute, 0.7263172
1573081480.942000, /eeg, 843.3333, 854.61536, 851.79486, 849.3773, 863.0769
1573081480.942000, /eeg, 844.1392, 857.4359, 849.3773, 861.8681, 890.07324
1573081480.943000, /eeg, 853.8095, 853.8095, 850.989, 866.30035, 854.61536
1573081480.944000, /eeg, 855.42126, 855.0183, 846.1539, 852.1978, 846.9597
1573081480.947000, /eeg, 844.1392, 853.8095, 846.55676, 842.52747, 873.5531
1573081480.947000, /eeg, 848.97437, 853.00366, 851.79486, 853.00366, 856.2271
1573081480.948000, /eeg, 859.0476, 852.6007, 850.18317, 863.8828, 826.0073
1573081480.950000, /eeg, 859.0476, 851.79486, 853.00366, 866.30035, 819.5604
1573081480.950000, /eeg, 851.79486, 852.1978, 846.9597, 854.61536, 859.45056
1573081480.951000, /eeg, 856.63007, 853.00366, 846.55676, 840.9158, 854.21246

熊猫会产生这个错误:

pandas.errors.ParserError: Error tokenizing data. C error: Expected 3 fields in line 6, saw 7

提前致谢!

【问题讨论】:

  • 您希望生成的数据结构是什么样的?某种数据框?有多少列?还有什么?
  • 我可以想象逐行读取文件,在 ',' 上拆分,将前两个元素分配给列表,并将其余元素保留为嵌套列表。换句话说,嵌套列表结构可以处理它。但是,你想从那里去哪里?您打算如何处理这些数据?
  • 我希望将其导入数据框。
  • 数据用于信号/频谱分析。到目前为止,我只需要处理平面 CSV 文件,这种格式更改让我想知道最好的方法。文件变大了,但 pandas 非常快,我真的很喜欢使用它。其他人肯定遇到过这种情况,这就是为什么我认为 pandas 或 numpy 可能已经有了解决方案。
  • 通过df = pd.read_csv('myFile.csv', header=None) 阅读。稍后您可以使用 df.columns = ['time', 'name', 'data1', 'data2', ... 'data_max'] 重命名列

标签: python pandas numpy csv


【解决方案1】:

您可以规范化 CSV,并以这种方式使用 Miller (https://github.com/johnkerl/miller) 创建一个无错误的 CSV:

mlr --csv --implicit-csv-header unsparsify \
then rename 1,one,2,two \
then reshape -r "[0-9]" -o item,value \
then filter -x -S '$value==""' \
then put '$item=fmtnum(($item-2),"%03d");$item=$two."_".$item' \
then cut -x -f two then sort -f item -n one \
then reshape -s item,value \
then unsparsify input.csv >output.csv

您将拥有这样的 CSV,您可以导入

one               /eeg_001  /eeg_002  /eeg_003  /eeg_004  /eeg_005  /elements/alpha_absolute_001 /elements/beta_absolute_001 /elements/delta_absolute_001 /elements/gamma_absolute_001 /elements/theta_absolute_001
1573081480.942000 844.1392  857.4359  849.3773  861.8681  890.07324 -                            -                           -                            -                            -
1573081480.943000 853.8095  853.8095  850.989   866.30035 854.61536 -                            -                           -                            -                            -
1573081480.944000 855.42126 855.0183  846.1539  852.1978  846.9597  -                            -                           -                            -                            -
1573081480.947000 848.97437 853.00366 851.79486 853.00366 856.2271  -                            -                           -                            -                            -
1573081480.948000 859.0476  852.6007  850.18317 863.8828  826.0073  -                            -                           -                            -                            -
1573081480.950000 851.79486 852.1978  846.9597  854.61536 859.45056 -                            -                           -                            -                            -
1573081480.951000 856.63007 853.00366 846.55676 840.9158  854.21246 -                            -                           -                            -                            -
1573081480.960000 -         -         -         -         -         0.48463312                   0.061746284                 -                            -                            -
1573081480.961000 -         -         -         -         -         -                            -                           0.7263172                    0.7263172                    0.7263172

【讨论】:

  • 这是一个非常有用的工具!但是,我不确定我是否清楚。以下是结果应该是什么样子的示例:
  • time, eeg_0, eeg_1, eeg_2, eeg_3, delta, theta, alpha, beta, gamma 1573081480.942000, 844.1392, 857.4359, 849.3773, 861.8681,,,,, 1573081480.947000, 844.1392, 853.8095, 846.55676, 842.52747, 873.5531,,,,, 1573081480.947000, 848.97437, 853.00366, 851.79486, 853.00366, 856.2271,,,,, 1573081480.948000, 859.0476, 852.6007, 850.18317, 863.8828, 826.0073,,,,, 1573081480.960000,,,,,,,0.48463312,, 1573081480.960000,,,,,,,,0.061746284, 1573081480.961000,,,,,0.7263172,,,, 1573081480.961000,,,,,0.52961296,,, 1573081480.962000,,,,,,,,-0.26484978
  • @DebraGracePeri 您可以编辑您的问题并在其中添加所需的输出吗?
  • 是的,谢谢,我刚刚做到了!我是 stackoverflow 的新手,正在学习格式化问题/答案的方法。
  • 您好,是的,我确实尝试过,但不幸的是它非常慢。我指的是使用pandas方法,速度更快,更适合大数据集。
【解决方案2】:

不清楚你到底想要什么。很好,您提供了一个示例输出,但如果它是您输入的预期输出,那就容易多了。

当我理解时,最简单的方法是循环每种类型,找到它们使用的列数,创建许多帧,最后连接它们。像这样:

# Using pandas:
max_number_of_columns = pandas.read_csv('test.txt', sep='|', header=None)[0].str.count(',').max()
# or just hardcoded:
max_number_of_columns = 10

base = pandas.read_csv('test.txt', header=None, names=list(range(max_number_of_columns)))
base.columns =  ['time','datatype'] + list(base.columns[2:])

results = [base.iloc[:,:2]]
for datatype in base['datatype'].unique():
    group = base[base['datatype']==datatype].iloc[:,2:].dropna(how='all', axis=1) 
    group.columns = [f"{datatype}_{x}" for x in range(len(group.columns))]
    results.append(group)

final = pandas.concat(results, axis=1)

编辑:当第一行包含的列少于后面的行时修复。

【讨论】:

  • pandas 在使用 pandas.read_csv() 读取 CSV 文件时失败。回溯(最后一次调用): pandas._libs.parsers.TextReader._read_rows 文件“pandas/_libs/parsers.pyx”,第 937 行,在 pandas._libs.parsers.TextReader._tokenize_rows 文件“pandas/_libs/ parser.pyx”,第 2132 行,在 pandas._libs.parsers.raise_parser_error pandas.errors.ParserError:错误标记数据。 C 错误:预计第 3 行中有 5 个字段,看到 7
  • 如果您将上面的示例数据粘贴到一个文本文件中并尝试解析它,这对您有用吗?
  • 是的,但我发现 pandas read_csv() 方法存在问题。如果第一行中的字段数小于后续行,则 pandas 会失败。我不知道如何将代码/文件数据添加到 cmets,所以我将添加到答案列表中。 (对不起,我是stackoverflow的新手)
  • 天啊!我认为这行得通!而且它比我编写的代码要快得多。我真的很喜欢熊猫。我很确定这是修复程序,需要再测试一下。非常感谢!
猜你喜欢
  • 1970-01-01
  • 2019-10-28
  • 2013-01-08
  • 2018-09-14
  • 2022-01-25
  • 1970-01-01
  • 2011-05-27
  • 1970-01-01
  • 2021-01-31
相关资源
最近更新 更多