Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

media di una matrice in VBA

417 views
Skip to first unread message

by sal

unread,
Jul 8, 2015, 1:51:38 AM7/8/15
to
Ciao a tutti, questa volta cerco un aiuto con una matrice.

devo calcolare la media di alcuni dati di una matrice.

ho una matrice bidimensionale con base 1 Calc(50000, 16)

ora dovrei calcolare la media non di tutta la matrice ma solo di una porzione

diciamo primo indice dalla 3000 alla 5000 della 4 secondo indice.

ho scritto questo codice creando una seconda matrice rng

""
n=1
for x = 3000 to 5000
rng(n) = calc(x,4)
n = n + 1
next x

poi calcolo la media

mm = WorksheetFunction.Average(rng)

""

ora vorrei eliminare il ciclo for...next perchè allunga i tempi di esecuzione, ci sarebbe un metodo migliore.

se i dati sarebbero sul foglio, farei un semplice

rng = Range("D3000:D5000")

eliminando il ciclo

ma i dati sono nella matrice Calc() e non so come fare la stessa cosa senza il ciclo

spero di essere stato chiaro

Ciao By Sal (8-D

Bruno Campanini

unread,
Jul 8, 2015, 5:13:12 AM7/8/15
to
by sal pretended :

> diciamo primo indice dalla 3000 alla 5000 della 4 secondo indice.
>
> ho scritto questo codice creando una seconda matrice rng
>
> ""
> n=1
> for x = 3000 to 5000
> rng(n) = calc(x,4)
> n = n + 1
> next x
>
> poi calcolo la media
Non mi sembra tu possa eliminare il ciclo, puoi ottimizzarlo:

For i = 3000 to 5000
n = n +1
S = S + calc(i, 4)
Next
S = S / n

Bruno

by sal

unread,
Jul 8, 2015, 5:55:19 AM7/8/15
to
Il giorno mercoledì 8 luglio 2015 11:13:12 UTC+2, Bruno Campanini ha scritto:
> by sal pretended :
>

> Non mi sembra tu possa eliminare il ciclo, puoi ottimizzarlo:
>
> For i = 3000 to 5000
> n = n +1
> S = S + calc(i, 4)
> Next
> S = S / n
>
> Bruno

Ciao Bruno come sempre grazie per le risposte.

sono quello dei grandi numeri, il ciclo di per se mi implica molto anche con la tua soluzione.

dovrei cercare di eliminarlo proprio.

questa la macro intera, anche se dici che leggere il codice di altri e come l'arabo

Option Explicit
Option Base 1

Sub Calcolo_1()
Dim r, x, y, k, n, T1, TT, rng(), Limite1, Limite2, Limite3, Fisso1, Fisso2, Dati, Calc
Dim Riga, Colonna, intervallo

Limite1 = 6000
Limite2 = 12000
Limite3 = 13000
Fisso1 = 4140

Application.Calculation = xlCalculationManual
TT = Now
Sheets("Dati").Select 'seleziona il foglio dati
r = Cells(Rows.Count, 2).End(xlUp).Row 'prende 50.000 righe
Dati = Range("A3:C" & r)
ReDim Calc(r, 1 To 16)
For x = LBound(Dati) To UBound(Dati)
Calc(x, 1) = Dati(x, 1)
Calc(x, 2) = Dati(x, 2)
Calc(x, 3) = Dati(x, 3)
If x = 1 Then
If Dati(x, 3) = 0 Then
Calc(x, 4) = 0
Else
Calc(x, 4) = Dati(x, 3)
End If
Else
If Dati(x, 3) = 0 Then
Calc(x, 4) = Calc(x - 1, 4)
Else
Calc(x, 4) = Dati(x, 3)
End If
End If
If x >= Limite1 Then
n = 1
ReDim rng(x)
For k = x - (Limite1 - 1) To x 'ciclo da rivedere
rng(n) = Calc(k, 4)
n = n + 1
Next k
Calc(x, 6) = WorksheetFunction.Average(rng) '"Calc(x - Limite1, 4):Calc(x, 4)")
End If
If x >= Limite2 Then
n = 1
ReDim rng(x)
For k = x - (Limite2 - 1) To x 'ciclo da rivedere
rng(n) = Calc(k, 4)
n = n + 1
Next k
Calc(x, 5) = WorksheetFunction.Average(rng) 'Calc(x - Limite2, 4), Calc(x, 4))
Calc(x, 7) = Calc(x, 6) - Calc(x, 5)
Calc(x, 8) = Calc(x, 7) - Calc(x - 1, 7)
If Calc(x, 8) = 0 Then Calc(x, 9) = Calc(x, 9) Else Calc(x, 9) = Calc(x, 8)
If Calc(x, 10) > 0 Then Calc(x, 11) = 1 Else Calc(x, 11) = 0
If Calc(x - 1, 11) = 0 And Calc(x, 11) = 1 Then Calc(x, 12) = "up" Else Calc(x, 12) = 0
If Calc(x, 12) = "up" Then Calc(x, 13) = Calc(x, 2) Else Calc(x, 13) = 0
If Calc(x - 1, 11) = 1 And Calc(x, 11) = 0 Then Calc(x, 14) = "down" Else Calc(x, 14) = 0
If Calc(x, 14) = "down" Then Calc(x, 15) = Calc(x, 2) Else Calc(x, 15) = 0
End If
If x >= Limite3 Then
n = 1
ReDim rng(x)
For k = x - (1000 - 1) To x 'Ciclo da rivedere
rng(n) = Calc(k, 9)
n = n + 1
Next k
Calc(x, 10) = WorksheetFunction.Average(rng) * Fisso1 'Calc(x - 1000, 9), Calc(x, 9)) * Fisso1
n = 1
ReDim rng(x)
For k = x - (5000 - 1) To x 'ciclo da rivedere
rng(n) = Calc(k, 9)
n = n + 1
Next k
Calc(x, 16) = WorksheetFunction.Average(rng) * Fisso1 'Calc(x - 1000, 9), Calc(x, 9) * Fisso2)
End If
Next x
Sheets("Calcolo").Select 'seleziona il foglio di scrittura dati
r = Cells(Rows.Count, 2).End(xlUp).Row
Range("A3:P" & r).ClearContents

Riga = UBound(Calc, 1)
Colonna = UBound(Calc, 2)
Set intervallo = Range("A3").Resize(Riga, Colonna)
intervallo.Value = Calc

Application.Calculation = xlCalculationAutomatic

TT = Now - T1
MsgBox "Tempo impiegato " & Format(TT, "hh:mm:ss")
End Sub.

i dati sono circa 50.000 righe ed ogni riga viene processata con calcoli, questi calcoli sono sul foglio con le formule, ora un foglio con 50.000 righe e 16 colonne piene di calcoli, ogni piccola variazione, anche mettendo il calcolo manuale implica un sacco di tempo per l'aggiornamento.

quindi ho creato questa macro che fa i calcoli e scrive il risultato sul foglio senza formule, vengono fatte dalla macro.

nella macro ci sono 5 medie da calcolare, ogni media calcola diverse righe da 1000 - 6000 e 13000, e questo mi comporta appunto un tempo importante per la macro.

ho fatto una prova eliminando i cicli per le medie il tutto fra lettura-calcolo e scrittura si arriva a circa 2 secondi per l'esecuzione completa.

ma come dici non ce modo di eliminarli.

con Redim preserve non si può salvare il pezzo di una matrice in un altra matrice, sapendo la riga(indice) di inizio e fine.

Ciao By Sal (8-D


Bruno Campanini

unread,
Jul 8, 2015, 6:21:20 AM7/8/15
to
After serious thinking by sal wrote :

[...]
> i dati sono circa 50.000 righe ed ogni riga viene processata con calcoli,
> questi calcoli sono sul foglio con le formule, ora un foglio con 50.000 righe
> e 16 colonne piene di calcoli, ogni piccola variazione, anche mettendo il
> calcolo manuale implica un sacco di tempo per l'aggiornamento.
>
> quindi ho creato questa macro che fa i calcoli e scrive il risultato sul
> foglio senza formule, vengono fatte dalla macro.
>
> nella macro ci sono 5 medie da calcolare, ogni media calcola diverse righe da
> 1000 - 6000 e 13000, e questo mi comporta appunto un tempo importante per la
> macro.
>
> ho fatto una prova eliminando i cicli per le medie il tutto fra
> lettura-calcolo e scrittura si arriva a circa 2 secondi per l'esecuzione
> completa.
Invece per l'operazione completa qual è il tempo impiegato?

Dici che hai creato un nuovo foglio senza formule (solo dati).
Però il lavoro è da rifare ad ogni nuova riga inserita, è così?

Potresti condividere il foglio completo, quello con tutte le formule?

Bruno

Scossa

unread,
Jul 8, 2015, 7:01:11 AM7/8/15
to
Il giorno mercoledì 8 luglio 2015 07:51:38 UTC+2, by sal ha scritto:
>
> se i dati sarebbero sul foglio, farei un semplice
>
> rng = Range("D3000:D5000")
>
> eliminando il ciclo
>
> ma i dati sono nella matrice Calc() e non so come fare la stessa cosa senza il ciclo


Ma non puoi semplicemente copiarli temporaneamente in un foglio di appoggio e poi estrarli da lì?

Sub prova()
Dim calc As Variant
ReDim calc(1 To 50000, 1 To 16) As Variant
calc = Range("A1:P50000")
'le righe sopra servono solo per creare la matrice di test

Foglio2.Range("A1:P50000") = calc
calc = Foglio2.Range("D3000:D5000")
Debug.Print Application.WorksheetFunction.Average(calc)

End Sub

Cristiano

unread,
Jul 8, 2015, 7:55:42 AM7/8/15
to
On 08/07/2015 11:55, by sal wrote:
> Dim r, x, y, k, n, T1, TT, rng(), Limite1, Limite2, Limite3, Fisso1, Fisso2, Dati, Calc
> Dim Riga, Colonna, intervallo

Senza definizione del tipo di variabile, se non ricordo male, queste
sono tutte variabili di tipo variant, ultra-lente.
Se definisci il tipo per ogni variabile, secondo me, guadagni già molto.

> For x = LBound(Dati) To UBound(Dati)

Dentro a questo ciclo c'è un'infinità di diramazioni. Dovresti tentare
di spezzettare il ciclo per eliminare gli if (ciò che viene chiamato
"loop unrolling").
Se l'if riguarda il contatore del ciclo, come in questi casi:

> If x = 1 Then

> If x >= Limite1 Then

la cosa è semplice, ma se l'if dipende dai dati, la cosa probabilmente
non è fattibile: If Dati(x, 3) = 0 Then...

Ci sono anche parecchi ReDim. Tenta di allocare i vettori e le matrici
al di fuori del for x.

> If Calc(x, 8) = 0 Then Calc(x, 9) = Calc(x, 9) Else Calc(x, 9) = Calc(x, 8)

Non so se qui c'è un errore: Calc(x, 9) = Calc(x, 9)?

Cristiano

by sal

unread,
Jul 8, 2015, 9:24:34 AM7/8/15
to

>
> > If x >= Limite1 Then
>
> la cosa è semplice, ma se l'if dipende dai dati, la cosa probabilmente
> non è fattibile: If Dati(x, 3) = 0 Then...
>
> Ci sono anche parecchi ReDim. Tenta di allocare i vettori e le matrici
> al di fuori del for x.
>
> > If Calc(x, 8) = 0 Then Calc(x, 9) = Calc(x, 9) Else Calc(x, 9) = Calc(x, 8)
>
> Non so se qui c'è un errore: Calc(x, 9) = Calc(x, 9)?
>
> Cristiano

Ciao Cristiano, i redim servono per azzerare la matrice rng per il nuovo riempimento dei dati

invece "If x >= Limite1 Then" serve soltanto perchè a partire da quel indice devono partire altre formule

hai ragione per questa

If Calc(x, 8) = 0 Then Calc(x, 9) = Calc(x, 9) Else Calc(x, 9) = Calc(x, 8)

in effetti la formula originale è questa

=SE(H12003=0;I12002;H12003)

che diventerebbe

If Calc(x, 8) = 0 Then Calc(x, 9) = Calc(x-1, 9) Else Calc(x, 9) = Calc(x, 8)

Ciao By Sal (8-D



by sal

unread,
Jul 8, 2015, 9:24:44 AM7/8/15
to
Il giorno mercoledì 8 luglio 2015 13:01:11 UTC+2, Scossa ha scritto:
> Il giorno mercoledì 8 luglio 2015 07:51:38 UTC+2, by sal ha scritto:

> Ma non puoi semplicemente copiarli temporaneamente in un foglio di appoggio e poi estrarli da lì?

Ciao Scossa No non posso in quanto la matrice Calc viene aggiornata(generata) ad ogni riga di Dati(), la matrice Dati() ha solo 3 colonne come 2° indice, le altre 13 colonne 2° indice sono calcoli nella matrice Calc.

forse però provo a fare come dici copiare i dati sul foglio e vedo se riesco in qualcosa.


Ciao By Sal (8-D

by sal

unread,
Jul 9, 2015, 3:27:43 AM7/9/15
to
Il giorno mercoledì 8 luglio 2015 15:24:44 UTC+2, by sal ha scritto:

Ciao una domanda veloce legata all'argomento.

ho pensato di inserire i dati in una Collection, ed ogni volta eleminare il primo elemento con Remove.

vi risulta che la New collection ha solo 256 elementi?

ho provato a farlo ma arriva solo a 256 valori.

Ciao By Sal (8-D


Bruno Campanini

unread,
Jul 9, 2015, 3:41:32 AM7/9/15
to
by sal brought next idea :
Usa Dictionary (richiede Microsoft Scripting Runtime); è molto più
veloce e capiente e consente la ricerca per chiave oltreché per
posizione.

Rinnovo la domanda: non puoi condividere il foglio con le formule?

Bruno

by sal

unread,
Jul 9, 2015, 5:30:44 AM7/9/15
to
> Rinnovo la domanda: non puoi condividere il foglio con le formule?
>
> Bruno

sono riuscito a risolvere alche l'ultimo problema della DDD

Però non riesco a vedere il post che ho messo poco fa.

ho inserito anche il link al file.

nel caso lo riscrivo

Ciao By Sal (8-D

by sal

unread,
Jul 9, 2015, 5:15:08 AM7/9/15
to
Il giorno giovedì 9 luglio 2015 09:41:32 UTC+2, Bruno Campanini ha scritto:
> Rinnovo la domanda: non puoi condividere il foglio con le formule?
>
> Bruno

Ciao Bruno scusa, mi è scappato di mente, non ho problemi a condividere il file, ecco il link

https://www.dropbox.com/s/7xfyjkibqsf7ty5/Prova1.xlsm?dl=0

il file è 10 Mb ma togliendo poi tutte le formule sicuramente diminuirà di peso, il foglio completo con le formule è il foglio dati, è un foglio di calcolo per l'andamento azionario, serve a generare un grafico

ma credo di aver risolto ora il tempo è appena 4 secondi con il mio PC datato

ho fatto in questo modo, ho creato 4 variabili DDA-DDB-DDC-DDD, mano a mano che scorro i dati faccio la somma dei dati della colonna interessata alla media, poi quando mi interessa mettere il valore nella Matrice faccio la media

DDx/numero righe interessate

logicamente per lo scorrere della media alla somma tolgo il primo valore cosi ho sempre un range di valori fissi per fare la media anche se variabili.

ora però sono alle prese con l'ultimo dilemma, interessa la DDD che ha una formula particolare per la media, e non riesco a riportarla per il VBA, sarà una sciocchezza, ma mi sono impantanato

ci sono 2 formule per la media fanno riferimento ad una sola colonna, ma sono diverse.

questa diciamo che è la formula classica inserita alla riga 13002

=MEDIA(I12003:I13002)*$J$1

nella colonna "J" che fa riferimento alla colonna "I"

=MEDIA(I12003:I13002*$J$1)

quest'altra invece nella colonna "P" sempre alla riga 13002

come si vede il valore fisso "$J$1" si trova all'interno delle parentesi

mentre per la prima ho assegnato DDC per il valore faccio

DDC = DDC + Calc(X, 9)

per l'incremento di DDC

per la seconda che ho assegnato DDD non riesco ancora a capire come impostare la formula in VBA

ho fatto

DDD = DDD + Calc(x, 9) * Fisso1 (che contiene il valore di $J$1)

ma non mi da lo stesso valore della cella "P13002"

in attesa di notizie Ciao By Sal (8-D



Bruno Campanini

unread,
Jul 9, 2015, 7:31:32 AM7/9/15
to
After serious thinking by sal wrote :

> Il giorno giovedì 9 luglio 2015 09:41:32 UTC+2, Bruno Campanini ha scritto:
>> Rinnovo la domanda: non puoi condividere il foglio con le formule?
>>
>> Bruno
>
> Ciao Bruno scusa, mi è scappato di mente, non ho problemi a condividere il
> file, ecco il link
>
> https://www.dropbox.com/s/7xfyjkibqsf7ty5/Prova1.xlsm?dl=0

Sì, riesco a intravvedere un foglio composto da più colonne,
solo quattro delle quali compilate, però Dropbox si pianta
e non me lo fa scaricare.

Bruno

by sal

unread,
Jul 9, 2015, 10:01:25 AM7/9/15
to
Ciao Bruno, le colonne sembrano solo 4 ma dalla riga 1000 incominciano le formule con più colonne fino alla 44.000 e rotti dalla 13.000 sono tutte le colonne fino alla "P" compilate

dal link della tua risposta sono riuscito a scaricarlo.

office 365 cerca di aprire lui il file logico che vuole che ti fai l'iscrizione ma dici di no e scarica solo il file.

non e che hai dropbox pieno ha raggiunto la sua capacità?

Ciao By Sal (8-D

0 new messages