Leia colunas específicas de um arquivo CSV com o módulo CSV?

176

Estou tentando analisar através de um arquivo csv e extrair os dados de apenas colunas específicas.

Exemplo csv:

ID | Name | Address | City | State | Zip | Phone | OPEID | IPEDS |
10 | C... | 130 W.. | Mo.. | AL... | 3.. | 334.. | 01023 | 10063 |

Eu estou tentando capturar apenas colunas específicas, dizem ID, Name, Zipe Phone.

O código que eu observei me levou a acreditar que posso chamar a coluna específica pelo seu número correspondente, ou seja: Namecorresponderia 2e iteraria através de cada linha usando row[2]produziria todos os itens da coluna 2. Só que não.

Aqui está o que eu fiz até agora:

import sys, argparse, csv
from settings import *

# command arguments
parser = argparse.ArgumentParser(description='csv to postgres',\
 fromfile_prefix_chars="@" )
parser.add_argument('file', help='csv file to import', action='store')
args = parser.parse_args()
csv_file = args.file

# open csv file
with open(csv_file, 'rb') as csvfile:

    # get number of columns
    for line in csvfile.readlines():
        array = line.split(',')
        first_item = array[0]

    num_columns = len(array)
    csvfile.seek(0)

    reader = csv.reader(csvfile, delimiter=' ')
        included_cols = [1, 2, 6, 7]

    for row in reader:
            content = list(row[i] for i in included_cols)
            print content

e espero que isso imprima apenas as colunas específicas que quero para cada linha, exceto que não, recebo apenas a última coluna.

frankV
fonte
1
por que 'rb'sinalizar para open()? não deveria ser simples r?
Elazar
7
@ Elazar: no Python 2 (que o OP está usando) "rb"é apropriado para a passagem csv.reader.
DSM
Por que seu arquivo CSV de exemplo mostra o caractere de pipe como delimitador, mas seu código de exemplo usa um espaço?
Kelly S. French
1
@ KellyS.French Eu pensei que ajudaria a visualizar os dados para os fins desta pergunta.
precisa saber é

Respostas:

187

A única maneira de obter a última coluna desse código é se você não incluir sua declaração de impressão em seu forloop.

Provavelmente, este é o fim do seu código:

for row in reader:
    content = list(row[i] for i in included_cols)
print content

Você quer que seja assim:

for row in reader:
        content = list(row[i] for i in included_cols)
        print content

Agora que cobrimos seu erro, gostaria de apresentar esse módulo ao pandas .

O Pandas é espetacular para lidar com arquivos csv, e o código a seguir seria tudo o que você precisa para ler um csv e salvar uma coluna inteira em uma variável:

import pandas as pd
df = pd.read_csv(csv_file)
saved_column = df.column_name #you can also use df['column_name']

portanto, se você deseja salvar todas as informações da sua coluna Namesem uma variável, é tudo o que você precisa fazer:

names = df.Names

É um ótimo módulo e sugiro que você o analise. Se, por algum motivo, sua declaração de impressão estava em forloop e ainda estava imprimindo apenas a última coluna, o que não deveria acontecer, mas deixe-me saber se minha suposição estava errada. Seu código postado possui muitos erros de recuo, portanto, era difícil saber o que deveria estar onde. Espero que isso tenha sido útil!

Ryan Saxe
fonte
1
É possível remover os números de índice da consulta? @Ryan Saxe
Malachi Bazar
Sim, apenas itere-o em um loop for.
Davegallant 07/07
109
import csv
from collections import defaultdict

columns = defaultdict(list) # each value in each column is appended to a list

with open('file.txt') as f:
    reader = csv.DictReader(f) # read rows into a dictionary format
    for row in reader: # read a row as {column1: value1, column2: value2,...}
        for (k,v) in row.items(): # go over each column name and value 
            columns[k].append(v) # append the value into the appropriate list
                                 # based on column name k

print(columns['name'])
print(columns['phone'])
print(columns['street'])

Com um arquivo como

name,phone,street
Bob,0893,32 Silly
James,000,400 McHilly
Smithers,4442,23 Looped St.

Saída

>>> 
['Bob', 'James', 'Smithers']
['0893', '000', '4442']
['32 Silly', '400 McHilly', '23 Looped St.']

Ou, como alternativa, se você deseja indexação numérica para as colunas:

with open('file.txt') as f:
    reader = csv.reader(f)
    reader.next()
    for row in reader:
        for (i,v) in enumerate(row):
            columns[i].append(v)
print(columns[0])

>>> 
['Bob', 'James', 'Smithers']

Para alterar o deliminador, adicione delimiter=" "à instanciação apropriada, ou seja,reader = csv.reader(f,delimiter=" ")

HennyH
fonte
30

Use pandas :

import pandas as pd
my_csv = pd.read_csv(filename)
column = my_csv.column_name
# you can also use my_csv['column_name']

Descartar colunas desnecessárias no momento da análise:

my_filtered_csv = pd.read_csv(filename, usecols=['col1', 'col3', 'col7'])

PS: Estou apenas agregando o que os outros disseram de uma maneira simples. As respostas reais são obtidas aqui e aqui .

VasiliNovikov
fonte
1
Eu acho que o Pandas é uma solução perfeitamente aceitável. Eu uso o Pandas frequentemente e realmente gosto da biblioteca, mas essa pergunta referenciou especificamente o módulo CSV.
FrankV 23/05
1
@frankV Bem, o título, as tags e o primeiro parágrafo não proíbem pandas de forma alguma, a AFAI pode ver. Na verdade, eu apenas esperava adicionar uma resposta mais simples às já feitas aqui (outras respostas também usam pandas).
VasiliNovikov
18

