Schrift
Wiki:Tipp zum Debugging: use Data::Dumper; local $Data::Dumper::Useqq = 1; print Dumper \@var;
[thread]8198[/thread]

Datenblöcke mitteln

Leser: 1


<< >> 9 Einträge, 1 Seite
EagleFox
 2006-07-25 14:04
#68373 #68373
User since
2006-04-10
66 Artikel
BenutzerIn
[default_avatar]
Hallo, ich suche ne Idee zum Mitteln von Datenblöcken.

Ich habe eine Datei mit gaaaaaanz vielen Datenblöcken, die jeweils durch zwei Leerzeilen getrennt sind. Die Datenblöcke selber bestehen aus 4 Spalten (jeweils durch Leerzeichen getrennt) und gaaanz vielen Zeilen.

Ich möchte nun z.B die Datenblöcke 1000 bis 1050 übereinander mitteln. Wie stelle ich das am besten an?
Alle Datenblöcke in jeweils ein Array packen, die Summen der jeweiligen Einträge bilden (ich brauche nur ne bestimmte Spalte) und anschliessend durch die Anzahl teilen ist ein bisschen aufwendig, oder?
Also:

Code: (dl )
1
2
3
4
5
6
7
8
9
10
for(my $k = 0; $k < $punkteproarray; $k++){

for(my $i = 0; $i < $anzahldatenblöcke; $i++){ # #Datenblöcke = #arrays

$neuesarray[$k] = $neuesarray[$k] + $array$i[$k];
}

$neuesarray[$k] = $neuesarray[$k] / $anzahldatenblöcke;

}


Geht das dann so, oder gibt es da einen simpleren Weg?
Linuxer
 2006-07-25 14:30
#68374 #68374
User since
2006-01-27
3872 Artikel
HausmeisterIn

user image
Hi,

