• ベストアンサー
※ ChatGPTを利用し、要約された質問です(原文:複数のデータの内、0以上の値のセル1/4個分の合計)

データの一部の合計を計算する方法についての質問

このQ&Aのポイント
  • 複数のデータの内、0以上の値を示すいくつかのセルの上1/4個分の合計を計算する方法について教えてください。
  • 具体的な説明として、A列に37個のデータがあり、値が0以上のセルはA7からA27までの21個です。上1/4個分のセルの合計を求める式は、A7+A8+A9+A10+A11+(A12*0.25)です。
  • しかし、実際には72列あり、それぞれの列で値が0以上のセルの数は異なります。良い方法があれば教えてください。

質問者が選んだベストアンサー

  • ベストアンサー
回答No.7

念のための確認ですが、四分位数なら QUARTILE 関数というのがあるのですが、そうではなくて、個数で 1/4 だけ合計ということでいいのですね? 0 以上ではなく、「0 より大きい」あるいは「正の数(正数)」ということですね。データ処理するときは文学的な表現でなく、数学の言い回しをなるべく使うよう心がけましょう。今回は図もあって明白なので意味は通じますが、紛れが生じる場合も多々あるかと思います。 D1 =countif(a:a,">0")/4 D2 =min(index(row(a1:a1000)+10^15*(a1:a1000<=0),)) D3 =if(d1>=1,sum(offset(a1,d2-1,0,int(d1),1)),)+mod(d1,1)*offset(a1,int(d1)+d2-1,0) データ量が 1,000 行を超えるときは、2 箇所の「a1000」を必要な行数に合わせてください。D1:D3 の数式を A1002:1004 とか別シートに入力しても構いません。別シートの場合は数式中に「sheet1!」などの追記が必要になりますが。「10^15」というのは、Excel が扱える最大の数値ということです。「+10^15*(a1:a1000<=0)」というのは、0 以下の行だけ 10^15 を足すという意味です。D2 セルでは配列を使っていますが、INDEX を混ぜているので、Ctrl+Shift+Enter の操作は不要です。IF で場合分けしているのは、D1 がゼロのときに OFFSET の第 4 引数もゼロになることによりエラーが発生するのを回避するための措置です。

goseinaito
質問者

お礼

『四分位数なら QUARTILE 関数というのがあるのですが、そうではなくて、個数で 1/4 だけ合計ということでいい』 『「0 より大きい」あるいは「正の数(正数)」』 これらの補足ありがとうございます。気がつきませんでした。 ご提示いただきました関数で、結果をだすことができました。 理解できたのは、D1の関数だけでしたが…。 ありがとうございました。

その他の回答 (8)

回答No.9

>理解できたのは、D1の関数だけでしたが…。 難しすぎて、すみません。なかなか全てを理解してもらうには、知っていただかないといけない要素が多くてたいへんかもしれませんが、回答を読んでいて、もしも何か追加のご質問でもありましたら、こちらで分かることは何でもお答えします。こういう QA サイトの本当の使い方は質問・回答なのであって、作業を人に手伝ってもらうことではないのですから…。

goseinaito
質問者

お礼

『もしも何か追加のご質問でもありましたら、こちらで分かることは何でもお答えします。』 あたたかいお言葉、心にしみました。 『こういう QA サイトの本当の使い方は質問・回答なのであって、作業を人に手伝ってもらうことではないのですから…。』 理解できるまで勉強して、それでもわからなかったら、「自分の理解を深めるために」QAサイトを頼ろうと思います。 うまく文字で表現できませんが、大きな何かをいただいた気がします。 ありがとうございました。

  • tom04
  • ベストアンサー率49% (2537/5117)
回答No.8

No.3です! 解決しているようですが・・・関数で無理やりやってみました。 とりあえず40行までの数式です。 A列の41行目以降のセルに =SUM(INDIRECT(ADDRESS(MIN(IF(A1:A40>0,ROW(A1:A40))),COLUMN())&":"&ADDRESS(SMALL(IF(A1:A40>0,ROW(A1:A40)),INT(COUNTIF(A1:A40,">0")/4)),COLUMN())))+INDIRECT(ADDRESS(SMALL(IF(A1:A40>0,ROW(A1:A40)),CEILING(COUNTIF(A1:A40,">0")/4,1)),COLUMN()))*MOD(COUNTIF(A1:A40,">0")/4,1) これは配列数式になってしまいますので、Shift+Ctrl+Enterで確定! この画面から数式をコピー&ペーストする場合は、 上記数式をコピー → 貼り付けたいセル(A41以降)を選択 → 数式バーを一度クリック → 貼り付け → そのまま(編集可能のまま)Shift+Ctrlキーを押しながらEnterキーで確定! 数式の前後に{ }マークが入り配列数式になります。 これを列方向にオートフィルでコピーしてみてください。 尚、「0より大きい」データ数が4個未満の場合はエラーとなります。 ※ 「0より大きい」データが連続していなくても対応できるようにしてみました。m(_ _)m

