如何在CSV文件中删除列?

48

我已经能够使用这个网站上其他用户的输入,用 Python 创建了一个 csv 文件,并对此表示感谢。现在我遇到了难题,并将发布我的第一个问题。

我的 input.csv 文件长这样:

day,month,year,lat,long
01,04,2001,45.00,120.00
02,04,2003,44.00,118.00

我想删除"year"列及其所有项。总共有40多个条目,年份范围从1960-2010年不等。


7
这是一个适合使用awk的问题:$ awk -F, 'BEGIN {OFS=","} {print $1,$2,$4,$5}' ex.csv。其中awk可以很好地处理这种问题,该命令将以逗号作为分隔符,选取CSV文件中第一、二、四、五列,并输出到标准输出流中。 - Eric Wilson
@Eric Wilson:幸运的是,这个CSV文件没有引号,可以让AWK工作。 - S.Lott
@S.Lott 我同意,当CSV格式变得更加复杂时,Python的csv是最好的选择。我只在明显可行且只有一行时才使用awk - Eric Wilson
12个回答

63
import csv
with open("source","rb") as source:
    rdr= csv.reader( source )
    with open("result","wb") as result:
        wtr= csv.writer( result )
        for r in rdr:
            wtr.writerow( (r[0], r[1], r[3], r[4]) )

顺便提一下,for 循环可以被移除,但并不会真正简化代码。

        in_iter= ( (r[0], r[1], r[3], r[4]) for r in rdr )
        wtr.writerows( in_iter )

另外,您可以以超字面的方式坚持删除列的要求。我认为这通常是一个不好的策略,因为它不适用于删除多列。当您尝试删除第二列时,您会发现位置已经全部移动,结果行并不明显。但对于仅有一列的情况,这是可行的。

            del r[2]
            wtr.writerow( r )

1
这个几乎完美地工作了,出现了有关语法的错误。应该从wtr=csv.writer(result)中删除冒号。感谢您对此的建议,它很有帮助,而且因为它适用于我可能需要删除的任意列,所以也非常方便。 - Jeff
5
您可以轻松地使用第二种方法来处理多列数据,只需先删除最高的列,例如: 'del r[8] del r[6] del r[2] wtr.writerow(r)' - Satvik Beri
你可以通过将(r[0], r[1], r[3], r[4])替换为类似于tuple(r[ii] for ii in range(len(r)) if ii != 2)的内容来为更大的CSV文件节省一些编写时间。 - srcerer
要删除最后一个点中的多个列,难道你不能只使用经典的向后删除方法吗? - bobobobo

52

使用Pandas模块会更加容易。

import pandas as pd
f=pd.read_csv("test.csv")
keep_col = ['day','month','lat','long']
new_f = f[keep_col]
new_f.to_csv("newFile.csv", index=False)

这里有个简短的解释:

>>>f=pd.read_csv("test.csv")
>>> f
   day  month  year  lat  long
0    1      4  2001   45   120
1    2      4  2003   44   118
>>> keep_col = ['day','month','lat','long'] 
>>> f[keep_col]
    day  month  lat  long
0    1      4   45   120
1    2      4   44   118
>>>

1
即使您的 CSV 文件中的字符串在行中有换行符,这也可以正常工作 - 许多其他 Linux 命令(如“cut”)在行字段包含 CSV 内容的换行符时无法删除列并保持数据完整性。 - technogeek1995
1
在我的情况下,整数被转换为浮点数。 - Gunarathinam
@Gunarathinam,您可以通过在read_csv中传递dtype=str来防止这种情况在较新的pandas版本中发生。 - ntjess

6
使用字典抓取标题,然后循环遍历可以让您干净地获得所需内容。
import csv
ct = 0
cols_i_want = {'cost' : -1, 'date' : -1}
with open("file1.csv","rb") as source:
    rdr = csv.reader( source )
    with open("result","wb") as result:
        wtr = csv.writer( result )
        for row in rdr:
            if ct == 0:
              cc = 0
              for col in row:
                for ciw in cols_i_want: 
                  if col == ciw:
                    cols_i_want[ciw] = cc
                cc += 1
            wtr.writerow( (row[cols_i_want['cost']], row[cols_i_want['date']]) )
            ct += 1

6
我会使用Pandas和列号
f = pd.read_csv("test.csv", usecols=[0,1,3,4])
f.to_csv("test.csv", index=False)

3
您可以直接使用以下方法删除该列:
del variable_name['year']

对我不起作用。它说它需要一个整数,因为它期望一个索引。 - ZekeC

2

您可以使用csv包遍历CSV文件并将所需的列输出到另一个CSV文件中。

下面的示例未经过测试,但应该说明了解决方案:

import csv

file_name = 'C:\Temp\my_file.csv'
output_file = 'C:\Temp\new_file.csv'
csv_file = open(file_name, 'r')
## note that the index of the year column is excluded
column_indices = [0,1,3,4]
with open(output_file, 'w') as fh:
    reader = csv.reader(csv_file, delimiter=',')
    for row in reader:
       tmp_row = []
       for col_inx in column_indices:
           tmp_row.append(row[col_inx])
       fh.write(','.join(tmp_row))

2
放弃使用 tmp_rowjoin,改用 csv.writer 和生成器表达式:for row in reader: wtr.writerow(row[i] for i in column_indices)。这样更安全(自动处理引号),更简洁,更快。 - Steven Rumbalski
1
为什么不也使用 csv 进行写入呢? - S.Lott

2

凭借我个人的经验,这样做可以完成任务,但是没有任何错误检查或配置能力。这些都需要读者自行处理。

outFile = open( 'newFile', 'w' )
for line in open( 'oldFile' ):
   items = line.split( ',' )
   outFile.write( ','.join( items[:2] + items[ 3: ] ) )
outFile.close()

2

我将为这个问题添加另一个答案。由于OP没有说明他们需要使用Python来完成,所以最快的删除列的方法(特别是当输入文件有成千上万行时),是使用awk

这是awk发挥作用的类型问题:

$ awk -F, 'BEGIN {OFS=","} {print $1,$2,$4,$5}' input.csv

如果需要将输出保存到文件中,可以在上述命令后面添加> output.csv

所有的荣誉归功于@eric-wilson,他在10年前作为对原问题的评论提供了这个非常棒的答案,几乎没有得到任何认可。


1
尝试:

result= data.drop('year', 1)
result.head(5)

0
这取决于您如何存储解析的CSV,但通常您需要使用del操作符。
如果您有一个字典数组:
input = [ {'day':01, 'month':04, 'year':2001, ...}, ... ]
for E in input: del E['year']

如果您有一个数组的数组:
input = [ [01, 04, 2001, ...],
          [...],
          ...
        ]
for E in input: del E[2]

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接