Chinaunix

标题: 怎么对文本中的数字进行分组然后运算 [打印本页]

作者: wpd0508    时间: 2014-06-25 09:30
标题: 怎么对文本中的数字进行分组然后运算
比如在a文件中有1 2 4 5 6 13 141 3 11 13 44 11 这12个数,我以5个为一组,进行一种运算得到一个数,最后2个数为一组,然后将得到的3个数进行求平均数的运算。
作者: Herowinter    时间: 2014-06-25 09:32
回复 1# wpd0508
一种运算指?
+-*/?或其他更复杂的运算或某个已实现好的函数f()?
   
作者: 关阴月飞    时间: 2014-06-25 09:37
1.文件中的数字是一行一个吗?
2.五个一组做什么运算?
作者: wpd0508    时间: 2014-06-25 09:41
不是一行一个,是和正常的文一样以空格为分隔符,
运算的话就是
awk '{
        a[NR] = $1
        s += $1
}
END{
        n =NR
        avg = s / n
        for(x=1; x<=n; x++)
        {
                y = a[x] - avg
                sx += x
                sy += y
                sxy += x * y
                sx2 += x * x
        }
        a0 = (sx2 * sy - sx * sxy) / (n * sx2 - sx * sx)
        a1 = (n * sxy - sx * sy) / (n * sx2 - sx * sx)
        printf "y = %s + %sx\n" ,a0 ,a1
}' test4回复 3# 关阴月飞


   
作者: wpd0508    时间: 2014-06-25 09:46
E = sqrt( sum (Yi - (a1*x+a0) )^2)最后每5个数得到一个E 然后进行求E的平均数运算

作者: zerostudy    时间: 2014-06-25 10:03

echo "1 2 4 5 6 13 141 3 11 13 44 11" | xargs -n 5 | awk

楼主,你看下如何把你的代码放上去
作者: 关阴月飞    时间: 2014-06-25 10:03
回复 4# wpd0508
    不是一行一个,是和正常的文一样以空格为分隔符,
运算的话就是
awk '{
        a[NR] = $1
        s += $1
}
END{
        n =NR
        avg = s / n
        for(x=1; x<=n; x++)
        {
                y = a[x] - avg
                sx += x
                sy += y
                sxy += x * y
                sx2 += x * x
        }
        a0 = (sx2 * sy - sx * sxy) / (n * sx2 - sx * sx)
        a1 = (n * sxy - sx * sy) / (n * sx2 - sx * sx)
        printf "y = %s + %sx\n" ,a0 ,a1
}' test4

意思是只要把五个数传给这个处理程序就好了是吗?

那只要把后面的test4文件处理一下:
xargs -n5 test4 |awk 'xxoo'

作者: Herowinter    时间: 2014-06-25 10:04
本帖最后由 Herowinter 于 2014-06-25 10:06 编辑

回复 5# wpd0508
你上面写的那程序应该是论坛一个大神帮你实现的用
最小2乘法求线性关系y=a1*x+a0的两个系数a0,a1,
但你现在没封装成函数,怎么调用?另外,
数学基础不好,你现在这个求E的公式中Yi,x分别表示
什么具体数据?

   
作者: LikeLx    时间: 2014-06-25 10:05
回复 8# Herowinter
你的积分也这么嗨皮了

   
作者: Herowinter    时间: 2014-06-25 10:08
回复 9# LikeLx
必须的,世界杯期间不瘦身怎么跟得上节奏?

   
作者: Herowinter    时间: 2014-06-25 10:19
翻了楼主的另一个帖子,找到计算E的这些参数的意义了。
  1. 如果我想要继续对得到的数据进行处理,比如说对以上得到的数组 [ Yi ]  以L个为单元进行分组, 即第一组为 [  Y1 Y2 Y3 ... YL].    对这L个数字进行最小二乘法拟合,得 Y=a1 x + a0, (这里的x为数组对应的下标数,即1~ L).
  2. 计算偏差量  E = sqrt( sum (Yi - (a1*xi +a0) )^2)这就很麻烦了是不是?能帮忙解决一下吗?
复制代码

作者: LikeLx    时间: 2014-06-25 10:24
回复 10# Herowinter
你瘦的不够彻底啊,你看我,完美身材

   
作者: Herowinter    时间: 2014-06-25 12:02
本帖最后由 Herowinter 于 2014-06-25 12:55 编辑

