2016-07-29 1 views
0

Je suis un urbaniste migrant vers l'analyse de données spatiales. Je ne suis pas inconscient de R et de la programmation en général mais comme je n'ai pas la formation adéquate, mes compétences sont parfois limitées.Importer des fichiers CSV avec des lignes brisées CRLF dans R

En ce moment j'essaie d'analyser environ 50 fichiers CSV contenant des données financières concernant des ventes aux enchères publiques qui sont de 60000 à 300000 lignes avec 39 champs. Les fichiers sont des exportations du système national d'enchères publiques roumain, qui est une plate-forme de type formulaire.

Le problème est que certaines des lignes sont brisées par CRLF terminaisons de ligne au milieu des champs d'adresse. Je soupçonne que lorsque les gens ont entré leur adresse dans le formulaire, ils l'ont copié/collé à partir d'autres fichiers où il était multiligne.

Le problème ne peut pas être résolu par Rechercher & Remplacer car cela remplacera également le bon CRLF à la fin de la ligne.

À titre d'exemple les données sont formatées quelque chose comme ça et a un CRLF après chaque ligne (Ils ont utilisé^comme séparateur):

Castigator^CastigatorCUI^CastigatorTara^CastigatorLocalitate^CastigatorAdresa^Tip^TipContract^TipProcedura^AutoritateContractanta^AutoritateContractantaCUI^TipAC^TipActivitateAC^NumarAnuntAtribuire^DataAnuntAtribuire^TipIncheiereContract^TipCriteriiAtribuire^CuLicitatieElectronica^NumarOfertePrimite^Subcontractat^NumarContract^DataContract^TitluContract^Valoare^Moneda^ValoareRON^ValoareEUR^CPVCodeID^CPVCode^NumarAnuntParticipare^DataAnuntParticipare^ValoareEstimataParticipare^MonedaValoareEstimataParticipare^FonduriComunitare^TipFinantare^TipLegislatieID^FondEuropean^ContractPeriodic^DepoziteGarantii^ModalitatiFinantare 
S.C. RCTHIA CO S.R.L.^65265644^Romania^Bucharest^DN1 
Nr. 1, ^Anunt de atribuire la anunt de participare^Furnizare^Licitatie deschisa^COMPANIA NATIONALA DE TRANSPORT AL ENERGIEI ^R656556^^Electricitate^96594^2007-12-14^Un contract de achizitii publice^Pretul cel mai scazut^^1^^61^2007-11-08 00:00:00.000^Televizoare^304503.95^RON^304503.950000000001^89650.5^45937^323124100-1^344578^2007-10-02^49700.00^RON^^^^^^Nu este cazul;^Surse proprii; 
ASOC : SC MNG SRLsi SC AquaiM SA ^56565575;656224^Romania^Ploiesti^Str. Independentei nr.15; 
Str. Carol nr. 45^Anunt de atribuire la anunt de participare^Lucrari^Negociere fara anunt de participare^MUNICIPIUL RAMNICU VALCEA^6562655^Administratie publica locala (municipii, orase, comune), institutie publica in subordonarea/coordonarea administratiei publice locale^Servicii generale ale administratiilor publice^56566^2007-10-10^Un contract de achizitii publice^Pretul cel mai scazut^^1^^65656^2007-09-12^Proiectare si executie lucrari^5665560.00^RON^659966.0^5455222^7140^65689966-2^^^^^^^^^^^ 

Afin de traiter correctement les données que je aurais besoin du CSV être lu comme celui-ci, en supprimant seulement les CRLF qui brisent les lignes - qui trouvent & Remplacer ne peut pas faire:

