¿Leer columnas específicas de un archivo csv con módulo csv?

176

Estoy tratando de analizar un archivo csv y extraer los datos solo de columnas específicas.

Ejemplo csv:

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

Estoy tratando de capturar solamente las columnas específicas, por ejemplo ID, Name, Zipy Phone.

El código que he visto me ha llevado a creer que puedo llamar a la columna específica por su número correspondiente, por ejemplo: Namecorrespondería 2e iterar a través de cada fila usando row[2]produciría todos los elementos en la columna 2. Solo que no.

Esto es lo que he hecho hasta ahora:

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

y espero que esto imprima solo las columnas específicas que quiero para cada fila, excepto que no, solo obtengo la última columna.

frankV
fuente
1
¿Por qué 'rb'marcar open()? ¿No debería ser simple r?
Elazar
77
@Elazar: en Python 2 (que está utilizando el OP) "rb"es apropiado para pasar a csv.reader.
DSM
¿Por qué su archivo CSV de ejemplo muestra el carácter de tubería como delimitador pero su código de ejemplo usa un espacio?
Kelly S. French
1
@ KellyS.French Pensé que ayudaría a visualizar los datos a los fines de esta pregunta.
frankV

Respuestas:

187

La única forma en que obtendría la última columna de este código es si no incluye su declaración de impresión en su forbucle.

Este es probablemente el final de su código:

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

Quieres que sea esto:

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

Ahora que hemos cubierto su error, me gustaría aprovechar este tiempo para presentarle el módulo de pandas .

Pandas es espectacular para tratar con archivos csv, y el siguiente código sería todo lo que necesita para leer un csv y guardar una columna completa en una variable:

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

así que si desea guardar toda la información en su columna Namesen una variable, esto es todo lo que necesita hacer:

names = df.Names

Es un gran módulo y le sugiero que lo investigue. Si por alguna razón su declaración de impresión estaba en forbucle y todavía solo imprimía la última columna, lo que no debería suceder, pero avíseme si mi suposición fue incorrecta. Su código publicado tiene muchos errores de sangría, por lo que era difícil saber qué se suponía que debía estar dónde. ¡Espero que esto haya sido útil!

Ryan Saxe
fuente
1
¿Es posible eliminar los números de índice de la consulta? @Ryan Saxe
Malachi Bazar
Sí, solo repítelo en un bucle for.
davegallant
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'])

Con un archivo como

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

Saldrá

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

O, alternativamente, si desea indexación numérica para las columnas:

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 cambiar el deliminador agregue delimiter=" "a la instanciación apropiada, es decirreader = csv.reader(f,delimiter=" ")

HennyH
fuente
30

Usa pandas :

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

Deseche las columnas innecesarias en el momento del análisis:

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

PD: Solo estoy agregando lo que otros han dicho de una manera simple. Las respuestas reales se toman de aquí y de aquí .

VasiliNovikov
fuente
1
Creo que Pandas es una solución perfectamente aceptable. Utilizo Pandas a menudo y me gusta mucho la biblioteca, pero esta pregunta hace referencia específica al módulo CSV.
frankV
1
@frankV Bueno, el título, las etiquetas y el primer párrafo no prohíben a los pandas de ninguna manera, AFAI puede ver. De hecho, solo esperaba agregar una respuesta más simple a las que ya se hicieron aquí (otras respuestas también usan pandas).
VasiliNovikov
18

Con pandas puedes usar read_csvcon el usecolsparámetro:

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

Ejemplo:

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
fuente
16

Puedes usar numpy.loadtext(filename). Por ejemplo, si esta es su base de datos .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 |

Y quieres la Namecolumna:

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')

Más fácilmente puedes usar genfromtext:

b = np.genfromtxt(r'filepath\name.csv', delimiter='|', names=True,dtype=None)
>>> b['Name']
array([' Adam ', ' Carl ', ' Adolf ', ' Den '], 
      dtype='|S7')
GM
fuente
@G ¿Se supone que debe haber una r junto a 'filepath \ name.csv'?
114
6

Contexto: para este tipo de trabajo, debe utilizar la increíble biblioteca python petl. Eso le ahorrará mucho trabajo y la posible frustración de hacer las cosas 'manualmente' con el módulo csv estándar. AFAIK, las únicas personas que todavía usan el módulo csv son aquellas que aún no han descubierto mejores herramientas para trabajar con datos tabulares (pandas, petl, etc.), lo cual está bien, pero si planea trabajar con muchos datos en su carrera de varias fuentes extrañas, aprender algo como petl es una de las mejores inversiones que puede hacer. Para comenzar, solo debe tomar 30 minutos después de haber realizado pip install petl. La documentación es excelente.

Respuesta: Digamos que tiene la primera tabla en un archivo csv (también puede cargar directamente desde la base de datos usando petl). Entonces simplemente lo cargaría y haría lo siguiente.

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
fuente
4

Creo que hay una manera más fácil

import pandas as pd

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

Entonces aquí iloc[:, 0], :significa todos los valores, 0significa la posición de la columna. en el siguiente ejemplo IDserá seleccionado

ID | Name | Address | City | State | Zip | Phone | OPEID | IPEDS |
10 | C... | 130 W.. | Mo.. | AL... | 3.. | 334.. | 01023 | 10063 |
Nuriddin Kudratov
fuente
Si funciona chicos, por favor, voten, que otros lo sepan :)
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
fuente
pip install pandasPrimero tendrás que hacerlo
Boris
1

Gracias a la forma en que puede indexar y subconjugar un marco de datos de pandas, una forma muy fácil de extraer una sola columna de un archivo csv en una variable es:

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

Algunas cosas a considerar:

El fragmento de arriba producirá un pandas Seriesy no dataframe. La sugerencia de ayhan con usecolstambién será más rápida si la velocidad es un problema. Probar los dos enfoques diferentes usando %timeitun archivo csv de 2122 KB de tamaño produce 22.8 msel enfoque de usecols y 53 msmi enfoque sugerido.

Y no te olvides import pandas as pd

Vestland
fuente
0

Si necesita procesar las columnas por separado, me gusta desestructurar las columnas con el zip(*iterable)patrón (efectivamente "descomprimir"). Entonces, para su ejemplo:

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

Para buscar el nombre de la columna , en lugar de usar readlines () mejor use readline () para evitar bucles y leer el archivo completo y almacenarlo en la matriz.

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

    # get number of columns

    line = csvfile.readline()

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