อนุญาตให้เมทริกซ์เข้าแทนที่ในจำนวนที่กำหนด


27

ฉันต้องการแก้ไขเมทริกซ์การเปลี่ยนตารางหนาแน่นในสถานที่โดยการเปลี่ยนลำดับของแถวและคอลัมน์หลายแห่งโดยใช้ไลบรารี่ของ python ศาสตร์นี้สอดคล้องกับการคูณเมทริกซ์ล่วงหน้าโดยเมทริกซ์การเปลี่ยนแปลง P และการโพสต์การคูณด้วย P ^ -1 = P ^ T แต่นี่ไม่ใช่วิธีการแก้ปัญหาที่สมเหตุสมผล

ตอนนี้ฉันกำลังสลับแถวและคอลัมน์ด้วยตนเอง แต่ฉันคาดว่าจะมี numpy ที่มีฟังก์ชั่นที่ดี f (M, v) โดยที่ M มี n แถวและคอลัมน์และ v มีรายการ n ดังนั้นการปรับปรุง f (M, v) M ตามการเปลี่ยนแปลงดัชนี v. บางทีฉันแค่ค้นหาอินเทอร์เน็ตไม่ได้

บางสิ่งเช่นนี้อาจเกิดขึ้นได้กับ "การจัดทำดัชนีขั้นสูง" ของนัมมี่ แต่ความเข้าใจของฉันคือว่าโซลูชันดังกล่าวจะไม่เข้าแทนที่ นอกจากนี้สำหรับสถานการณ์ที่เรียบง่ายบางอย่างมันอาจจะเพียงพอที่จะแยกการติดตามการเปลี่ยนแปลงดัชนี แต่สิ่งนี้ไม่สะดวกในกรณีของฉัน

เพิ่ม:
บางครั้งเมื่อผู้คนพูดถึงการเรียงสับเปลี่ยนพวกเขาหมายถึงการสุ่มตัวอย่างแบบสุ่มเรียงสับเปลี่ยนเท่านั้นตัวอย่างเช่นเป็นส่วนหนึ่งของกระบวนการเพื่อรับค่า p ในสถิติ หรือพวกมันหมายถึงการนับหรือแจกแจงพีชคณิตที่เป็นไปได้ ฉันไม่ได้พูดถึงสิ่งเหล่านี้

เพิ่มเติม:
เมทริกซ์มีขนาดเล็กพอที่จะใส่ลงในเดสก์ท็อปแรม แต่ใหญ่พอที่ฉันไม่ต้องการคัดลอกมันโดยไม่ตั้งใจ จริง ๆ แล้วฉันต้องการใช้เมทริกซ์ที่มีขนาดใหญ่ที่สุดเท่าที่จะเป็นไปได้ แต่ฉันไม่ต้องการที่จะจัดการกับความไม่สะดวกที่ไม่สามารถถือมันไว้ใน RAM และฉันทำการดำเนินการ LAPACK O (N ^ 3) บนเมทริกซ์ซึ่ง จำกัด ขนาดเมทริกซ์ในทางปฏิบัติ ขณะนี้ฉันคัดลอกเมทริกซ์ขนาดใหญ่นี้โดยไม่จำเป็น แต่ฉันหวังว่าจะสามารถหลีกเลี่ยงการเปลี่ยนแปลงได้อย่างง่ายดาย


3
มันจะดีถ้าคุณสามารถปรับปรุงคำถามเพื่อให้ขนาดของเมทริกซ์ของคุณ "มหึมา" ไม่ได้หมายถึงสิ่งเดียวกันกับทุกคน
Bill Barth

2
คุณมีสิทธิ์ที่การสร้างดัชนีขั้นสูง (หรือเรียกว่าแฟนซี) สร้างสำเนา แต่ถ้าคุณยอมรับที่จะอยู่กับความจริงนั้นรหัสของคุณเป็นเพียงM[v]การเปลี่ยนแถว
Daniel Velkov