回复 1# wpd0508
不知道结果对不对,有错请指出,把大神提供的最小2乘法封装了下,
用来求数组a中a[1],..a[n]对应的系数a0,a1
  1. #!/bin/bash

  2. awk -vl=5 '
  3.     function least_square(a,n,a0,a1){
  4.         for(x=1;x<=n;x++)
  5.             s += a[x];
  6.         avg = s/n;
  7.         for(x=1; x<=n; x++)
  8.         {
  9.                 y = a[x] - avg
  10.                 sx += x
  11.                 sy += y
  12.                 sxy += x * y
  13.                 sx2 += x * x
  14.         }
  15.         a0 = (sx2 * sy - sx * sxy) / (n * sx2 - sx * sx)
  16.         a1 = (n * sxy - sx * sy) / (n * sx2 - sx * sx)
  17.     }
  18.       
  19.     {
  20.       sum = 0
  21.       count = 0
  22.       k = 0
  23.       for(i=1;i<=NF;i++){
  24.          a[++count]=$i
  25.          if(count==l){
  26.              least_square(a,l,a0,a1);
  27.              sum=0;
  28.              count=0;
  29.              for(j=1;j<=l;j++){
  30.                  sum += a[j]-(a1*j+a0)^2
  31.              }
  32.              E[++k]=sqrt(sum);
  33.             
  34.          }
  35.       }
  36.       if(count>0){
  37.           least_square(a,count,a0,a1);
  38.           sum=0;
  39.           for(j=1;j<=count;j++){
  40.                  sum += a[j]-(a1*j+a0)^2
  41.              }
  42.           E[++k]=sqrt(sum);
  43.       }
  44.       sum=0;
  45.       for(i in E)
  46.           sum += E[i]
  47.       print sum/k
  48.     }
  49.    
  50.    ' i
复制代码
  1. cat i
  2. 1 2 4 5 6 13 141 3 11 13 44 11
  3. 1 2 4 5 6 7 8 9 10
复制代码
结果
  1. ./test.sh
  2. 8.37082
  3. 8.7449
复制代码

作者: wpd0508    时间: 2014-06-25 12:42
大大,非常感谢你教我了在LINUX里如何封装函数,sum += a[j]-(a1*j+a0) 这里少了一个平方,还有就是为什么得到的是a1,a0,而不是E的平均数吗?回复 13# Herowinter


   
作者: Herowinter    时间: 2014-06-25 12:57
本帖最后由 Herowinter 于 2014-06-25 13:06 编辑

回复 14# wpd0508
13楼的代码我改了,加了平方,但是计算结果没影响。。。
不知到哪里有问题。按照你的需求,要先算出a0,a1才能代入
公式计算E的吧,我这里最后打印的就是每行的所有E的平均值。

有个数学知识请教下,我输入Y=[1,2,3,4,5],最小2乘法算出来的
不是a1=1,a0=0,Y=x吗?
   
作者: wpd0508    时间: 2014-06-25 13:03
如果a1=1,a0=1 ,Y=1+x大大还有就是awk 'BEGIN{getline t < "b"}{for(i=0;i++<NFprintf ( "%d\n",i,X=X[i-1]+$i-t)>c}' a  这个代码能产生的数是以一行1个数的形式放入文件c中的,如何改为以空格为分隔符放入文件c中呢
回复 15# Herowinter


   
作者: Herowinter    时间: 2014-06-25 13:09
回复 16# wpd0508
上面我写错是a1=1,a0=0,你的原始文本不是1行
10几个数吗?怎么又变成1行1个了。。。,你重新
描述需求吧,输入数据格式,期望结果。
   
作者: wpd0508    时间: 2014-06-25 13:59
对的,我是想让你帮我看看另外一个问题,
cat test2
1 3 3 5 4 2
test3
3
awk 'BEGIN{getline t < "test3"}{for(i=0;i++<NFprintf ("X%d=%d\n",i,X=X[i-1]+$i-t)> "test4"}' test2
X1=-2
X2=-2
X3=-2
X4=0
X5=1
X6=0
如何将-2 -2 -2 0 1 0 这几个数以这种形式放入test4 ,前面提到的问题就是从这一步开始的。回复 17# Herowinter


   
作者: Herowinter    时间: 2014-06-25 14:11
本帖最后由 Herowinter 于 2014-06-25 14:14 编辑

回复 18# wpd0508
你从test2 => test4 仅仅是为了把
1 2 3 4 5变为

1
2
3
4
5  ???
我是有点被你搞糊涂了,我13楼的代码不需要这种转换,
你直接把里面的文件名改为test2应该可以的。

还有,想要得到正确的结果,必须要保证你提供的最小2乘法
算法能计算出正确的a0,a1,为什么我输入5个点(1,1)  (2,2)
(3,3)  (4,4)  (5,5),计算的结果不是a0=0,a1=1,  y=x呢?


   
作者: ly5066113    时间: 2014-06-25 14:12
回复 15# Herowinter


