Saya punya dataframe dengan setiap baris memiliki nilai daftar.
id list_of_value
0 ['a','b','c']
1 ['d','b','c']
2 ['a','b','c']
3 ['a','b','c']
saya harus menghitung skor dengan satu baris dan terhadap semua baris lainnya
Untuk misalnya:
Step 1: Take value of id 0: ['a','b','c'],
Step 2: find the intersection between id 0 and id 1 ,
resultant = ['b','c']
Step 3: Score Calculation => resultant.size / id.size
ulangi langkah 2,3 antara id 0 dan id 1,2,3, sama untuk semua id.
dan membuat bingkai data N x N; seperti ini:
- 0 1 2 3
0 1 0.6 1 1
1 1 1 1 1
2 1 1 1 1
3 1 1 1 1
Saat ini kode saya hanya memiliki satu untuk loop:
def scoreCalc(x,queryTData):
#mathematical calculation
commonTData = np.intersect1d(np.array(x),queryTData)
return commonTData.size/queryTData.size
ids = list(df['feed_id'])
dfSim = pd.DataFrame()
for indexQFID in range(len(ids)):
queryTData = np.array(df.loc[df['id'] == ids[indexQFID]]['list_of_value'].values.tolist())
dfSim[segmentDfFeedIds[indexQFID]] = segmentDf['list_of_value'].apply(scoreCalc,args=(queryTData,))
Apakah ada cara yang lebih baik untuk melakukan ini? bisakah saya hanya menulis satu fungsi yang berlaku alih-alih melakukan iterasi for-loop. dapatkah saya membuatnya lebih cepat?
list_of_value
?list_of_value
. Maksud saya total, di semua baris.Jawaban:
Jika data Anda tidak terlalu besar, Anda bisa menggunakannya
get_dummies
untuk menyandikan nilai dan melakukan perkalian matriks:Keluaran:
Pembaruan : Berikut ini penjelasan singkat untuk kodenya. Gagasan utamanya adalah mengubah daftar yang diberikan menjadi satu-hot-encoded:
Setelah kita memiliki itu, ukuran persimpangan dari dua baris, katakan,
0
dan1
hanya produk titik mereka, karena karakter milik kedua baris jika dan hanya jika diwakili oleh1
keduanya.Dengan pemikiran itu, gunakan pertama kali
untuk mengubah setiap sel menjadi seri dan menggabungkan semua seri itu. Keluaran:
Sekarang, kami menggunakan
pd.get_dummies
pada seri itu untuk mengubahnya menjadi kerangka data satu-panas-disandikan:Seperti yang Anda lihat, setiap nilai memiliki barisnya sendiri. Karena kami ingin menggabungkan mereka yang memiliki baris asli yang sama ke satu baris, kami dapat menjumlahkannya dengan indeks asli. Jadi
memberikan dataframe binary-encoded yang kita inginkan. Baris selanjutnya
sama seperti logika Anda:
s.dot(s.T)
menghitung titik produk dengan baris, lalu.div(s.sum(1))
membagi jumlah dengan baris.sumber
12k x 12k
kerangka data. Seharusnya tidak masalah jika Anda memiliki sekitar beberapa ratus nilai unik.Coba ini
Keluaran
Anda juga dapat melakukannya sebagai berikut
sumber
Gunakan pemahaman daftar bersarang pada daftar set
s_list
. Dalam pemahaman daftar, gunakanintersection
operasi untuk memeriksa tumpang tindih dan mendapatkan panjang setiap hasil. Terakhir, buat kerangka data dan bagilah dengan panjang masing-masing daftardf.list_of_value
Dalam hal terdapat nilai-nilai duplikat di setiap daftar, Anda harus menggunakan
collections.Counter
bukanset
. Saya mengubah sampel data id = 0 ke['a','a','c']
dan id = 1 ke['d','b','a']
sumber
Diperbarui
Karena ada banyak solusi kandidat yang diusulkan, sepertinya ide yang baik untuk melakukan analisis waktu. Saya menghasilkan beberapa data acak dengan baris 12k seperti yang diminta oleh OP, tetap dengan 3 elemen per set tetapi memperluas ukuran alfabet yang tersedia untuk mengisi set. Ini dapat disesuaikan agar sesuai dengan data aktual.
Beri tahu saya jika Anda memiliki solusi yang ingin Anda uji atau perbarui.
Mendirikan
Pemenang saat ini
Peserta
Posting asli dengan detail solusi
Dimungkinkan untuk melakukan ini
pandas
dengan bergabung sendiri.Seperti yang ditunjukkan oleh jawaban lain, langkah pertama adalah membongkar data menjadi bentuk yang lebih panjang.
Dari tabel ini dimungkinkan untuk menghitung jumlah per-ID.
Dan kemudian muncul self-join, yang terjadi pada
value
kolom. Ini memasangkan ID satu kali untuk setiap nilai perpotongan, sehingga ID yang berpasangan dapat dihitung untuk mendapatkan ukuran persimpangan.Keduanya kemudian dapat digabungkan, dan skor dihitung.
Jika Anda lebih suka bentuk matriks, itu dimungkinkan dengan a
pivot
. Ini akan menjadi representasi yang jauh lebih besar jika datanya jarang.sumber
Solusi ini akan bekerja secara efisien dengan ukuran data apa pun dan segala jenis nilai dalam Anda
list
katakanstr
atauint
atau sebaliknya, juga menjaga nilai berulang jika ada.Dalam hal ini, Pemahaman daftar berkinerja lebih baik karena tidak perlu memuat atribut append dari daftar dan menyebutnya sebagai fungsi di setiap iterasi. Dengan kata lain dan secara umum, pemahaman daftar berkinerja lebih cepat karena menangguhkan dan melanjutkan bingkai fungsi, atau beberapa fungsi dalam kasus lain lebih lambat daripada membuat daftar sesuai permintaan.
Menggunakan pemahaman daftar sebagai ganti loop yang tidak membangun daftar, secara nonsensik mengumpulkan daftar nilai yang tidak berarti dan kemudian membuang daftar itu, seringkali lebih lambat karena overhead menciptakan dan memperluas daftar.
Hasil:
Waktu eksekusi:
sumber
Anda dapat mengubah daftar menjadi satu set dan menggunakan fungsi persimpangan untuk memeriksa tumpang tindih:
(hanya 1 fungsi yang digunakan saat Anda bertanya :-))
sumber
Saya akan gunakan
product
untuk mendapatkan semua kombinasi. Kemudian kita dapat memeriksanumpy.isin
dannumpy.mean
:Sampel waktu
sumber
Harus cepat, pertimbangkan juga duplikat dalam daftar
sumber
Iya! Kami sedang mencari produk Cartesian di sini, yang diberikan dalam jawaban ini . Ini dapat dicapai tanpa untuk loop atau pemahaman daftar
Mari kita tambahkan nilai berulang baru ke bingkai data kita
df
sehingga terlihat seperti ini:Selanjutnya bergabung dengan dirinya sendiri
Beginilah tampilan bingkai yang digabungkan:
Kemudian kami menerapkan fungsi yang diinginkan untuk setiap baris menggunakan
axis=1
Membentuk ulang ini untuk mendapatkan nilai dalam format yang diinginkan
Semoga ini membantu :)
sumber