@daniel: และมันจะเป็น M [v,:] [:, v] ที่จะทำการเปลี่ยนแปลงทั้งหมด? นี่จะเป็นวิธีที่ดีที่สุดในการเปลี่ยนแปลงโดยใช้การจัดทำดัชนีแฟนซีหรือไม่? และจะใช้หน่วยความจำเมทริกซ์ 3 เท่ารวมถึงขนาดของเมทริกซ์ดั้งเดิมเมทริกซ์แถว + คอลัมน์ที่ถูกเมทริกซ์และเมทริกซ์แถวที่อนุญาตชั่วคราวหรือไม่
ไม่มี

ถูกต้องคุณจะมีเมทริกซ์ดั้งเดิมและสำเนา 2 ชุด Btw ทำไมคุณต้องเปลี่ยนทั้งแถวและคอลัมน์ในเวลาเดียวกัน
Daniel Velkov

4
คุณจะทำอย่างไรกับเมทริกซ์ที่อนุญาต? มันอาจเป็นการดีกว่าที่จะเปลี่ยนรูปเวกเตอร์เมื่อใช้โอเปอเรเตอร์
Jed Brown

คำตอบ:


9

ตามเอกสารที่ไม่มีในสถานที่วิธีการเปลี่ยนแปลงใน numpy บางอย่างเช่นndarray.sort

ดังนั้นทางเลือกของคุณ (สมมติว่าMเป็นเมทริกซ์และเวกเตอร์การเปลี่ยนแปลง) ที่ยังไม่มีข้อความ×ยังไม่มีข้อความp

  1. การใช้อัลกอริทึมของคุณเองใน C เป็นโมดูลส่วนขยาย (แต่อัลกอริทึมในสถานที่ยากสำหรับฉันอย่างน้อย!)
  2. หน่วยความจำ Nค่าใช้จ่ายยังไม่มีข้อความ

    for i in range(N):
        M[:,i] = M[p,i]
    for i in range(N):
        M[i,:] = M[i,p]
  3. โอเวอร์เฮดของหน่วยความจำ 2 Nยังไม่มีข้อความ2

    M[:,:] = M[p,:]
    M[:,:] = M[:,p]

หวังว่าแฮ็คที่ไม่มีประโยชน์เหล่านี้มีประโยชน์


@ ไม่มีคือแฮ็ค 2. สิ่งที่คุณเรียกว่า 'การสลับแถวและคอลัมน์ด้วยตนเอง'?
Stefano M

1
ฉันจะรวมตัวเลือกที่ 1 และ 2: เขียนรหัส C ที่ใช้บัฟเฟอร์ของคำสั่ง N เพื่อเขียนคอลัมน์ที่เรียงสับเปลี่ยนกันแล้วเขียนกลับไปยังที่ที่มันมาจาก; จากนั้นทำเช่นเดียวกันสำหรับแถว ตามที่ @Stefano เขียนสิ่งนี้จะใช้หน่วยความจำเสริมเท่านั้นซึ่งคุณใช้จ่ายไปแล้วในการจัดเก็บการเปลี่ยนแปลงpในตอนแรก O(ยังไม่มีข้อความ)พี
Erik P.

@ErikP สำหรับการใช้งาน C หน่วยความจำเสริมนั้นสมเหตุสมผลและเพื่อให้แน่ใจว่าการกระจายของคุณเขียนไปที่อุณหภูมิและวิธีการคัดลอกกลับเป็นเสียง คำถามที่น่าสนใจคือถ้ามีอัลกอริธึมที่มีประสิทธิภาพมากขึ้นให้หน่วยความจำเสริมO ( N ) ฉันคิดว่าคำตอบนั้นยากเพราะเราควรคำนึงถึงสถาปัตยกรรมตัวประมวลผลของบัญชีรูปแบบการเข้าถึงหน่วยความจำแคชที่นิยม ... นี่บอกว่าฉันจะทำตามคำแนะนำของคุณและไปหาอัลกอริทึมที่ง่ายและสะดวก O(ยังไม่มีข้อความ)O(ยังไม่มีข้อความ)
Stefano M