把 y = a[x] - avg 改为
y = a[x]
就是你想要的结果了。

楼主原来的需求里是把样本数据减去均值后的数据作为样本的,所以我的代码里减去了均值。
作者: Herowinter    时间: 2014-06-25 14:26
本帖最后由 Herowinter 于 2014-06-25 14:38 编辑

回复 20# ly5066113
多谢大神指点,现在(i i) i=1,2,...5,得到的结果是y=x了。
  1. #!/bin/bash

  2. awk -vl=5 '
  3.     function least_square(a,n,a0,a1){
  4.         s=0;sx=0;sy=0;sxy=0;sx2=0;
  5.         for(x=1;x<=n;x++)
  6.             s += a[x];
  7.         avg = s/n;
  8.         for(x=1; x<=n; x++)
  9.         {
  10.                 y = a[x]
  11.                 sx += x
  12.                 sy += y
  13.                 sxy += x * y
  14.                 sx2 += x * x
  15.         }
  16.         a0 = (sx2 * sy - sx * sxy) / (n * sx2 - sx * sx)
  17.         a1 = (n * sxy - sx * sy) / (n * sx2 - sx * sx)
  18.         printf "###y = %s + %sx\n" ,a0 ,a1
  19.     }
  20.       
  21.     {
  22.       sum = 0
  23.       count = 0
  24.       k = 0
  25.       for(i=1;i<=NF;i++){
  26.          a[++count]=$i
  27.          if(count==l){
  28.              least_square(a,l,a0,a1);
  29.              sum=0;
  30.              count=0;
  31.              for(j=1;j<=l;j++){
  32.                  sum += a[j]-(a1*j+a0)^2
  33.              }
  34.              E[++k]=sqrt(sum);
  35.             
  36.          }
  37.       }
  38.       if(count>0){
  39.           least_square(a,count,a0,a1);
  40.           sum=0;
  41.           for(j=1;j<=count;j++){
  42.                  sum += a[j]-(a1*j+a0)^2
  43.              }
  44.           E[++k]=sqrt(sum);
  45.       }
  46.       sum=0;
  47.       for(i=1;i<=k;i++)
  48.           sum += E[i]
  49.       print sum/k
  50.     }
  51.    
  52.    ' test2
复制代码
  1. ./test.sh
  2. ###y = -0.3 + 1.3x
  3. ###y = 75.2 + -13x
  4. ###y = 77 + -33x
  5. 8.37082
  6. ###y = 0 + 1x
  7. 3.872988
复制代码
  1. cat test2
  2. 1 2 4 5 6 13 141 3 11 13 44 11
  3. 1 2 3 4 5
复制代码

作者: wpd0508    时间: 2014-06-25 15:02
是为了将1 3 3 5 4 2  先求均值,然后求出与均值的偏差X1,X2,X3,X4,X5,X6,最后累加 Y1=X1 ,Y2=Y1+X2,...但是我用awk 'BEGIN{getline t < "test3"}{for(i=0;i++<NFprintf ("X%d=%d\n",i,Y=Y[i-1]+$i-t) > "test4"}' test2得到的是
Y1=-2
Y2=-2



这样的形式,而我想的是将-2  -2  1  。以这种形式放入test4中,然后进行最小二乘法回复 19# Herowinter [/

   
作者: wpd0508    时间: 2014-06-25 15:11
解决了 ,我去原来/N在shell中也表示换行,,
我真是愚,谢谢各位大大们这几天的帮忙。。 回复 22# wpd0508


   
作者: wpd0508    时间: 2014-06-25 15:11
解决了 ,我去原来/N在shell中也表示换行,,
我真是愚,谢谢各位大大们这几天的帮忙。。 回复 22# wpd0508


   
作者: Herowinter    时间: 2014-06-25 15:32
回复 22# wpd0508
  1. [masonzhu@rat122 zzz]$ awk 'BEGIN{getline t < "test3"}{for(i=1;i<=NF;i++){Y[i]=Y[i-1]+$i-t;s=s?s" "Y[i]:Y[i]};print s > "test4"}' test2
  2. [masonzhu@rat122 zzz]$ cat test4
  3. -2 -2 -2 0 1 0

  4. [masonzhu@rat122 zzz]$ cat test2
  5. 1 3 3 5 4 2
  6. [masonzhu@rat122 zzz]$ cat test3
  7. 3
复制代码





欢迎光临 Chinaunix (http://bbs.chinaunix.net/) Powered by Discuz! X3.2