Castigator^CastigatorCUI^CastigatorTara^CastigatorLocalitate^CastigatorAdresa^Tip^TipContract^TipProcedura^AutoritateContractanta^AutoritateContractantaCUI^TipAC^TipActivitateAC^NumarAnuntAtribuire^DataAnuntAtribuire^TipIncheiereContract^TipCriteriiAtribuire^CuLicitatieElectronica^NumarOfertePrimite^Subcontractat^NumarContract^DataContract^TitluContract^Valoare^Moneda^ValoareRON^ValoareEUR^CPVCodeID^CPVCode^NumarAnuntParticipare^DataAnuntParticipare^ValoareEstimataParticipare^MonedaValoareEstimataParticipare^FonduriComunitare^TipFinantare^TipLegislatieID^FondEuropean^ContractPeriodic^DepoziteGarantii^ModalitatiFinantare 
S.C. RCTHIA CO S.R.L.^65265644^Romania^Bucharest^DN1 Nr. 1, ^Anunt de atribuire la anunt de participare^Furnizare^Licitatie deschisa^COMPANIA NATIONALA DE TRANSPORT AL ENERGIEI ^R656556^^Electricitate^96594^2007-12-14^Un contract de achizitii publice^Pretul cel mai scazut^^1^^61^2007-11-08 00:00:00.000^Televizoare^304503.95^RON^304503.950000000001^89650.5^45937^323124100-1^344578^2007-10-02^49700.00^RON^^^^^^Nu este cazul;^Surse proprii; 
ASOC : SC MNG SRLsi SC AquaiM SA ^56565575;656224^Romania^Ploiesti^Str. Independentei nr.15; Str. Carol nr. 45^Anunt de atribuire la anunt de participare^Lucrari^Negociere fara anunt de participare^MUNICIPIUL RAMNICU VALCEA^6562655^Administratie publica locala (municipii, orase, comune), institutie publica in subordonarea/coordonarea administratiei publice locale^Servicii generale ale administratiilor publice^56566^2007-10-10^Un contract de achizitii publice^Pretul cel mai scazut^^1^^65656^2007-09-12^Proiectare si executie lucrari^5665560.00^RON^659966.0^5455222^7140^65689966-2^^^^^^^^^^^ 

J'ai trouvé une solution possible (Is there a way in R to join broken lines of csv file?), mais il a fallu un peu tweakin g pour répondre à mes besoins. Le résultat final est que le code ci-dessous se bloque et n'atteint pas la fin du processus, même sur de petits fichiers d'échantillons.

Mon altération du code de solution retenue du poste mentionné ci-dessus:

dat <- readLines("filename.csv") # read whatever is in there, one line at a time 
varnames <- unlist(strsplit(dat[1], "^", fixed = TRUE)) # extract variable names 
nvar <- length(varnames) 

k <- 1 # setting up a counter 
dat1 <- matrix(NA, ncol = nvar, dimnames = list(NULL, varnames)) 

while(k <= length(dat)){ 
    k <- k + 1 
    if(dat[k] == "") {k <- k + 1 
    print(paste("data line", k, "is an empty string")) 
    if(k > length(dat)) {break} 
    } 
    temp <- dat[k] 
    # checks if there are enough commas or if the line was broken 
    while(length(gregexpr("^", temp)[[1]]) < nvar-1){ 
    k <- k + 1 
    temp <- paste0(temp, dat[k]) 
    } 
    temp <- unlist(strsplit(temp, "^")) 
    message(k) 
    dat1 <- rbind(dat1, temp) 
} 

dat1 = dat1[-1,] # delete the empty initial row  

comptage des champs entre délimiteurs semble être une bonne solution, mais je suis incapable de trouver une bonne façon de le faire et mes compétences en programmation R ne sont pas assez apparemment.

Y a-t-il un moyen de réparer ce type de fichiers CSV cassés dans R?

exemples de fichiers de travail peuvent être consultés ici: http://data.gv.ro/dataset/4a4903c4-b1e3-46d1-82a5-238287f9496c/resource/c6abc0ef-3efb-4aef-bc0a-411f8cab2a28/download/contracte-2007.csv

Merci pour toute aide que vous pouvez donner!

Répondre

1

Le problème semble être que^est un caractère spécial. Si vous parcourez votre code, vous verrez que vous avez 627 variables au lieu de 39. Cela fait de chaque caractère une variable. Essayez ceci:

dat <- readLines("filename.csv") # read whatever is in there, one line at a time 
varnames <- unlist(strsplit(dat[1], "\\^")) # extract variable names 
nvar <- length(varnames) 

k <- 1 # setting up a counter 
dat1 <- matrix(NA, ncol = nvar, dimnames = list(NULL, varnames)) 

