J'ai un très gros fichier CSV (million + lignes), sur lequel j'aimerais effectuer quelques opérations. Le problème est que certaines lignes ont des sauts de ligne indésirables, comme ceci:
New York City; Iron Man; no superpowers Metropolis; Superman; superpowers; New York City; Spider-Man; superpowers; Gotham; Batman; no superpowers; New York City; Doctor Strange; superpowers;
Le fichier a donc trois colonnes ( location , super-héros , superpouvoirs ). Puisque l'entrée de Spider-Man est défectueuse, car elle a des sauts de ligne entre ses entrées, les pandas supposent à tort qu'il s'agit de trois lignes séparées, avec NaNs dans la deuxième et la troisième colonne.
Mon idée était de résoudre ce problème lors de l'importation avec regex. Selon ce site Web , cette expression régulière correspond correctement aux lignes souhaitées et ne correspond pas au ceux défectueux (par exemple Spider-Man).
(. * [;]. * [;]. *)
Son inverse ( (?! (. * [;]. * [;]. *)) , cependant, ne fonctionne pas, car non seulement il ne correspond pas aux trois lignes défectueuses, mais aussi à la troisième entrée de chaque ligne normale.
Mon autre approche consistait simplement à définir le nombre de colonnes, puis à supprimer tous les sauts de ligne du fichier entier. Cela ne fonctionnait pas non plus.
superhero_df = pd.read_csv("superheroes.csv", sep=' *; *', skiprows=12, names=["location", "superhero", "superpower"], index_col=False, engine="python")
superhero_df = superhero_df.replace('\r\n','', regex=True)
5 Réponses :
Et à propos de ça:
import re
regex = r"^([^;]+);[\r\n]*([^;]+);[\r\n]*([^;]+);"
test_str = ("New York City; Iron Man; no superpowers;\n"
"Metropolis; Superman; superpowers;\n"
"New York City;\n"
"Spider-Man;\n"
"superpowers;\n"
"Gotham; Batman; no superpowers;\n"
"New York City; Doctor Strange; superpowers;\n\n")
subst = "\\1;\\2;\\3;"
# You can manually specify the number of replacements by changing the 4th argument
result = re.sub(regex, subst, test_str, 0, re.MULTILINE | re.DOTALL)
if result:
print (result)
et remplacer par:
\1;\2;\3;
^([^;]+);[\r\n]*([^;]+);[\r\n]*([^;]+);
Malheureusement, cela ne semble pas fonctionner avec mes données, car le résultat est toujours le même. L'impression des lignes défectueuses avec des pandas génère les résultats suivants: 'location New York City \ nsuperhero NaN \ nsuperpower None \ nName: 131061, dtype: object'
L'expression régulière suivante élimine les sauts de ligne indésirables et autres espaces blancs tous les trois champs. Cela suppose que les champs n'ont pas de point-virgule interne:
print(re.sub(r'([^;]*);\s*([^;]*);\s*([^;]*);\s+', r'\1;\2;\3\n',
line, flags=re.M))
#New York City; Iron Man;no superpowers
#Metropolis;Superman;superpowers
#New York City;Spider-Man;superpowers
#Gotham;Batman;no superpowers
#New York City;Doctor Strange;superpowers
Vous pouvez l'exécuter en boucle pour prétraiter le fichier avant d'utiliser Pandas.
Malheureusement, cela ne semble pas fonctionner, car le résultat est toujours le même. Imprimer les sorties des lignes de défaut: 'location New York City \ nsuperhero NaN \ nsuperpower None \ nName: 131061, dtype: object'
J'ai utilisé vos exemples de données et j'ai obtenu les résultats attendus. D'où viennent les nans? Vous devez nettoyer le fichier CSV avant de le charger dans les pandas. Il ne devrait y avoir aucun nans dedans.
Tu avais raison. J'ai parcouru le fichier avant de le charger, mais il ne semble toujours pas fonctionner. C'est ce que j'ai fait: tmp = "" pour la ligne dans data.splitlines (): line = re.sub (r '([^;] *); \ s * ([^;] *); \ s * ([^;] *); \ s + ', r' \ 1; \ 2; \ 3 \ n ', ligne, drapeaux = re.M) tmp + = ligne
Solution la plus simple:
import pandas as pd
import re
string = """New York City; Iron Man; no superpowers;
Metropolis; Superman; superpowers;
New York City;
Spider-Man;
superpowers;
Gotham; Batman; no superpowers;
New York City; Doctor Strange; superpowers;"""
cities=[]
superheros=[]
superpowers = []
splited_list = re.split(';', string)
splited_list.pop(len(splited_list) - 1 )
i = 0
while i < len(splited_list) - 1:
cities.append(splited_list[i])
superheros.append(splited_list[i + 1])
superpowers.append(splited_list[i + 2])
i = i + 3
df = pd.DataFrame({
"City": cities,
"Superhero": superheros,
"superpowers": superpowers
})
Voici mon approche, non optimisée pour les performances mais je peux le faire:
[['New York City', 'Iron Man', 'no superpowers'], ['Metropolis', 'Superman', 'superpowers'], ['New York City', 'Spider-Man', 'superpowers'], ['Gotham', 'Batman', 'no superpowers'], ['New York City', 'Doctor Strange', 'superpowers']]
le résultat est une liste de listes:
from pprint import pprint
def main():
count=0
outer_list=[]
row=[]
with open('superheroes.csv') as f:
for line in f:
for word in line.split(";"):
if not str.isspace(word):
word=word.strip()
row.append(str(word))
count = count + 1
if count % 3 == 0:
outer_list.append(row)
row=[]
pprint(outer_list)
if __name__== "__main__":
main()
p>
Si j'étais vous, je réécrirais toutes les données dans un nouveau fichier texte avec une simple itération sur le fichier texte source et chargerais le fichier résultant dans Pandas, aucun re nécessaire:
pd.read_csv('target.txt', header=None, sep=';')
# 0 1 2
# 0 New York City Iron Man no superpowers
# 1 Metropolis Superman superpowers
# 2 New York City Spider-Man superpowers
# 3 Gotham Batman no superpowers
# 4 New York City Doctor Strange superpowers
Résultat:
with open('source.txt') as fin, open('target.txt', 'w') as fout:
lc = 0
for line in fin:
lc += line.count(';')
if lc < 3:
fout.write(line.strip())
else:
fout.write(line.strip()[:-1] + '\n')
lc = 0
Lecture dans Pandas:
pd.read_csv('target.txt', header=None, sep=';', usecols=range(3))
# 0 1 2
# 0 New York City Iron Man no superpowers
# 1 Metropolis Superman superpowers
# 2 New York City Spider-Man superpowers
# 3 Gotham Batman no superpowers
# 4 New York City Doctor Strange superpowers
Remarque: usecols n'est nécessaire qu'à cause du point-virgule de fin. Cela peut être évité en important avec
# New York City; Iron Man; no superpowers; # Metropolis; Superman; superpowers; # New York City;Spider-Man;superpowers; # Gotham; Batman; no superpowers; # New York City; Doctor Strange; superpowers;
Lecture dans Pandas:
with open('source.txt') as fin, open('target.txt', 'w') as fout:
lc = 0
for line in fin:
lc += line.count(';')
if lc < 3:
fout.write(line[:-1])
else:
fout.write(line)
lc = 0
Vous pouvez exécuter quelque chose comme ideone.com/jTP9S3 pour prétraiter le fichier, écrivez-le dans un autre (utilisez
f.write (newfile)au lieu des commandesprint), puis chargez-le comme d'habitude. Cela signifie que vous n'avez pas à lire le fichier entier en mémoire. Ce que vous essayez est de charger d'abord le contenu dans dataframe, puis d'exécuterreplace, alors que ce devrait être l'inverse: d'abord remplacer, puis charger.