我有几个.txt
文件,每个文件有 3000 多万行,并且有 20 到 40 个“列”(有些用逗号分隔,有些用空格分隔,所有 ASCII 行都用换行符分隔)。我不需要所有(甚至大多数)列,其中一些列有用 填充的空空格NULL
。
我的目标是:
- 删除我不需要的列
- 按我认为合适的方式重新排列列(为了便于阅读)
- 通过管道将输出传输到另一个 .txt 文件,其中各列以冒号分隔
我刚刚对一个大型文本文件进行了此操作,将其拆分为约 40 个.txt
文件,每个文件有 1,000,000 行,将它们逐个导入 Excel,然后使用 CONCATENATE,但这种方法对我的下一个目标没有任何效果。该文件以逗号分隔,但仍需要从 转换为.txt
,.csv
并且 Excel 在导入过程中会卡住;即使我将其放入 Excel,主文件也会分解为 200 多个较小的文件以符合 Excel 的上限,并且执行同样的事情超过 200 次效率不高。
我正在研究 2020 年末的 MacBook Pro,对任何编码语言都不够熟悉,甚至不知道从哪里开始,但我对使用 shell 编写脚本很熟悉,并且总是想学习新的技巧,只是不知道从哪里开始。
答案1
选择您的工具
Excel 似乎不是适合您要执行的操作的工具。
一种方法是使用不同的工具来合并或汇总数据。、、或者awk
可能sed
更适合这种初步处理,并创建一个较小的 CSV 文件,然后可以在 Excel 或其他工具中进行处理。grep
perl
还有其他工具可能更适合完成整个工作。可能是 R 或 DBMS 之类的东西。这取决于你想用数据做什么。
如果只是获取一堆不同的文本文件并重新排序和选择列,我会立即跳转到perl
。其他人会使用awk
。
awk
由于和等工具perl
可以逐行处理文件,不需要将所有内容存储在内存中,因此它们可以处理其他工具无法处理的大型文件。而且它们的速度也快得惊人。
只是为了好玩,举个例子
有了这个数据
Apples,27,500,10.2,fruit,100,200,300
Chairs 1 501 123.78 furniture 101 201 301
Europe, 655, 502,0.0001,continent, 102, 202,302
我们可以产生这个输出
fruit:Apples:10.2
furniture:Chairs:123.78
continent:Europe:0.0001
使用此命令
perl -l -n -e "print join(':',(split(/[, \t] */))[4,0,3])" *.txt
解释
元素 | 它能做什么 |
---|---|
-l |
每次打印后添加换行符 |
-n |
逐行处理但不隐式打印 |
-e |
接下来是要执行的程序 |
print |
打印以下表达式的结果 |
join(":" 列表) |
从列表中创建一个字符串,每个字符串之间使用“:” |
split (/ 表达式/) |
使用表达式将行划分为字段 |
[, \t] |
逗号、空格或制表符后跟 |
* (空格星号) |
0、1 或多个空格 |
( 列表)[4,0,3] |
从列表中选择第 4、第 0 和第 3 个项目 |
该行程序相当于下面的程序,可能更容易理解
#!perl
use warnings;
use strict;
while(<>) { # read line by line all input or all listed files
my @columns = split(/[, \t] */); # split on whitespace or commas
my @chosen = @columns[4,0,3]; # choose what to keep
my $new_line = join(":", @chosen); # join items using colons between
print "$new_line\n"; # print with line-separator
}
调用为perl data.pl *.txt > newdata.txt
我喜欢perl
并且对它的一个子集相当熟悉,尽管它的受欢迎程度正在下降,部分原因是它很容易编写perl
难以阅读的程序。然而,它正是为您的用例而设计的。任何熟悉awk
、python
或ruby
大量工具中的任何一个的人都可以轻松解决这个问题。
答案2
与操作系统无关的答案:
只需学习一点点 Python,您就会拥有一个工具来以任何您希望的方式进行类似的转换。
将其输入到文件中,保存为例如cvt.py
(最初基于来自的代码这里)
导入系统 导出列 = [3, 4, 5] 使用 open(sys.argv[1], 'r') 作为 fi: 对于 fi 中的行: 列 = 行.拆分(',') 打印('\t'.join(columns[col] for col in exportcolumns))
安装 Python(版本 3,没有其他!)后,您应该能够通过以下方式运行上述操作,
Python3 cvt.py filename >newfile
其中 filename 是您的数据文件之一,newfile 是您想要结果的位置。
正如所写,代码寻找,
列分隔符,输出第 3、4、5 列(按此顺序),并使用制表符\t
作为分隔符(在每列的末尾)。
如果你有更复杂(不一致)的列分隔,你可能会这样做
import re
...如下所示:https://stackoverflow.com/a/4998688/3720510
以上内容的简要解释
- 第一行使
sys
模块可用。这允许使用sys.argv
此处;使命令行参数作为简单列表提供给脚本。 - 第二行创建一个列表,其中包含要从输入数据中提取的列的索引。
- with 行打开文件并使其在以下缩进块期间可用 - 文件在执行完该块后关闭。
- for-对从文件中读取的每一行循环一次。
- 下一行;创建一行内容的列表,每行拆分一次
,
。 - 打印;使用“列表理解”从列表中选择列,用
\t
(制表符)连接它们,然后将它们打印到sys.stdout
(隐含 print()),它可能是一个文件 - 如果您>
在命令行上使用重定向。
答案3
免责声明:我实际上没有尝试过使用 70 GB 的文件,但我已经处理了几 GB 和超过 400 万行的文件。
大文件的预期工作流程不是将整个文件加载到工作表中,而是连接到该文件。
打开数据选项卡,选择“来自文本/CSV”,选择您的文件。预览对话框出现时,单击“加载”按钮旁边的插入符号,然后选择“仅创建连接”。就是这样。这里有一个更详细的教程:https://excel.officetuts.net/en/examples/open-large-csv
列转换可能会遇到一些问题和更多挑战,但如果您对 Excel 的使用感觉比使用命令行工具好得多,那么值得尝试一下。
另一个选择是——如果您可以访问 Access,您也可以在那里导入和处理数据。该软件是高级用户的数据库系统。
话虽如此,我还是会选择 awk 来完成这项任务。不过你至少应该对 shell 有点熟悉了。
答案4
关于数据提取机制,其他地方有很多好的建议,但是您需要一些肮脏的编码技巧才能用它做任何有用的事情。
大型数据集通常包含损坏的行、循环数据、奇怪的字符、用“哦”代替“零”以及各种格式错误。您需要验证和过滤您所得到的内容。(例如,将文件拆分成两个,然后将它们合并。在合并时可能会出现最微妙的缺陷。可能所有正常的行都是 CRLF,但在合并时,行尾只是 CR。这可能会被忽视,甚至导致读入假定文件结束!)至少我会确保您输出的行数与您读取的行数完全相同。
仍然逐行处理,对数据添加非常基本的完整性检查非常简单且值得。即使某个字段没有输出,如果很容易检查,那么就检查一下,因为它可能表明存在一些更微妙的问题。请注意,实际数据可能不符合官方规范。为什么有时会出现 -1 的价格?一个特别有用的检查字段是最后一个应该始终包含内容的字段或每行中的最后一个字段。
在某处记录处理。这样,您就可以让进程运行并去吃午饭了。您有一份记录,记录了使用哪个版本的程序来创建哪些输出。当然,您一直在寻找“...lines denied:0”。
错误的源代码行应输出到失败文件。(但在 15 行之后退出。)您可以目视检查少量数据,看看您遇到了什么样的怪异情况。
很可能在处理每一行的循环中,您必须应用过滤器。这可能不会在第一次传递时发生,但随着下游分析的进展,您可能会被要求提供更精选的数据集。例如,排除名称中带有“test”或产品代码以 9 开头的产品行。
一个经常被忽略的验证问题是数据缺失或重复。例如,不知何故,周五的原始数据被添加到了周四数据的末尾,而周五的数据是前一周的。怎么会有人知道呢?网络从下午 3 点到 5 点出现故障,因此没有任何记录。周一是银行休假日,不应该有任何交易,但有人提供了上周一的数据。您可以做一些简单的总结,例如每日营业额或最长无活动时间等。这些是批量健全性检查,用于在有毒数据进一步传递到链条之前让人们停下来思考并提示检查。决定如何处理循环批次可能不是您的工作,但您可以突出显示它并调整代码以提供更好的数据集。
以上所有内容都是“简单”的,一步一步编程。您将了解自动化、整洁的工作流程、循环格式和基本数据异常。您还将成为发现异常数据和字段含义方面的专家。这对...很有用。
利用数据做一些有用的事情。您应该参与下游分析。这并不是说您应该在翻译程序中构建分析,但您已经准备好了一个框架来做这件事。总计、平均值、最大值和最小值、每小时、每天、每周都是可能简单的(NB 自动化)输出。您可能认为数据库是更好的工具,但对于繁琐的事情,简单的编码可能更好。让我举个例子:平滑一组数据点。一个简单的移动平均值是 nextPoint = (lastPoint *(0.8)) + (rawValue *(0.2)) [调整 .8 和 .2 以适应]。这对于连续数据来说很好,但每天开始营业怎么办?这是一个特殊情况,其中 nextPoint = rawValue。也许需要编码。
虚假数据值是原始数据处理和分析交叉的一个很好的例子。当有人输入 175 英镑而他们实际上想要 1.75 英镑时,我们真的想将其包括在我们的分析中吗?这有点像艺术,或者说是捏造,但原始数据处理器可以轻松计算出几千个数据点的平均值和标准差,或所有数据行的实际分布。您可能想要在数据处理阶段丢弃、标记、突出显示或以其他方式引起对意外值的注意,或者使用它来通知分析阶段。也许可以添加另一列,其中空白表示 OK,而“H”表示高于预期,等等。
您将成为一名熟练的工匠,能够从头到尾将一棵大树变成有用的木板。您将了解谁想要什么样的木板用于什么目的,并能够以正确的方式锯切原木以避免裂缝和摇晃。此外,如果您发现一棵病树,您可以发出警报。