while(k <= length(dat)){ 
    k <- k + 1 
    #if(dat[k] == "") {k <- k + 1 
    #print(paste("data line", k, "is an empty string")) 
    if(k > length(dat)) {break} 
    #} 
    temp <- dat[k] 
    # checks if there are enough commas or if the line was broken 
    while(length(gregexpr("\\^", temp)[[1]]) < nvar-1){ 
    k <- k + 1 
    temp <- paste0(temp, dat[k]) 
    } 
    temp <- unlist(strsplit(temp, "\\^")) 
    message(k) 
    dat1 <- rbind(dat1, temp) 
} 

dat1 = dat1[-1,] # delete the empty initial row  

Désolé manqué cette différence dans votre code et le mien. Vous ne voulez pas fixed = true. en le changeant à ci-dessus vous donne ceci:

> varnames 
[1] "Castigator"      "CastigatorCUI"     "CastigatorTara"     
[4] "CastigatorLocalitate"    "CastigatorAdresa"     "Tip"        
[7] "TipContract"      "TipProcedura"      "AutoritateContractanta"   
[10] "AutoritateContractantaCUI"  "TipAC"       "TipActivitateAC"     
[13] "NumarAnuntAtribuire"    "DataAnuntAtribuire"    "TipIncheiereContract"    
[16] "TipCriteriiAtribuire"    "CuLicitatieElectronica"   "NumarOfertePrimite"    
[19] "Subcontractat"     "NumarContract"     "DataContract"      
[22] "TitluContract"     "Valoare"       "Moneda"       
[25] "ValoareRON"      "ValoareEUR"      "CPVCodeID"      
[28] "CPVCode"       "NumarAnuntParticipare"   "DataAnuntParticipare"    
[31] "ValoareEstimataParticipare"  "MonedaValoareEstimataParticipare" "FonduriComunitare"    
[34] "TipFinantare"      "TipLegislatieID"     "FondEuropean"      
[37] "ContractPeriodic"     "DepoziteGarantii"     "ModalitatiFinantare" 
+0

Salut Michael, merci pour votre réponse. La solution que vous avez publiée ne fonctionne pas pour moi. J'ai mis à jour l'échantillon de données pour refléter les données réelles. Pourriez-vous faire un test rapide pour voir si le problème est peut-être sur ma machine? Cela serait très appréciable! – AFG

+0

Le code que vous avez suggéré ne sépare pas les en-têtes de mes données d'échantillon par le délimiteur "^". – AFG

+0

Vous avez raison, le fixed = true ne devrait pas être là. Voir le code fixe ci-dessus et la sortie. –

0

Nous pouvons déterminer la dernière ligne de chaque enregistrement en vérifiant s'il se termine par un champ numérique. Puis, en utilisant cumsum, nous pouvons étiqueter les lignes du même enregistrement en utilisant 1, 2, 3, .... Enfin, collez-les ensemble.

# test data 
Lines <- "Name^FiscCode^Country^Adress^SomeData^ 
SomeCompany^235356^Romania^Adress1 
Adress2^ 565863 
SomeCompany^235356^Romania^Adress1^ 565863" 

# for real problem use readLines("myfile")[-1] 
L <- readLines(textConnection(Lines))[-1] 

g <- rev(cumsum(rev(grepl("\\^ *\\d+$", L)))) ## 
g <- max(g) - g + 1 
L2 <- tapply(L, g, paste, collapse = " ") 
read.table(text = L2, sep = "^") 

Les travaux ci-dessus pour les données présentées dans la question, mais s'il y a des différences dans les données réelles à ce que vous avez montré alors quelques modifications peuvent être nécessaires en fonction de ce que ces différences.

Note: S'il y a toujours quatre^caractères dans chaque enregistrement essayez de remplacer la ligne marquée ## avec ceci:

cnt <- count.fields(textConnection(L), sep = "^") - 1 
g <- rev(cumsum(rev(cumsum(cnt) %% 4 == 0))) 

Mise à jour La question a changé de fournir de nouvelles données d'échantillon.Notez que la réponse affichée fonctionne avec, mais vous devez bien sûr remplacer 4 par 38 car les nouvelles données ont 38 délimiteurs par enregistrement alors que les anciennes données en contenaient 4. De plus, les anciennes données avaient un en-tête et les nouvelles données non. supprimé les occurrences de -1 utilisées pour supprimer l'en-tête. Voici un auto exemple contenu qui peut être copié et collé dans R.