2
นี่เป็น canidate ที่ดีจริงๆสำหรับฟังก์ชั่น cython Shoudl ไม่ควรเกิน 10 บรรทัด . . ต้องการให้ฉันให้มันแตก?
meawoppl

ฮ่า ๆ. ฉันเริ่มที่จะ Cython นี้แล้วพบคำตอบที่ถูกต้องในฟังก์ชั่นที่ฉันใช้ตลอดเวลา Doh ดูคำตอบที่โพสต์ของฉัน
meawoppl

6

คำเตือน:ตัวอย่างด้านล่างทำงานได้อย่างถูกต้อง แต่การใช้ชุดเต็มของพารามิเตอร์ที่แนะนำที่ท้ายโพสต์จะทำให้เกิดข้อบกพร่องหรืออย่างน้อยก็เป็น "คุณลักษณะที่ไม่มีเอกสาร" ในฟังก์ชัน numpy.take () ดูความคิดเห็นด้านล่างเพื่อดูรายละเอียด ยื่นรายงานข้อผิดพลาดแล้ว

คุณสามารถทำสิ่งนี้ในสถานที่ด้วยฟังก์ชั่นใช้เวลาของ numpyแต่มันต้องมีการกระโดดห่วง

นี่คือตัวอย่างของการทำการเรียงสับเปลี่ยนแบบสุ่มของแถวเมทริกซ์เอกลักษณ์:

import numpy as np
i = np.identity(10)
rr = range(10)
np.random.shuffle(rr)
np.take(i, rr, axis=0)
array([[ 0.,  1.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.],
       [ 0.,  0.,  0.,  0.,  0.,  1.,  0.,  0.,  0.,  0.],
       [ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  1.,  0.],
       [ 0.,  0.,  0.,  0.,  0.,  0.,  1.,  0.,  0.,  0.],
       [ 0.,  0.,  0.,  1.,  0.,  0.,  0.,  0.,  0.,  0.],
       [ 0.,  0.,  0.,  0.,  1.,  0.,  0.,  0.,  0.,  0.],
       [ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  1.,  0.,  0.],
       [ 1.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.],
       [ 0.,  0.,  1.,  0.,  0.,  0.,  0.,  0.,  0.,  0.],
       [ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  1.]])

สิ่งที่คุณต้องทำคือการระบุพารามิเตอร์ "out" ให้เหมือนกับอาร์เรย์อินพุตและคุณต้องตั้งค่า mode = "clip" หรือ mode = "wrap" หากคุณไม่ได้ตั้งค่าโหมดมันจะทำสำเนาเพื่อเรียกคืนรัฐอาร์เรย์ในข้อยกเว้นหลาม(ดูที่นี่)

ในบันทึกสุดท้ายดูเหมือนว่าจะเป็นวิธีอาร์เรย์ดังนั้นแทนที่จะ

np.take(i, rr, axis=0)

คุณสามารถโทร

i.take(rr, axis=0)

ถ้านั่นเป็นสิ่งที่คุณชื่นชอบ ดังนั้นโดยรวมแล้วการโทรควรมีลักษณะดังนี้

#Inplace Rearrange
arr = makeMyBixMatrix()
pVec0, pVec1 = calcMyPermutationVectors()
arr.take(pVec0, axis=0, out=arr, mode="clip")
arr.take(pVec1, axis=1, out=arr, mode="clip")

เพื่อเปลี่ยนทั้งแถวและคอลัมน์ฉันคิดว่าคุณต้องวิ่งสองครั้งหรือดึง shenanigans ที่น่าเกลียดด้วยnumpy.unravel_indexที่ทำให้ฉันปวดหัว


ตามที่กล่าวไว้ในขั้นตอนวิธีนั้นยาก โซลูชันของคุณไม่ทำงานกับ numpy 1.6.2 และ 1.7.1 (แถว / คอลัมน์ซ้ำกัน) ไม่มีเวลาตรวจสอบว่า 1.8.x แก้ไขปัญหานี้ได้หรือไม่
Stefano M