hier ein Beispiel (im kleinen Rahmen):
Code: (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#!/usr/bin/perl
# vim: set ts=4 sw=4 et sta:
use strict;
use warnings;

{
# Zeilentrenner neu definieren; eher Datenblocktrenner
local $/ = "\n\n";

# Datenblockweise einlesen
while ( <DATA> ) {
# Trenner entfernen
chomp;

# 2. bis 3. Datenblock ausgeben
print $_, "\n" if ( $. >= 2 and $. <= 3 );
}
}

__DATA__
AAA1 AAA2 AAA3 AAA4

BBB1 BBB2 BBB3 BBB4
BBB5 BBB6 BBB7 BBB8

CCC1 CCC2 CCC3 CCC4


Das Mitteln ist hierbei nicht implementiert; Aber es soll Dir zeigen, wie Du die Datensaetze x bis y ermitteln kannst, ohne alle Datensaetze in den Speicher jagen zu muessen.\n\n

<!--EDIT|Linuxer|1153823538-->
meine Beiträge: I.d.R. alle Angaben ohne Gewähr und auf Linux abgestimmt!
Die Sprache heisst Perl, nicht PERL. - Bitte Crossposts als solche kenntlich machen!
Ronnie
 2006-07-25 14:55
#68375 #68375
User since
2003-08-14
2022 Artikel
BenutzerIn
[default_avatar]
Soweit ich das verstanden habe willst du für eine bestimmte Spalte je Datensatz den Durchschnitt bilden?
Code: (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#!/usr/bin/perl

use strict;
use warnings;

use Data::Dumper;
use List::Util qw/sum/;

my $aoa = [];
my $cur = [];

while (<DATA>) {
chomp;
push @$aoa, $cur and $cur = [] and next if /^$/;
push @$cur, (split /\s/)[1]; # nur eine Spalte
}
push @$aoa, $cur;
print Dumper $aoa;

# mittel bilden

@$aoa = map { sum(@$_)/scalar(@$_) } @$aoa;
print Dumper $aoa;

__DATA__
12 15 17 13
22 35 11 14
10 25 19 14
32 18 27 25

33 13 13 26
16 42 29 13
61 11 22 14
52 31 17 25
18 14 27 39
\n\n

<!--EDIT|Ronnie|1153824982-->
EagleFox
 2006-07-25 17:52
#68376 #68376
User since
2006-04-10
66 Artikel
BenutzerIn
[default_avatar]
Danke erstmal für die Hilfe.
Ich muss mir erst mal Eure scripte genauer anschauen bevor ich da genau durchsteige, bin noch Anfänger.
@ Ronnie: Also um das mal genau zu spezifizieren.
In den Datensätzen sind experimentelle Daten, sogenante Spektren. Nun habe ich bei einer Messung ganz viele gleiche Spektren aufgenommen und will das Rauschen ausbügeln. Dazu muss ich diese Spektren mitteln. Also, nein, ich will eine Spalte (die pro Datenblock genau ein vollständiges Spektrum darstellt) über alle Datenblöcke mitteln und nicht pro Datenblock den Inhalt einer Spalte!

@Linuxer:
verstehe ich noch nicht so ganz. Wie spreche ich dann die Einzelnen Blöcke an, wenn ich mitteln muss? $_ hat ja immer nur den einen aktuellen Block in sich, oder? Ich muss die Werte ja Zeilenweise zusammenbringen. Also Zeile 1 vom ertsen Block (oder 1001), vom zweiten Block (1002), vom dritten Block (1003), usw.
Wenn ich den Datentrenner auf \n\n setze und dann chomp verwende, löscht mir das dann auch die eine Leerzeile, die dann noch im Array ist? Oder setze ich den Trenner lieber direkt auf \n\n\n (Ich muss ja das \n der letzten Datenzeile vor den beiden Leerzeilen mitnehmen, oder?)?
renee
 2006-07-25 17:54
#68377 #68377
User since
2003-08-04
14371 Artikel
ModeratorIn
[Homepage] [default_avatar]
Kannst Du mal ein paar Beispieldaten posten und daran die Aufgabenstellung etwas verdeutlichen?? Ich bin nämlich noch nicht so schlau aus dem Post geworden...
OTRS-Erweiterungen (http://feature-addons.de/)
Frankfurt Perlmongers (http://frankfurt.pm/)
--

Unterlagen OTRS-Workshop 2012: http://otrs.perl-services.de/workshop.html
Perl-Entwicklung: http://perl-services.de/
EagleFox
 2006-07-25 18:27
#68378 #68378
User since
2006-04-10
66 Artikel
BenutzerIn
[default_avatar]
ok, sorry, wenn ich mich so umständlich augedrückt habe.

Hier mal zwei Beispieldatenblöcke (sehr abgespeckt und mit nur 3 Spalten):

Code: (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
90      0.0247481564832794      0.672855350654247
91 0.0179393727770228 0.681444966159488
92 0.0304371590737797 0.691292629756847
93 0.0262014613090327 0.707479206603499
94 0.0305333702130782 0.724031300019831
95 0.0525632991251114 0.753174235934156
96 0.0574365799673195 0.794255448616359
97 0.0725499384492012 0.862002403540431
98 0.0927733251916131 0.974801235547166
99 0.136405139700346 1.13948111440606
100 0.192932811366311 1.32871785730181
101 0.282688216036466 1.51623138283789
102 0.402239003921947 1.69772068627076
103 0.56223170033369 1.90410025534609
104 0.725195879835909 2.12095396642429
105 0.898628378821595 2.3301273446293
106 1.06479678866679 2.44947735124137
107 1.16128855007647 2.4940882878221
108 1.21569780182376 2.50476895606553
109 1.21221238764562 2.4515395716686
110 1.19329673251675 2.39611029659576
111 1.17089662191081 2.37435290419067
112 1.14373226362788 2.3815580812627
113 1.11578901516974 2.42486864203755
114 1.06435015929128 2.49637082087012
115 1.00034562092867 2.58250417517929
116 0.954443065753162 2.66973255797948
117 0.915476334196782 2.74274046159771
118 0.904779978146295 2.7432554840368
119 0.90319550547491 2.67206644956634
120 0.911481493659881 2.56772951730234
121 0.916122057904484 2.43932314434413
122 0.925537914627349 2.38911927019685
123 0.936541675120858 2.36278928582175
124 0.963713109402471 2.38891696746544
125 0.966531951370864 2.39857714266341
126 0.982539828240094 2.44076306112701
127 0.991482294320707 2.44979151013995
128 1.00955297169011 2.46249347511908
129 1.03094957340561 2.46267885270415
130 1.04648161500776 2.45823473602878
131 1.05535416390104 2.46921643404491
132 1.06569315635946 2.49130427591031
133 1.07159468121726 2.5291475086356
134 1.07912028510846 2.57384860981081
135 1.08705981053296 2.60567236913802
136 1.08282481806786 2.6333280478104
137 1.06636363501865 2.6203406219547
138 1.06971232548074 2.58314395340472
139 1.06595206945007 2.54020150235651
140 1.05167093633685 2.50285287195519
141 1.04831159896809 2.47861301839691
142 1.04295279072632 2.45414115237987
143 1.02967881196966 2.43678222793384
144 1.02169327914388 2.43183224594095
145 1.02236474338473 2.43496801002349
146 1.0154151002411 2.44845986351744
147 1.00792187830782 2.44984457405115
148 0.9946997696284 2.45796598437857
149 0.990358230947281 2.46728574279559
150 0.991467194809884 2.48257865301508


90 0.0230764579156433 0.676198398681967
91 0.0282334103527949 0.684963109911959
92 0.0275317795328473 0.694989480270408
93 0.0301524562700934 0.70796497660355
94 0.037567005927381 0.729267549176281
95 0.0572362219534508 0.763883493442457
96 0.0582805390904889 0.809640812895614
97 0.075263304257001 0.890780994118883
98 0.108891506925485 1.00905369427771
99 0.147240841049655 1.16653132556536
100 0.195302160156675 1.34322978177851
101 0.262093193727629 1.5069645920176
102 0.371295737232743 1.67192059175855
103 0.508710344274156 1.85783092114614
104 0.682465898392946 2.07452836665005
105 0.866283686561771 2.29291650938797
106 1.03502230651316 2.44015318604034
107 1.16711375210265 2.49062665208144
108 1.21104566000203 2.47514492285909
109 1.20435125526391 2.4295443350691
110 1.18483159498592 2.40023828131923
111 1.15496247580961 2.38010006445298
112 1.13254619570817 2.39339009686616
113 1.10697483977195 2.42386083999358
114 1.07391352281015 2.51623670966748
115 1.00710044264407 2.56581236530272
116 0.950053781901314 2.64559980779503
117 0.909336136529518 2.71826047605894
118 0.906566443409401 2.74995321890157
119 0.901341586088408 2.68557734525015
120 0.897227347854775 2.57265341104904
121 0.911345764156694 2.46580587587264
122 0.923485594001276 2.39349331995626
123 0.933030024060488 2.37604762257258
124 0.955182618458814 2.39196314510909
125 0.970733832532778 2.42392329293268
126 0.988949297705822 2.44006585595658
127 0.993766746577445 2.45164564473399
128 1.00786810818989 2.45359823766655
129 1.03335882099798 2.49654177467453
130 1.01361510035665 2.44511687112987
131 1.04816238845352 2.50884639002889
132 1.04715934543243 2.5173430679694
133 1.07423979545642 2.58463373398895
134 1.07074389377746 2.60819502144475
135 1.07252234863156 2.61153051578901
136 1.07038047443981 2.612530219868
137 1.06536850643254 2.58301471806237
138 1.05655796384276 2.52581200890336
139 1.0574800758066 2.4954957626308
140 1.06209990466163 2.46520061751725
141 1.04959161724734 2.44861436747182
142 1.03367068280193 2.42873582532285
143 1.03260380075361 2.44622297724992
144 1.00963196507022 2.43265274994915
145 1.00217488057533 2.44197285388682
146 0.996236076295552 2.4480430163982
147 0.991245188891314 2.45397112001721
148 0.984905933790027 2.45495778637452
149 0.974701438967374 2.47090452887429
150 0.972661350727274 2.48248141355621


Wenn Du nun Spalte zwei vom ersten Datenblock plottest, erhälst Du ein Spektrum, eine experimentelle Datenkurve, einen Grafen, oder wie auch immer wir das nun nennen wollen.
Spalte zwei aus dem zweiten Datenblock enthält das "gleiche" Spektrum...
Bei den Aufnahmen der Daten gibt es immer ein gewisses "Rauschen", oder anders ausgedrückt, die Datenpunkte sind statistischen Schwankungen unterlegen. Das möchte ich herausmitteln, indem ich den ersten Wert des ersten Spektrums mit dem ersten Wert des zweiten Spektrums addiere und dann durch 2 teile (durch 2 teilen weil ich nur über 2 Spektren mittel). Dann möchte ich den zweiten Wert des ersten Spektrums mit dem zweiten Wert des zweiten Spektrums addieren und durch zwei teilen. Dann den dritten Wert des ersten Spektrums mit dem dritten Wert des zweiten Spektrums...usw.

So, nun möchte ich aber nicht nur über zwei Spektren mitteln, sondern z.B. über 50. Damit erhält man dann ein über 50 Spektren gemitteltes Spektrum, welches sehr viel weniger "Rauschen" enthält.

Code: (dl )
1
2
3
4
5
6
7
8
9
1  5.9  10.1
2 7.1 10.2
3 8.8 9.9
4 9.1 10.1

1 6.1 10.3
2 7.3 10.1
3 9.0 9.9
4 9.6 10.3


wird also zu:

Code: (dl )
1
2
3
4
1  6.0  10.2
2 7.2 10.15
3 8.9 9.9
4 9.35 10.2


.. wenn ich die kompletten Zeilen, also nicht nur eine Spalte, mittel.
Ich hoffe das ist jetzt ein kleines bisschen klarer???\n\n

<!--EDIT|EagleFox|1153837885-->
Linuxer
 2006-07-25 22:31
#68379 #68379
User since
2006-01-27
3872 Artikel
HausmeisterIn

user image
Hi EagleFox,

hmm, habe Deinen ersten Beitrag hierzu wohl gelesen, aber nur halb verstanden.
Habe mir auch keine grossen Gedanken um das Mitteln an sich gemacht (also 1.
Zeile jedes Datenblocks miteinander, jede 2., etc.).

Ich würde sagen, vergiss meine erste Variante ;o)
Hier ist ein neuer Lösungsansatz (allerdings setzt der ein paar Annahmen
voraus, die sich aber - glaub ich - recht einfach einrichten lassen):

Hier zunächst mal der Code:

Code: (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
#!/usr/bin/perl
use strict;
use warnings;

my @wert = ();
my $cnt = 0;

# zeilenweise einlesen
while ( <DATA> ) {
# Zeilenumbruch entfernen
chomp;

# ANNAHME: eine (und nur eine) Leerzeile trennt die Datenbloecke
if ( $_ =~ m/^\s*$/ ) {
# also erhoehen wir den Blockzaehler
$cnt++;
}
else {
# ANNAHME: erstes Feld nummeriert das Datenfeld, dann folgen Daten
my ($row, @val) = split();

# wenn fuer Feldnr. noch nichts eingetragen, uebernehme die Daten
# Struktur ist ein Array-of-Array
if ( !exists($wert[$row]) ) {
$wert[$row] = [ @val ];
}
# Wenn Feldnummer schon bekannt, addiere Werte
# ANNAHME: jeder Datenblock enthaelt die gleiche Anzahl Datenzeilen
# und auch jede Feldnr ist entsprechend vorhanden
else {
foreach ( 0 .. $#{$wert[$row]} ) {
$wert[$row]->[$_] += $val[$_];
}
}
}
}
# ANNAHME: der letzte Datenblock endet _nicht_ mit einer Leerzeile!
# ansonsten ist $cnt hinterher um eines zu hoch!
$cnt++;

# Ausgabe gezaehlte Datenbloecke
print "$cnt Datenbloecke", $/;

# fuer jede Datenzeile; Start- und Ende-Wert koennen ja angepasst werden
# oder auch variabel gestaltet werden ( 1000 .. 1050 oder $von .. $bis )
for ( 0 .. $#wert ) {

# undefinierte Werte überspringen; z.B. bei Index 0
next unless defined( $wert[$_] );

# fuer jeden Datenwert
for ( @{$wert[$_]}) {
# berechne das Mittel und uebernehme es
$_ = $_ / $cnt;
}

# gebe die Datenzeile aus
printf( "%6d " . ( "%9.1f " x scalar( @{$wert[$_]} ) ) . "\n", $_, @{$wert[$_]} );
}

__DATA__
1 5.9 10.1
2 7.1 10.2
3 8.8 9.9
4 9.1 10.1

1 6.1 10.3
2 7.3 10.1
3 9.0 9.9
4 9.6 10.3
meine Beiträge: I.d.R. alle Angaben ohne Gewähr und auf Linux abgestimmt!
Die Sprache heisst Perl, nicht PERL. - Bitte Crossposts als solche kenntlich machen!
Ronnie
 2006-07-26 03:10
#68380 #68380
User since
2003-08-14
2022 Artikel
BenutzerIn
[default_avatar]
Ich habe mal angenommen das die erste Spalte eine fortlaufenden steigende Nummer ist, aber so sollte es funktionieren:
Code: (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#!/usr/bin/perl

use strict;
use warnings;

my %set;
my $set_cnt = 1;
my $line_cnt = 0;

while (<DATA>) {
chomp;

++$line_cnt and next if /^\s*$/;
if ($line_cnt == 2) { $line_cnt = 0; $set_cnt++ }

my ($n, @m) = split /\s+/;
$set{$n}->[$_] += $m[$_] for 0 .. $#m;
}

foreach my $k (sort { $a <=> $b } keys %set) {
print $k, "\t";
print $_/$set_cnt, "\t" for @{$set{$k}};
print "\n";
}


__DATA__
90 0.0247481564832794 0.672855350654247
91 0.0179393727770228 0.681444966159488
92 0.0304371590737797 0.691292629756847
93 0.0262014613090327 0.707479206603499
94 0.0305333702130782 0.724031300019831
95 0.0525632991251114 0.753174235934156


90 0.0230764579156433 0.676198398681967
91 0.0282334103527949 0.684963109911959
92 0.0275317795328473 0.694989480270408
93 0.0301524562700934 0.70796497660355
94 0.037567005927381 0.729267549176281
95 0.0572362219534508 0.763883493442457
\n\n

<!--EDIT|Ronnie|1153869110-->
EagleFox
 2006-07-26 12:45
#68381 #68381
User since
2006-04-10
66 Artikel
BenutzerIn
[default_avatar]
Guten Morgen zusammen!
Vielen tausend Dank für Eure Mühen, Ihr seid echt riesig!
Eure beiden Scripte sind, soweit ich das beurteilen kann und verstanden habe, ja relativ ähnlich. Ich habe mal versucht das in ein Programm für meine Anwendung zu integrieren.

@Linuxer:
Leider kann ich nicht ganz vorraussehen was mit Deinem Code (der mal echt genial kommentiert ist!!!) passiert, aber die Datenblöcke haben NICHT alle die gleiche Größe. Die Variation beträgt aber nur +- 2 Zeilen. Wahrscheinlich passiert das selbe wie mit Ronnies code: die letzten Werte gehen natürlich voll in den Keller, weil ja nicht genausoviele Werte addiert wurden, wie bei den anderen Zeilen, aber durch genau die gleiche Anzahl geteilt wird.

Hier mal mein wahrscheinlich dilettantischer code:

Code: (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
#! /usr/bin/perl
# mittelt mehrere Spektren einer Datei
# Erstes Spektrum ist SPEKTRUMNUMMER
# gemittelt wird ueber ANZAHL folgende Spektren
# HOWTO: ./avg.pl DATEI SPEKTRUMNUMMER ANZAHL

use strict;
use warnings;
use Term::ANSIColor qw(:constants);

if(!defined $ARGV[0]){
printf "\nAus welcher Datei soll gemittelt werden?\n";
$ARGV[0] = <STDIN>;
chomp $ARGV[0];
}

if(!defined $ARGV[1]){
printf "\nWelcher Spektrenblock soll gemittelt werden?\n";
printf BLUE "Anfang:\t";
printf CLEAR;
$ARGV[1] = <STDIN>;
chomp $ARGV[1];
}

if(!defined $ARGV[2]){
printf "\nUeber wieviele Spektren sollen gemittelt werden?\n";
printf BLUE"Anzahl:\t";
printf CLEAR;
$ARGV[2] = <STDIN>;
chomp $ARGV[2];
}


my $file = $ARGV[0];
my $anfang = $ARGV[1];
my $ende = $ARGV[1] + $ARGV[2];

my ($in,$suffix) = $ARGV[0] =~ /(.*?)(\.[^\.]+)$/;
my $out = $in.'.avg'.$ende.'.dat';


open(my $daten,"<",$file) or die $!;
open(my $avg,">",$out) or die $!;

my $data;
my $block = 0;
my %set;
my $set_cnt = 0;

while(do {local $/="\n\n\n";defined($data = <$daten>)}){
chomp $data;

if($block > $anfang && $block < $ende){
my ($n, @m) = split (/\s+/,$data);
$set{$n}->[$_] += $m[$_] for 0 .. $#m;
$set_cnt++;
}

$block++;
}

foreach my $k (sort { $a <=> $b } keys %set) {
print $avg $k, "\t";
print $avg $_/$set_cnt, "\t" for @{$set{$k}};
print $avg "\n";
}


close $avg;
close $file;


Das Programm läuft und das Ergebnis ist super! Bis auf die letzten (variierenden) Zeilen. Macht aber nichts, die letzten Werte kann ich ja im Plot abschneiden. (oder mir bei Gelegenheit überlegen, wie ich das Problem mit dem Teilen anders in den Griff bekomme.)
Ich danke Euch!
<< >> 9 Einträge, 1 Seite



View all threads created 2006-07-25 14:04.