Lines <- "Castigator^CastigatorCUI^CastigatorTara^CastigatorLocalitate^CastigatorAdresa^Tip^TipContract^TipProcedura^AutoritateContractanta^AutoritateContractantaCUI^TipAC^TipActivitateAC^NumarAnuntAtribuire^DataAnuntAtribuire^TipIncheiereContract^TipCriteriiAtribuire^CuLicitatieElectronica^NumarOfertePrimite^Subcontractat^NumarContract^DataContract^TitluContract^Valoare^Moneda^ValoareRON^ValoareEUR^CPVCodeID^CPVCode^NumarAnuntParticipare^DataAnuntParticipare^ValoareEstimataParticipare^MonedaValoareEstimataParticipare^FonduriComunitare^TipFinantare^TipLegislatieID^FondEuropean^ContractPeriodic^DepoziteGarantii^ModalitatiFinantare 
S.C. RCTHIA CO S.R.L.^65265644^Romania^Bucharest^DN1 
Nr. 1, ^Anunt de atribuire la anunt de participare^Furnizare^Licitatie deschisa^COMPANIA NATIONALA DE TRANSPORT AL ENERGIEI ^R656556^^Electricitate^96594^2007-12-14^Un contract de achizitii publice^Pretul cel mai scazut^^1^^61^2007-11-08 00:00:00.000^Televizoare^304503.95^RON^304503.950000000001^89650.5^45937^323124100-1^344578^2007-10-02^49700.00^RON^^^^^^Nu este cazul;^Surse proprii; 
ASOC : SC MNG SRLsi SC AquaiM SA ^56565575;656224^Romania^Ploiesti^Str. Independentei nr.15; 
Str. Carol nr. 45^Anunt de atribuire la anunt de participare^Lucrari^Negociere fara anunt de participare^MUNICIPIUL RAMNICU VALCEA^6562655^Administratie publica locala (municipii, orase, comune), institutie publica in subordonarea/coordonarea administratiei publice locale^Servicii generale ale administratiilor publice^56566^2007-10-10^Un contract de achizitii publice^Pretul cel mai scazut^^1^^65656^2007-09-12^Proiectare si executie lucrari^5665560.00^RON^659966.0^5455222^7140^65689966-2^^^^^^^^^^^" 

L <- readLines(textConnection(Lines)) 

cnt <- count.fields(textConnection(L), sep = "^") - 1 # 38 4 34 4 34 
g <- rev(cumsum(rev(cumsum(cnt) %% 38 == 0))) 
g <- max(g) - g + 1 # 1 2 2 3 3 
L2 <- tapply(L, g, paste, collapse = " ") 
DF <- read.table(text = L2, sep = "^") 
dim(DF) 
## [1] 3 39 

Les données de l'échantillon ne contient pas de caractères de commentaire (#) ou des guillemets simples ou doubles, mais si elle ne contient ce sont une partie de leurs données, alors l'ajout de comment.char = "", quote = "" aux appels count.fields et read.table serait nécessaire.

+0

Merci pour votre réponse! En effet les données sont beaucoup plus variées. L'exemple était juste pour illustrer la rupture dans la ligne. Certaines lignes manquent plusieurs attributs et se terminent par exemple dans ^^^^^^^^^, ce qui devrait être des champs vides. De même, comment les lignes complètes (sans coupures accidentelles) seraient-elles traitées? L'idée que je recherchais (inspiré par le message mentionné) était de compter les champs entre les délimiteurs et si la valeur est inférieure à 39, alors il ajouterait des champs de la ligne suivante jusqu'à ce qu'il atteigne 39 de longueur. Je ne sais pas si je suis clair. – AFG

+0

La solution peut être étendue à condition que vous puissiez trouver une condition qui soit toujours satisfaite par la dernière ligne de chaque enregistrement. Par exemple, si seule la dernière ligne de chaque enregistrement se termine par un champ numérique ou un champ vide, il suffirait alors de modifier la première ligne 'g <-' dans la réponse, c'est-à-dire de remplacer le + par un *. –

+0

J'ai également ajouté une note qui fonctionnerait s'il y a toujours le même nombre de champs par enregistrement. –