อืมม คุณสามารถโพสต์รหัสทดสอบที่ไหนสักแห่ง? ในหัวของฉันฉันรู้สึกราวกับว่าจะต้องมีการดำเนินการเรียงลำดับในดัชนีที่เกิดขึ้นก่อนที่จะถอนขน ฉันจะตรวจสอบ PM นี้เพิ่มเติม
meawoppl

1
เมื่อฉันเรียกรหัสนี้ฉันได้รับ1.6.2, test take, not overwriting: True, test not-in-place take: True, test in-place take: False, rr [3, 7, 8, 1, 4, 5, 9, 0, 2, 6], ,arr [30 70 80 70 40 50 90 30 80 90] ref [30 70 80 10 40 50 90 0 20 60]ดังนั้นnp.takeอย่างน้อยสำหรับ numpy 1.6.2 จึงไม่ทราบว่าจะทำการเปลี่ยนรูปแบบในสถานที่และทำให้เกิดความยุ่งเหยิง
Stefano M

Yeouch แสดงให้เห็นอย่างดี สิ่งนี้อาจมีคุณสมบัติเป็นข้อบกพร่อง IMHO อย่างน้อยที่สุดเอกสารควรบอกว่าอินพุตและเอาต์พุตไม่สามารถเป็นอาร์เรย์เดียวกันได้อาจตรวจสอบเพื่อดูและยกเว้นว่าเป็น
meawoppl

เห็นด้วยกับข้อผิดพลาด: บางทีคุณควรเพิ่มบันทึกย่อในโพสต์ของคุณเพื่อเตือนผู้อ่านว่าโซลูชันของคุณสามารถให้ผลลัพธ์ที่ผิด
Stefano M

2

หากคุณมีเมทริกซ์เบาบางจัดเก็บในCOOรูปแบบต่อไปนี้อาจเป็นประโยชน์

    A.row = perm[A.row];
    A.col = perm[A.col];

ACOOpermnumpy.arrayม.ม.


แต่ค่าใช้จ่ายหน่วยความจำสำหรับการจัดเก็บเมทริกซ์หนาแน่นเต็มเป็นC00เมทริกซ์เบาบางในสถานที่แรก
Federico Poloni

intfloatfloatn2numpy.ndarray

1

ฉันไม่มีชื่อเสียงพอที่จะแสดงความคิดเห็น แต่ฉันคิดว่าคำถาม SO ต่อไปนี้อาจเป็นประโยชน์: https://stackoverflow.com/questions/4370745/view-onto-a-numpy-array

จุดพื้นฐานคือคุณสามารถใช้การแบ่งส่วนพื้นฐานและที่จะสร้างมุมมองไปยังอาร์เรย์โดยไม่ต้องคัดลอก แต่ถ้าคุณทำการแบ่งส่วน / การทำดัชนีขั้นสูงมันจะสร้างสำเนา


OP กำลังขอการเปลี่ยนรูปและไม่สามารถทำได้โดยการแบ่งส่วนพื้นฐาน
Stefano M

คุณถูกต้องแน่นอน. ฉันคิดว่ามันจะมีประโยชน์สำหรับ OP ที่จะเข้าใจว่าเกิดอะไรขึ้นกับการแบ่งส่วน (ในกรณีที่พวกเขาไม่รู้) เนื่องจากพวกเขากังวลว่าเมื่อไรจะมีการทำสำเนา ถ้าเขาใช้บางสิ่งจากคำตอบของคุณฉันคิดว่าคงเป็นการดีที่จะรู้ตั้งแต่คุณใช้มันในลูปของคุณ
hadsed

-1

เกี่ยวกับอะไร

my_array [:, [0, 1]] = my_array [:, [1, 0]]


1
สิ่งนี้สร้างชั่วคราวซึ่งเป็นสิ่งที่เขาต้องการหลีกเลี่ยง
Michael Grant
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.