質問するログイン新規登録
Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

1回答

517閲覧

最大2×2のデータを対角状にたくさん並べたい

yyicp

総合スコア82

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

1グッド

2クリップ

投稿2025/07/31 03:06

編集2025/07/31 04:32

1

2

実現したいこと

sample10.txtは以下のようなファイルです。
4
0
0
13

sample20.txtは以下のようなファイルです。
5
0
0
8

5
0
1
4

5
1
1
1

sample30.txtは以下のようなファイルです。
6
0
0
5

6
1
0
8

各塊は、
x座標
y座標
z座標

の順番に並んでいます。

このデータを以下の図のようなデータにしたいです。
イメージ説明
対角状に並べるデータのサイズは最大で2×2です。(1×1、1×2、2×1、2×2があり得ます)

一応できたのですが、14~27行目は似たような内容を書いています。
今はsample10.txt、sample20.txt、sample30.txtの3つのファイルですが、もっとファイルの個数が多くなることを想定しています。ファイルの個数が多くなったときには、コードをどのように直したら良いでしょうか。

該当のソースコード

python

1import numpy as np 2import pandas as pd 3from scipy.linalg import block_diag 4 5cols = 2 6rows = 2 7R10 = np.arange(rows*cols,dtype=np.float32).reshape(rows,cols) 8R10[...] = 0 9R20 = np.arange(rows*cols,dtype=np.float32).reshape(rows,cols) 10R20[...] = 0 11R30 = np.arange(rows*cols,dtype=np.float32).reshape(rows,cols) 12R30[...] = 0 13 14with open('sample10.txt') as f: 15 blocks = f.read().split('\n\n') 16R10[0][0] = int(blocks[0].split('\n')[3]) 17 18with open('sample20.txt') as f: 19 blocks = f.read().split('\n\n') 20R20[0][0] = int(blocks[0].split('\n')[3]) 21R20[0][1] = int(blocks[1].split('\n')[3]) 22R20[1][1] = int(blocks[2].split('\n')[3]) 23 24with open('sample30.txt') as f: 25 blocks = f.read().split('\n\n') 26R30[0][0] = int(blocks[0].split('\n')[3]) 27R30[1][0] = int(blocks[1].split('\n')[3]) 28 29A = block_diag(R10, R20, R30) 30print(A) 31#[[13. 0. 0. 0. 0. 0.] 32# [ 0. 0. 0. 0. 0. 0.] 33# [ 0. 0. 8. 4. 0. 0.] 34# [ 0. 0. 0. 1. 0. 0.] 35# [ 0. 0. 0. 0. 5. 0.] 36# [ 0. 0. 0. 0. 8. 0.]] 37 38A = A[np.ix_(~np.all(A == 0, axis=1), ~np.all(A == 0, axis=0))] 39print(A) 40#[[13. 0. 0. 0.] 41# [ 0. 8. 4. 0.] 42# [ 0. 0. 1. 0.] 43# [ 0. 0. 0. 5.] 44# [ 0. 0. 0. 8.]]

試したこと

データファイルを1個のフォルダの中にまとめて保存し、その中のファイルについて14~27行目のような操作をすれば良いのではないかと考えています。あるいは、ファイル名を関数の変数にすれば良いかなと思っています。(やり方が分かりませんでした)

sample10.txt、sample20.txt、sample30.txtの行数を調べると、

python

1nl = len(open('sample10.txt').readlines()) 2print(nl)#4 3nl = len(open('sample20.txt').readlines()) 4print(nl)#14 5nl = len(open('sample30.txt').readlines()) 6print(nl)#9

なので、14、18、24行目の場合分けは、ファイルの行数で行えば良いかなと思っています。

melian👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

TakaiY

2025/07/31 03:56 編集

質問の説明の意味がわからないのはぼくだけだろうか。 各塊は、 x座標 y座標 z座標 値 のような構成で、 ファイルにはたとえば、 4 0 0 13 とあるので、これが対応しているのだろうと思います。 で、(x, y, z) = (4, 0, 0)の値が13なので、 表の(y, z) = (0, 0) のところが13になっているのでいいのですが、 5 0 0 8 この8は、どこにあるものですか? あと、xはどこにいった? また、「対角状に並べるデータのサイズは最大で2×2です。」の意味もわかりません。何をどこに対角状にならべるのでしょう。
yyicp