goseinaito
質問者

お礼

『この画面から数式をコピー&ペーストする場合は、 上記数式をコピー → 貼り付けたいセル(A41以降)を選択 → 数式バーを一度クリック → 貼り付け → そのまま(編集可能のまま)Shift+Ctrlキーを押しながらEnterキーで確定! 数式の前後に{ }マークが入り配列数式になります。』 具体的なご説明で作業がわかりやすく、すぐできました。 ありがとうございました。

  • tsubuyuki
  • ベストアンサー率45% (699/1545)
回答No.6

#5さんの式に、なるほどと感心しつつ。 とりあえず「解決したのかしていないのか」 あるいは「回答を理解できたのか出来なかったのか」 教えて頂けませんか? 実は「お礼」にはあまりこだわっておりません。 質問者さんが「質問をどのように解決したか」の方が気になります。 そんなわけで、マクロ編です。 例えば、 Sub Sample() Dim XVal As Long, YVal As Long, Zval As Double Dim myCount As Long, myVal As Double Dim myRow As Long, myCol As Long     For myCol = 1 To Cells(1, Columns.Count).End(xlToLeft).Column         XVal = Application.CountIf(Range(Cells(1, myCol), Cells(1, myCol).End(xlDown)), ">0")         YVal = Int(XVal / 4)         Zval = XVal / 4 - YVal         myCount = 0: myVal = 0         For myRow = 1 To Cells(1, myCol).End(xlDown).Row             If Cells(myRow, myCol) > 0 Then                 myVal = myVal + Cells(myRow, myCol)                 myCount = myCount + 1                 If myCount >= YVal Then                     myVal = myVal + Cells(myRow + 1, myCol) * Zval                     Exit For                 End If             End If         Next myRow         Cells(40, myCol) = myVal     Next myCol End Sub これを走らせると、40行目に結果を表示します。 ユーザー定義関数にすると Function mySumIf(myrange As Range, myInd As Long) As Double Dim XVal As Long, YVal As Long, Zval As Double Dim myCount As Long, myVal As Double Dim myRow As Long     XVal = Application.CountIf(myrange, ">0")     YVal = Int(XVal / myInd)     Zval = XVal / myInd - YVal     For myRow = 1 To myrange.Count         If Cells(myRow, myrange.Column) > 0 Then             myVal = myVal + Cells(myRow, myrange.Column)             myCount = myCount + 1             If myCount >= YVal Then                 myVal = myVal + Cells(myRow + 1, myrange.Column) * Zval                 Exit For             End If         End If     Next myRow     mySumIf = myVal End Function これを標準モジュールに貼り付けると、 ワークシート上で   =mySumIf(A1:A37,4) などのように使えます。 後ろの「,4」は > このうち、上1/4個分のセルの合計を出したいです。 の「4」です。5でも10でも指定できます。 多分、もっと良い書き方はあるはずですが、参考までに。

goseinaito
質問者

お礼

表面的ですが、おかげさまで解決しました。 理解のほどは、と言いますと、ほぼ困難です。 (私が、マクロを日常的に使えていないせいです。) 具体的には、 『そんなわけで、マクロ編です。 例えば、~これを走らせると、40行目に結果を表示します。』 の部分は、コピーペーストで、解を得ることができました。 『ユーザー定義関数にすると~5でも10でも指定できます。』 の部分は、コピーペーストすらできませんでした。 (私自信、どこがどう理解できているのかもよくわかっていないせいです。) 少しずつでも理解しないと、自立に結びつかないです。 がんばります! ご教授ありがとうございました。

  • keithin
  • ベストアンサー率66% (5278/7941)
回答No.5

簡単のためセルを分けて計算しますが、その気になれば一個に詰め込んでも出来ます。お勧めはしませんが。 A38に =IF(A40,IFERROR(SUM(OFFSET(A1,A39-1,0,INT(A40),1)),0)+INDEX(A1:A37,A39+A40)*MOD(A40,1),"") A39に =IF(A40,MIN(IF(A1:A37>0,ROW(A1:A37))),"") 必ずコントロールキーとシフトキーを押しながらEnterで入力 A40に =COUNTIF(A1:A37,">0")/4 #補足 ゼロより大きい数字セルは「必ず連続している」とします #参考 ゼロより大きい数字セルが4個未満しかなかった場合の処置がお話をちょっとややこしくしています

goseinaito
質問者

お礼

