Lire des colonnes spécifiques à partir d'un fichier csv avec le module csv?

176

J'essaie d'analyser un fichier csv et d'extraire les données de colonnes spécifiques uniquement.

Exemple csv:

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

Je suis en train de saisir uniquement des colonnes spécifiques, par exemple ID, Name, ZipetPhone .

Le code que j'ai regardé m'a amené à croire que je peux appeler la colonne spécifique par son numéro correspondant, donc c'est-à-dire: Namecorrespondrait à2 et itérer à travers chaque ligne en utilisant row[2]produirait tous les éléments de la colonne 2. Seulement, ce n'est pas le cas.

Voici ce que j'ai fait jusqu'à présent:

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

et je m'attends à ce que cela n'imprime que les colonnes spécifiques que je veux pour chaque ligne sauf que ce n'est pas le cas, je reçois la dernière colonne uniquement.

frankV
la source
1
pourquoi 'rb'signaler open()? ne devrait-il pas être simple r?
Elazar
7
@Elazar: en Python 2 (que l'OP utilise) "rb"est approprié pour le passage csv.reader.
DSM
Pourquoi votre exemple de fichier CSV affiche-t-il le caractère pipe comme délimiteur mais votre exemple de code utilise un espace?
Kelly
1
@ KellyS.French J'ai pensé que cela aiderait à visualiser les données aux fins de cette question.
frankV

Réponses:

187

La seule façon d'obtenir la dernière colonne de ce code est de ne pas inclure votre instruction d'impression dans votre forboucle.

C'est probablement la fin de votre code:

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

Vous voulez que ce soit ceci:

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

Maintenant que nous avons couvert votre erreur, j'aimerais profiter de ce temps pour vous présenter le module pandas .

Pandas est spectaculaire pour traiter les fichiers csv, et le code suivant serait tout ce dont vous avez besoin pour lire un csv et enregistrer une colonne entière dans une variable:

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

donc si vous souhaitez enregistrer toutes les informations de votre colonne Namesdans une variable, c'est tout ce que vous devez faire:

names = df.Names

C'est un excellent module et je vous suggère de l'examiner. Si pour une raison quelconque votre instruction d'impression était en forboucle et qu'elle n'imprimait toujours que la dernière colonne, ce qui ne devrait pas arriver, mais faites-moi savoir si mon hypothèse était erronée. Votre code publié contient beaucoup d'erreurs d'indentation, il était donc difficile de savoir ce qui était censé être où. J'espère que cela a été utile!

Ryan Saxe
la source
1
Est-il possible de supprimer les numéros d'index de la requête? @Ryan Saxe
Malachi Bazar
Oui, parcourez-le simplement dans une boucle 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'])

Avec un fichier comme

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

Sortira

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

Ou bien si vous souhaitez une indexation numérique des colonnes:

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

Pour changer le déliminateur, ajoutez delimiter=" "à l'instanciation appropriée, c'est-à-direreader = csv.reader(f,delimiter=" ")

HennyH
la source
30

Utilisez des pandas :

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

Supprimer les colonnes inutiles au moment de l'analyse:

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

PS Je ne fais qu'agréger ce que les autres ont dit d'une manière simple. Les réponses réelles sont tirées d' ici et d' ici .

VasiliNovikov
la source
1
Je pense que Pandas est une solution parfaitement acceptable. J'utilise souvent Pandas et j'aime beaucoup la bibliothèque, mais cette question faisait spécifiquement référence au module CSV.
frankV
1
@frankV Eh bien, le titre, les balises et le premier paragraphe n'interdisent en aucun cas les pandas, AFAI peut le voir. J'espérais simplement ajouter une réponse plus simple à celles déjà faites ici (d'autres réponses utilisent aussi des pandas).
VasiliNovikov
18

Avec les pandas, vous pouvez utiliser read_csvavec le usecolsparamètre:

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

Exemple:

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
la source
16

Vous pouvez utiliser numpy.loadtext(filename). Par exemple, s'il s'agit de votre base de données .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 |

Et vous voulez la Namecolonne:

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

Plus facilement, vous pouvez utiliser genfromtext:

b = np.genfromtxt(r'filepath\name.csv', delimiter='|', names=True,dtype=None)
>>> b['Name']
array([' Adam ', ' Carl ', ' Adolf ', ' Den '], 
      dtype='|S7')
GM
la source
@G Est-il censé y avoir un r à côté de 'filepath \ name.csv'?
114 du
6

Contexte: Pour ce type de travail, vous devez utiliser l'incroyable bibliothèque petl python. Cela vous évitera beaucoup de travail et de frustration potentielle en faisant les choses «manuellement» avec le module csv standard. AFAIK, les seules personnes qui utilisent encore le module csv sont celles qui n'ont pas encore découvert de meilleurs outils pour travailler avec des données tabulaires (pandas, petl, etc.), ce qui est bien, mais si vous prévoyez de travailler avec beaucoup de données en votre carrière à partir de diverses sources étranges, apprendre quelque chose comme Petl est l'un des meilleurs investissements que vous puissiez faire. Pour commencer, cela ne devrait prendre que 30 minutes après avoir terminé l'installation de pip petl. La documentation est excellente.

Réponse: Disons que vous avez la première table dans un fichier csv (vous pouvez également charger directement à partir de la base de données en utilisant petl). Ensuite, vous le chargez simplement et procédez comme suit.

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
la source
4

Je pense qu'il existe un moyen plus simple

import pandas as pd

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

Donc ici iloc[:, 0], :signifie toutes les valeurs, 0signifie la position de la colonne. dans l'exemple ci ID- dessous sera sélectionné

ID | Name | Address | City | State | Zip | Phone | OPEID | IPEDS |
10 | C... | 130 W.. | Mo.. | AL... | 3.. | 334.. | 01023 | 10063 |
Nuriddin Kudratov
la source
Si cela fonctionne les gars, veuillez voter pour, faites-le savoir aux autres :)
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
la source
Vous devrez d' pip install pandasabord
Boris le
1

Grâce à la façon dont vous pouvez indexer et sous-définir un dataframe pandas, un moyen très simple d'extraire une seule colonne d'un fichier csv dans une variable est:

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

Quelques points à considérer:

L'extrait ci-dessus produira un pandas Serieset non dataframe. La suggestion d'ayhan avec usecolssera également plus rapide si la vitesse est un problème. Tester les deux approches différentes à l'aide %timeitd'un fichier csv de 2122 Ko donne des résultats 22.8 mspour l'approche usecols et 53 mspour l'approche suggérée.

Et n'oubliez pas import pandas as pd

vestland
la source
0

Si vous avez besoin de traiter les colonnes séparément, j'aime déstructurer les colonnes avec le zip(*iterable)motif (effectivement "décompresser"). Donc pour votre exemple:

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

Pour récupérer le nom de la colonne , au lieu d'utiliser readlines (), mieux vaut utiliser readline () pour éviter de boucler et de lire le fichier complet et de le stocker dans le tableau.

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

    # get number of columns

    line = csvfile.readline()

    first_item = line.split(',')
Suren
la source