2025/07/31 04:33

>TakaiY様 コメントありがとうございます。 説明が分かりづらくて申し訳ありません。図を直しましたので、ご確認ください。
TakaiY

2025/07/31 04:50

そういうことだしたか。理解できました。 ありがとうございます。
guest

回答1

0

ベストアンサー

numpy.loadtxt で読み込んで、4列の2次元配列(shape (-1, 4))に変換するとよいかと思います。

python

1import numpy as np 2import pandas as pd 3from scipy.linalg import block_diag 4 5data_files = ['sample10.txt', 'sample20.txt', 'sample30.txt'] 6R = [] 7for f in data_files: 8 data = np.zeros((2, 2)) 9 # 4行ごとに分割(空行はスキップされる) 10 for blk in np.loadtxt(f).reshape((-1, 4)): 11 data[*blk[1:3].astype(int)] = blk[3] 12 R.append(data) 13 14A = block_diag(*R) 15print(A) 16#[[13. 0. 0. 0. 0. 0.] 17# [ 0. 0. 0. 0. 0. 0.] 18# [ 0. 0. 8. 4. 0. 0.] 19# [ 0. 0. 0. 1. 0. 0.] 20# [ 0. 0. 0. 0. 5. 0.] 21# [ 0. 0. 0. 0. 8. 0.]] 22 23A = A[np.ix_(~np.all(A == 0, axis=1), ~np.all(A == 0, axis=0))] 24print(A) 25#[[13. 0. 0. 0.] 26# [ 0. 8. 4. 0.] 27# [ 0. 0. 1. 0.] 28# [ 0. 0. 0. 5.] 29# [ 0. 0. 0. 8.]]

投稿2025/07/31 04:08

編集2025/08/05 00:52
melian

総合スコア21343

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

yyicp

2025/07/31 04:38

できました。 どうもありがとうございました。
yyicp

2025/07/31 05:32

sample1.txtの中身を 4 0 0 13.1 にすると、(13から13.1にしました) IndexError: arrays used as indices must be of integer (or boolean) type が出るのですが、解決法がよく分かりませんでした。
melian

2025/07/31 05:46

ごめんなさい、data[blk[1], blk[2]] のインデックス値である blk[1] と blk[2] が float 型になる場合を考慮していませんでした。修正しましたのでご確認ください。
yyicp

2025/07/31 05:46

for blk in pd.read_csv(f, header=None, chunksize=4, dtype=float): blk = blk.to_numpy() data[int(blk[1]), int(blk[2])] = blk[3] とすることで、DeprecationWarningがたくさん出てやや心配ではありますが、解決しました。
yyicp

2025/07/31 05:48

丁度行き違いになってしまいました。 修正していただいたコードで正しく動くことを確認しました。 どうもありがとうございました。
yyicp

2025/08/05 02:32

コードの修正、ありがとうございます。 両方とも正しく回るのですが、今回のコードの方が良いと考えられた理由がありましたら教えてください。 <以前のコード> for blk in pd.read_csv(f, header=None, chunksize=4): blk = blk.to_numpy() data[blk[1].astype(int), blk[2].astype(int)] = blk[3] <今回のコード> for blk in np.loadtxt(f).reshape((-1, 4)): data[*blk[1:3].astype(int)] = blk[3]
melian

2025/08/05 03:13

後になってから気がついたのですが、numpy.loadtxt() も空行を読み飛ばす仕様になっていて、reshape((-1,4)) とすることで pd.read_csv(f, header=None, chunksize=4) と同じ結果内容が得られます。(pd.read_csv(..., chunksize=4)はイテレータを返しますが) read_csv() では to_numpy() で numpy 配列に変換していますが、loadtxt() ではその必要がありません。要は Numpy だけで処理が可能であることが判ったので今回のコードへ変更しました。(あまり積極的な理由ではありませんが…) また、既にご存知だとは思いますが、 data[*blk[1:3].astype(int)] = blk[3] の * (アンパック演算子) はシーケンスを展開しますので、元のコードと同義になります。 data[blk[1].astype(int), blk[2].astype(int)] = blk[3]
yyicp

2025/08/05 04:13

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.30%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問