如何使用 R 中的 powershell 删除 csv 文件中的一行?
How to delete a row in a csv file with powershell in R?
早上好,
我是 powershell 的新手,我想问问你是否有人可以帮助我。
我有一个大约 3.5gb 的大 csv 文件,我的目标是在 R 环境中用 fread(一个 data.table 函数)加载它,但是这个函数出错了。
> n_a<-fread("C:/x/xy/xyz/name_file.csv",sep=";", fill = TRUE)
错误是:
Warning message:
In fread("C:/x/xy/xyz/name_file.csv") :
Stopped early on line 458945. Expected 29 fields but found 30. Consider fill=TRUE and comment.char=. First discarded non-empty line
我试过用不同的方法(我把我的代码放在fill=true
,但没有用)来解决这个问题,但我做不到。
经过不同的研究,我发现了这种解决方案(总是在 R 中做):
>system("powershell Get-Content C:/a/b/c/file.csv | Select -Index (0..458944 + 1000000) > output.csv")
在R中使用powershell的重点是删除特定行并使用fread加载文件。
我的问题是:
如何在不指定矩阵长度的情况下删除 powershell 中 csv 中的特定行?
提前感谢您提供的各种帮助。
弗朗切斯科
这在 powershell 中很容易完成:读取通用列表中的 csv,删除行并写回:
Add-Type -AssemblyName System.Collections
[System.Collections.Generic.List[string]]$csvList = @()
$csvFile = 'C:\test\myfile.csv'
$csvList = [System.IO.File]::ReadLines( $csvFile )
$lineToDelete = 2
[void]$csvList.RemoveAt( $lineToDelete - 1 )
[System.IO.File]::WriteAllLines( $csvFile, $csvList ) | Out-Null
我猜无效行的位置未知。在这种情况下,读取原始文件并创建一个仅包含有效数据的新文件可能是明智的。更重要的是,如果源数据有利于操作,可以在将其读入 R 之前完成。
3.5 GiB 这样大的文件在内存中读取有点大。当然,它可以在 64 位系统时代完成,但对于简单的行处理来说,它很笨重。可扩展的解决方案使用 .Net 方法和逐行方法。
要逐行处理文件,请使用 .Net 方法进行高效的行读取。创建一个 StringBuilder 来存储包含有效数据的行,其他的将被丢弃。 StringBuilder 每隔一段时间就会刷新到磁盘上。即使在使用 SSD 的日子里,每行的写入操作相对于一次写入 10 000 行的大量数据来说也相对较慢。
$sb = New-Object Text.StringBuilder
$reader = [IO.File]::OpenText("MyCsvFile.csv")
$i = 0
$MaxRows = 10000
$colonCount = 30
while($null -ne ($line = $reader.ReadLine())) {
# Split the line on semicolons
$elements = $line -split ';'
# If there were $colonCount elements, add those to builder
if($elements.count -eq $colonCount) {
# If $line's contents need modifications, do it here
# before adding it into the builder
[void]$sb.AppendLine($line)
++$i
}
# Write builder contents into file every now and then
if($i -ge $MaxRows) {
add-content "MyCleanCsvFile.csv" $sb.ToString()
[void]$sb.Clear()
$i = 0
}
}
# Flush the builder after the loop if there's data
if($sb.Length -gt 0) {
add-content "MyCleanCsvFile.csv" $sb.ToString()
}
给定输入文件的大小, 提供最佳解决方案。
以下也有效,但会 慢 - 一般来说,由于使用管道的开销,而且因为 Get-Content
本身很慢用附加属性装饰每一行读取(参见 green-lighted,但尚未实现 GitHub suggestion #7537):
# Exclude line number 458945 (0-based index 458944)
Get-Content C:/a/b/c/file.csv | Select-Object -SkipIndex 458944 > output.csv
使用管道的另一面有益的是它充当了内存节流器,所以上面的命令可以用来处理任意大的文件(尽管它可能需要很长一段时间)。
早上好,
我是 powershell 的新手,我想问问你是否有人可以帮助我。
我有一个大约 3.5gb 的大 csv 文件,我的目标是在 R 环境中用 fread(一个 data.table 函数)加载它,但是这个函数出错了。
> n_a<-fread("C:/x/xy/xyz/name_file.csv",sep=";", fill = TRUE)
错误是:
Warning message:
In fread("C:/x/xy/xyz/name_file.csv") :
Stopped early on line 458945. Expected 29 fields but found 30. Consider fill=TRUE and comment.char=. First discarded non-empty line
我试过用不同的方法(我把我的代码放在fill=true
,但没有用)来解决这个问题,但我做不到。
经过不同的研究,我发现了这种解决方案(总是在 R 中做):
>system("powershell Get-Content C:/a/b/c/file.csv | Select -Index (0..458944 + 1000000) > output.csv")
在R中使用powershell的重点是删除特定行并使用fread加载文件。
我的问题是:
如何在不指定矩阵长度的情况下删除 powershell 中 csv 中的特定行?
提前感谢您提供的各种帮助。
弗朗切斯科
这在 powershell 中很容易完成:读取通用列表中的 csv,删除行并写回:
Add-Type -AssemblyName System.Collections
[System.Collections.Generic.List[string]]$csvList = @()
$csvFile = 'C:\test\myfile.csv'
$csvList = [System.IO.File]::ReadLines( $csvFile )
$lineToDelete = 2
[void]$csvList.RemoveAt( $lineToDelete - 1 )
[System.IO.File]::WriteAllLines( $csvFile, $csvList ) | Out-Null
我猜无效行的位置未知。在这种情况下,读取原始文件并创建一个仅包含有效数据的新文件可能是明智的。更重要的是,如果源数据有利于操作,可以在将其读入 R 之前完成。
3.5 GiB 这样大的文件在内存中读取有点大。当然,它可以在 64 位系统时代完成,但对于简单的行处理来说,它很笨重。可扩展的解决方案使用 .Net 方法和逐行方法。
要逐行处理文件,请使用 .Net 方法进行高效的行读取。创建一个 StringBuilder 来存储包含有效数据的行,其他的将被丢弃。 StringBuilder 每隔一段时间就会刷新到磁盘上。即使在使用 SSD 的日子里,每行的写入操作相对于一次写入 10 000 行的大量数据来说也相对较慢。
$sb = New-Object Text.StringBuilder
$reader = [IO.File]::OpenText("MyCsvFile.csv")
$i = 0
$MaxRows = 10000
$colonCount = 30
while($null -ne ($line = $reader.ReadLine())) {
# Split the line on semicolons
$elements = $line -split ';'
# If there were $colonCount elements, add those to builder
if($elements.count -eq $colonCount) {
# If $line's contents need modifications, do it here
# before adding it into the builder
[void]$sb.AppendLine($line)
++$i
}
# Write builder contents into file every now and then
if($i -ge $MaxRows) {
add-content "MyCleanCsvFile.csv" $sb.ToString()
[void]$sb.Clear()
$i = 0
}
}
# Flush the builder after the loop if there's data
if($sb.Length -gt 0) {
add-content "MyCleanCsvFile.csv" $sb.ToString()
}
以下也有效,但会 慢 - 一般来说,由于使用管道的开销,而且因为 Get-Content
本身很慢用附加属性装饰每一行读取(参见 green-lighted,但尚未实现 GitHub suggestion #7537):
# Exclude line number 458945 (0-based index 458944)
Get-Content C:/a/b/c/file.csv | Select-Object -SkipIndex 458944 > output.csv
使用管道的另一面有益的是它充当了内存节流器,所以上面的命令可以用来处理任意大的文件(尽管它可能需要很长一段时间)。