『A38に =IF(A40,IFERROR(SUM(OFFSET(A1,A39-1,0,INT(A40),1)),0)+INDEX(A1:A37,A39+A40)*MOD(A40,1),"") 』 この部分は、お示しいただいた関数をコピーペーストしました。 IFERROR、OFFSET、INT、MODは、私にとってなじみのない関数で、理解するのに時間がかかりそうですが、これらの関数が理解できるよう、がんばってみます。 『A39に =IF(A40,MIN(IF(A1:A37>0,ROW(A1:A37))),"") 必ずコントロールキーとシフトキーを押しながらEnterで入力』 この部分の注意書きの意味を理解するのは、時間がかかりそうです。ROW関数の理解も時間がかかりそうです。 『A40に =COUNTIF(A1:A37,">0")/4』 この関数は、すぐに理解できました。 私の理解の程度は、上記のような状況です。 そのため、A40に出てきた値が5.25となりました。 お示しいただいたご回答を、活用できるよう、時間をかけてみます。 また、補足や参考を加筆いただき、ありがとうございました。 加筆していただいた内容が、お示しいただいた関数とどのように関係しているのか理解するのには、時間がかかりそうですが、一つずつ、解決したいです。 ありがとうございました。

  • tom04
  • ベストアンサー率49% (2537/5117)
回答No.4

No.3です! たびたびごめんなさい。 前回のコードで1行訂正してください。 最後の方の >Do Until Cells(n, j) > 0 を >Do Until wS1.Cells(n, j) > 0 のようにしてください。 ※ Sheetを指定していなかったので、Sheet2がアクティブな状態でマクロを実行すると エラーになってしまいます。 尚、前回書き忘れたのですが、Sheet1の1行目で最終列を取得していますので、 元データは1行目からあり、何らかのデータが入っているという前提のコードです。m(_ _)m

goseinaito
質問者

お礼

ありがとうございました。

  • tom04
  • ベストアンサー率49% (2537/5117)
回答No.3

こんばんは! 何とか関数で!と頑張ってみたのですが・・・ギブアップです。 >0以上の値を示すいくつかのセル・・・ とありますが、画像を拝見すると「0より大きい」セルのようですので、 0より大きいセルを対象としています。 VBAでやってみました。 Sheet1(お示しの画像)のデータをSheet2の1行目に表示するようにしています。 Alt+F11キー → メニュー → 挿入 → 標準モジュール → VBE画面に ↓のコードをコピー&ペーストしてマクロを実行してみてください。 (Alt+F8キー → マクロ → マクロ実行です) Sub Sample1() 'この行から Dim i As Long, j As Long, endCol As Long, n As Long, cnt As Long, wS1 As Worksheet, wS2 As Worksheet Set wS1 = Worksheets("Sheet1") Set wS2 = Worksheets("Sheet2") Application.ScreenUpdating = False wS2.Cells.ClearContents endCol = wS1.Cells(1, Columns.Count).End(xlToLeft).Column With wS2.Cells(2, 1).Resize(1, endCol) .Formula = "=INT(COUNTIF(Sheet1!A:A,"">0"")/4)" .Value = .Value End With With wS2.Cells(3, 1).Resize(1, endCol) .Formula = "=MOD(COUNTIF(Sheet1!A:A,"">0"")/4,1)" .Value = .Value End With For j = 1 To endCol cnt = 0 For i = 1 To wS1.Cells(Rows.Count, j).End(xlUp).Row If wS1.Cells(i, j) > 0 Then cnt = cnt + 1 wS2.Cells(1, j) = wS2.Cells(1, j) + wS1.Cells(i, j) End If If cnt = wS2.Cells(2, j) Then Exit For End If Next i n = i + 1 If wS1.Cells(n, j) <= 0 Then Do Until Cells(n, j) > 0 n = n + 1 Loop End If wS2.Cells(1, j) = wS2.Cells(1, j) + wS1.Cells(n, j) * wS2.Cells(3, j) Next j wS2.Rows(2 & ":" & 3).Clear Application.ScreenUpdating = True End Sub 'この行まで ※ 関数で簡単にできる方法があればごめんなさいね。m(_ _)m

goseinaito
質問者

お礼

ありがとうございました。

  • tsubuyuki
  • ベストアンサー率45% (699/1545)
回答No.2

添付忘れました。 重ねて、すいません。

goseinaito
質問者

お礼

丁寧なご返答ありがとうございました。

  • tsubuyuki
  • ベストアンサー率45% (699/1545)
回答No.1

すいません、作業列を使うやり方しか思いつかなかった上に、 非常に効率が悪い式になってしまいました。 でも、なんとなく勿体無いので、 =IF(AND(A1>0,COUNTIF($A$1:$A$37,">0")/4>=COUNTIF(A$1:A1,">0")),A1,IF(COUNTIF(A$1:A1,">0")=ROUNDUP(COUNTIF($A$1:$A$37,">0")/4,0),A1*(COUNTIF($A$1:$A$37,">0")/4-INT(COUNTIF($A$1:$A$37,">0")/4)),"")) これをB列に貼り付けてフィルしたものが添付図です。 あとはこのB列に対してSUMしてやれば合計がでます。 マクロを使えばあるいは・・なんですが・・・ すいません、賢人の登場をお待ち下さいませ。

goseinaito
質問者

お礼

ありがとうございました。

関連するQ&A