Com os pandas você pode usar read_csvcom o usecolsparâmetro:

df = pd.read_csv(filename, usecols=['col1', 'col3', 'col7'])

Exemplo:

import pandas as pd
import io

s = '''
total_bill,tip,sex,smoker,day,time,size
16.99,1.01,Female,No,Sun,Dinner,2
10.34,1.66,Male,No,Sun,Dinner,3
21.01,3.5,Male,No,Sun,Dinner,3
'''

df = pd.read_csv(io.StringIO(s), usecols=['total_bill', 'day', 'size'])
print(df)

   total_bill  day  size
0       16.99  Sun     2
1       10.34  Sun     3
2       21.01  Sun     3
ayhan
fonte
16

Você pode usar numpy.loadtext(filename). Por exemplo, se este é seu banco de dados .csv:

ID | Name | Address | City | State | Zip | Phone | OPEID | IPEDS |
10 | Adam | 130 W.. | Mo.. | AL... | 3.. | 334.. | 01023 | 10063 |
10 | Carl | 130 W.. | Mo.. | AL... | 3.. | 334.. | 01023 | 10063 |
10 | Adolf | 130 W.. | Mo.. | AL... | 3.. | 334.. | 01023 | 10063 |
10 | Den | 130 W.. | Mo.. | AL... | 3.. | 334.. | 01023 | 10063 |

E você quer a Namecoluna:

import numpy as np 
b=np.loadtxt(r'filepath\name.csv',dtype=str,delimiter='|',skiprows=1,usecols=(1,))

>>> b
array([' Adam ', ' Carl ', ' Adolf ', ' Den '], 
      dtype='|S7')

Mais facilmente você pode usar genfromtext:

b = np.genfromtxt(r'filepath\name.csv', delimiter='|', names=True,dtype=None)
>>> b['Name']
array([' Adam ', ' Carl ', ' Adolf ', ' Den '], 
      dtype='|S7')
GM
fonte
@G Existe um r ao lado de 'filepath \ name.csv'?
114
6

Contexto: Para esse tipo de trabalho, você deve usar a incrível biblioteca python petl. Isso poupará muito trabalho e potencial frustração de fazer as coisas 'manualmente' com o módulo csv padrão. AFAIK, as únicas pessoas que ainda usam o módulo csv são aquelas que ainda não descobriram ferramentas melhores para trabalhar com dados tabulares (pandas, petl etc.), o que é bom, mas se você planeja trabalhar com muitos dados em sua carreira de várias fontes estranhas, aprender algo como petl é um dos melhores investimentos que você pode fazer. Para começar, demore apenas 30 minutos depois de concluir o pip install petl. A documentação é excelente.

Resposta: Digamos que você tenha a primeira tabela em um arquivo csv (você também pode carregar diretamente do banco de dados usando petl). Então você simplesmente carregaria e faria o seguinte.

from petl import fromcsv, look, cut, tocsv 

#Load the table
table1 = fromcsv('table1.csv')
# Alter the colums
table2 = cut(table1, 'Song_Name','Artist_ID')
#have a quick look to make sure things are ok. Prints a nicely formatted table to your console
print look(table2)
# Save to new file
tocsv(table2, 'new.csv')
PeteBeat
fonte
4

Eu acho que existe uma maneira mais fácil

import pandas as pd

dataset = pd.read_csv('table1.csv')
ftCol = dataset.iloc[:, 0].values

Então aqui iloc[:, 0], :significa todos os valores, 0significa a posição da coluna. no exemplo abaixo IDserá selecionado

ID | Name | Address | City | State | Zip | Phone | OPEID | IPEDS |
10 | C... | 130 W.. | Mo.. | AL... | 3.. | 334.. | 01023 | 10063 |
Nuriddin Kudratov
fonte
Se funcionar pessoal, por favor, avise, deixe que os outros saibam :)
Nuriddin Kudratov
3
import pandas as pd 
csv_file = pd.read_csv("file.csv") 
column_val_list = csv_file.column_name._ndarray_values
Hari K
fonte
Você terá que pip install pandasprimeiro
Boris
1

Graças à maneira como você pode indexar e agrupar um dataframe do pandas, uma maneira muito fácil de extrair uma única coluna de um arquivo csv para uma variável é:

myVar = pd.read_csv('YourPath', sep = ",")['ColumnName']

Algumas coisas a considerar:

O trecho acima produzirá pandas Seriese não dataframe. A sugestão de ayhan with usecolstambém será mais rápida se a velocidade for um problema. Testar as duas abordagens diferentes usando %timeitum arquivo CSV de 2122 KB de tamanho gera 22.8 msa abordagem usecols e 53 msa minha abordagem sugerida.

E não esqueça import pandas as pd

Vestland
fonte
0

Se você precisar processar as colunas separadamente, eu gostaria de desestruturar as colunas com o zip(*iterable)padrão (efetivamente "descompacte"). Então, para o seu exemplo:

ids, names, zips, phones = zip(*(
  (row[1], row[2], row[6], row[7])
  for row in reader
))
Robert Jensen
fonte
-1

Para buscar o nome da coluna , em vez de usar readlines (), use readline () para evitar loop e ler o arquivo completo e armazená-lo na matriz.

with open(csv_file, 'rb') as csvfile:

    # get number of columns

    line = csvfile.readline()

    first_item = line.split(',')
Suren
fonte