Salin atau tidak salin, itu pertanyaannya

 – Beragampengetahuan
6 mins read

Salin atau tidak salin, itu pertanyaannya – Beragampengetahuan

Oleh: Blog Bogumił Kamiński

Repost dari:

Saya telah menggunakan Julia selama beberapa waktu sekarang.
Jadi saya pikir saya sudah terbiasa menggunakan bahasa ini dengan aman.
Sayangnya, itu tidak sepenuhnya benar.
Hari ini saya ingin berbagi dengan Anda pemikiran saya tentang template penting yang saya butuhkan
belajar kembali secara terus menerus.

Seperti yang Anda ketahui, pengembang paket di Julia ingin mereka cepat. Untuk ini
alasan mereka biasanya mengoptimalkannya. Salah satu pengoptimalan umum adalah menghindari
alokasi yang tidak perlu. Pendekatan ini masuk akal, tetapi berisiko tidak diinginkan
mutasi data tersebut.

Secara umum, Anda memiliki dua situasi ketika Anda mungkin memiliki masalah
mutasi:

  • saat Anda meneruskan data ke fungsi yang dapat mengubahnya;
  • ketika Anda mendapatkan data yang dikembalikan dari fungsi dan kemudian Anda mengubahnya
    Pada saat yang sama, operasi ini mengubah beberapa data lain yang belum Anda miliki
    diharapkan untuk diubah.

Skenario pertama ditangani dengan cukup jelas di Julia. Fungsi apapun
dapat mengubah argumennya dengan konvensi, jadi namanya diakhiri dengan !.
Ini dijelaskan dengan jelas dalam manual Julia di
menambahkan ! ke nama fungsi yang mengubah bagian argumennya.

Kasus kedua kurang jelas dan menjadi fokus postingan saya hari ini. saya akan menjelaskan
itu menggunakan dua contoh yang diambil dari pertanyaan nyata yang diajukan oleh pengguna Julia minggu lalu.

Posting ditulis di bawah Julia 1.9.0-rc1, DataFrames.jl 1.5.0, GLM.jl 1.8.1 dan
ShiftedArrays.jl 2.0.0.

Pertimbangkan kode berikut:

julia> using DataFrames

julia> using Random

julia> using ShiftedArrays: lag

julia> Random.seed!(1234);

julia> df = DataFrame(x = rand(10))
10×1 DataFrame
 Row │ x
     │ Float64
─────┼───────────
   1 │ 0.579862
   2 │ 0.411294
   3 │ 0.972136
   4 │ 0.0149088
   5 │ 0.520355
   6 │ 0.639562
   7 │ 0.839622
   8 │ 0.967143
   9 │ 0.131026
  10 │ 0.946453

julia> df.xlag = lag(df.x)
10-element ShiftedVector{Float64, Missing, Vector{Float64}}:
  missing
 0.5798621201341324
 0.4112941179498505
 0.9721360824554687
 0.014908849285099945
 0.520354993723718
 0.6395615996802734
 0.8396219340580711
 0.967142768915383
 0.13102565622085904

julia> df
10×2 DataFrame
 Row │ x          xlag
     │ Float64    Float64?
─────┼────────────────────────────
   1 │ 0.579862   missing
   2 │ 0.411294         0.579862
   3 │ 0.972136         0.411294
   4 │ 0.0149088        0.972136
   5 │ 0.520355         0.0149088
   6 │ 0.639562         0.520355
   7 │ 0.839622         0.639562
   8 │ 0.967143         0.839622
   9 │ 0.131026         0.967143
  10 │ 0.946453         0.131026

Jebakan potensial adalah :xlag kolom adalah tampilan. Jika kita memodifikasi :x Tetapi juga :xlag akan dimodifikasi.

Ini contohnya:

julia> df.x[1] = 0.0
0.0

julia> df
10×2 DataFrame
 Row │ x          xlag
     │ Float64    Float64?
─────┼────────────────────────────
   1 │ 0.0        missing
   2 │ 0.411294         0.0
   3 │ 0.972136         0.411294
   4 │ 0.0149088        0.972136
   5 │ 0.520355         0.0149088
   6 │ 0.639562         0.520355
   7 │ 0.839622         0.639562
   8 │ 0.967143         0.839622
   9 │ 0.131026         0.967143
  10 │ 0.946453         0.131026

Dalam beberapa kasus, Anda mungkin menginginkannya secara nyata. Tetapi dalam banyak kasus ini akan menyebabkan kesalahan,
terutama jika kedua objek digunakan di bagian kode yang berbeda. Di sini saya menyimpannya
bingkai data karena ini adalah cara mudah untuk menunjukkan apa yang terjadi.

Jebakan lainnya adalah saat Anda mencoba mengubah kerangka data seperti itu dengan mendorong baris ke dalamnya:

julia> push!(df, (10.0, 11.0))
┌ Error: Error adding value to column :xlag. Maybe it was forgotten to ask for column element type promotion, which can be done by passing the promote=true keyword argument.

Seperti yang Anda lihat, operasi gagal karena kami memiliki tampilan yang dihosting
sebagai kolom kerangka data dan tampilan tidak dapat diubah ukurannya.

Ini sepertinya kesalahan sederhana, tetapi kenyataannya, pengguna melaporkan telah melakukannya.
Cara paling sederhana untuk mengatasi masalah ini adalah memastikan bahwa Anda copy pendapat:

julia> df.xlag = copy(lag(df.x))
10-element Vector{Union{Missing, Float64}}:
  missing
 0.0
 0.4112941179498505
 0.9721360824554687
 0.014908849285099945
 0.520354993723718
 0.6395615996802734
 0.8396219340580711
 0.967142768915383
 0.13102565622085904

julia> push!(df, (10.0, 11.0))
11×2 DataFrame
 Row │ x           xlag
     │ Float64     Float64?
─────┼─────────────────────────────
   1 │  0.0        missing
   2 │  0.411294         0.0
   3 │  0.972136         0.411294
   4 │  0.0149088        0.972136
   5 │  0.520355         0.0149088
   6 │  0.639562         0.520355
   7 │  0.839622         0.639562
   8 │  0.967143         0.839622
   9 │  0.131026         0.967143
  10 │  0.946453         0.131026
  11 │ 10.0             11.0

Biarkan saya mengilustrasikan jebakan lain dengan model linier. Mulailah dengan membuat kumpulan data sederhana:

julia> Random.seed!(1234);

julia> df = DataFrame(randn(10, 3), [:x1, :x2, :error]);

julia> df.y = df.x1 + df.x2 + df.error;

julia> df.wts = rand(10);

julia> df
10×5 DataFrame
 Row │ x1          x2          error       y           wts
     │ Float64     Float64     Float64     Float64     Float64
─────┼───────────────────────────────────────────────────────────
   1 │  0.970656    0.705993   -1.0565      0.620151   0.840641
   2 │ -0.979218    1.09156     0.148361    0.260698   0.523948
   3 │  0.901861    0.871498   -1.83851    -0.0651514  0.0128461
   4 │ -0.0328031   0.0856911  -1.07363    -1.02074    0.40573
   5 │ -0.600792    0.960079   -0.20563     0.153657   0.124074
   6 │ -1.44518     0.907837    0.770703    0.233363   0.648874
   7 │  2.70742    -1.46506    -1.21394     0.0284219  0.574296
   8 │  1.52445    -0.215859    1.0915      2.40009    0.408537
   9 │  0.759804    0.575094    1.22004     2.55494    0.0731709
  10 │ -0.881437   -1.79563    -0.0758316  -2.7529     0.501756

Sekarang paskan model linier berbobot:

julia> using GLM

julia> model = lm(@formula(y ~ x1 + x2), df, wts=df.wts)
StatsModels.TableRegressionModel{LinearModel{GLM.LmResp{Vector{Float64}}, GLM.DensePredChol{Float64, LinearAlgebra.CholeskyPivoted{Float64, Matrix{Float64}, Vector{Int64}}}}, Matrix{Float64}}

y ~ 1 + x1 + x2

Coefficients:
─────────────────────────────────────────────────────────────────────────
                 Coef.  Std. Error      t  Pr(>|t|)  Lower 95%  Upper 95%
─────────────────────────────────────────────────────────────────────────
(Intercept)  -0.163691    0.721581  -0.23    0.8550   -7.38861    7.06123
x1            0.698275    0.554725   1.26    0.4108   -4.85598    6.25253
x2            1.03178     0.732565   1.41    0.3753   -6.30312    8.36668
─────────────────────────────────────────────────────────────────────────

Misalkan kita menulis fungsi sederhana untuk menghitung varians-kovarians
matriks koefisien model kami:

function our_vcov(model)
    X = modelmatrix(model)
    u² = residuals(model) .^ 2
    wts = model.model.rr.wts
    X .*= sqrt.(wts)
    u² .*= wts
    dfr = dof_residual(model)
    M = inv(X'*X)
    return M * sum(u²) / dfr
end

Mari kita periksa apakah kita mendapatkan hasil yang sama seperti yang dikembalikan oleh integrasi vcov fungsi:

julia> vcov(model)
3×3 Matrix{Float64}:
  0.520679   -0.0861524  -0.0613806
 -0.0861524   0.30772     0.168677
 -0.0613806   0.168677    0.536652

julia> our_vcov(model)
3×3 Matrix{Float64}:
  0.520679   -0.0861524  -0.0613806
 -0.0861524   0.30772     0.168677
 -0.0613806   0.168677    0.536652

Semua terlihat bagus. Mari kita jalankan kembali fungsi kita:

julia> our_vcov(model)
3×3 Matrix{Float64}:
  0.954193  -0.196279  -0.191441
 -0.196279   0.534882   0.295785
 -0.191441   0.295785   0.965165

Tunggu – kali ini kami memiliki hasil yang berbeda. Apa masalahnya?

Masalahnya adalah dengan X .*= sqrt.(wts) operasi pembaruan X di tempat.
Dan itu berhasil X = modelmatrix(model) kami mengikat X nilai yang
disimpan secara internal di model Benda. Jadi kami, tanpa sadar berubah
model.

Dalam hal ini, perbaikan akan menjadi contoh untuk menulis X = X .* sqrt.(wts) atau
X = copy(modelmatrix(model)).

Masalahnya adalah sangat mudah untuk melupakannya. Keduanya X = modelmatrix(model)
Dan X .*= sqrt.(wts) karya yang terlihat alami dan dapat dengan mudah digunakan bersama.

Juga jika Anda melihat modelmatrix membantu:

help?> modelmatrix
search: modelmatrix ModelMatrix

  modelmatrix(model::RegressionModel)

  Return the model matrix (a.k.a. the design matrix).

tidak ada yang memperingatkan Anda bahwa operasi dapat mengembalikan beberapa nilai yang disimpan model
atau salinannya.

Catatan untuk pengembang paket: jenis kesalahan ini tidak mungkin terdeteksi oleh pengujian standar
karena hanya menjadi jelas setelah Anda menjalankan operasi dua kali pada beberapa objek (dan seringkali
tes dijalankan hanya sekali).

Jadi pola apa yang perlu saya pelajari kembali? Aturan emasnya adalah:

Selalu periksa apakah nilai yang dikembalikan oleh beberapa fungsi baru dialokasikan.

Sayangnya, seperti yang Anda lihat dari contoh yang saya berikan, mudah lupa untuk memverifikasi ini.
Masalah utamanya adalah tidak ada bantuan visual yang dapat membantu Anda mengidentifikasi masalah tersebut
(berlawanan dengan fungsi yang mengubah argumennya yang diakhiri dengan .) !).

Jika Anda adalah pengguna DataFrames.jl, Anda terlindungi sebagian dari risiko yang saya bahas hari ini.
Fungsi yang biasa digunakan seperti select, combine, transformatau DataFrame konstruktor
pastikan untuk membuat salinan kolom dari kerangka data yang mereka kembalikan.
Memang, ini mengurangi kinerjanya, tetapi membantu memastikan keamanan dan biasanya perolehan kinerjanya minimal.
(dan untuk pengguna yang terobsesi dengan kecepatan, kami punya copycols=false argumen kata kunci atau fungsi dengan
! bekerja di lokasi).

Jadi jawaban saya untuk pertanyaan dari judul posting adalah: Menyalin (kecuali jika Anda yakin bisa
lewati penyalinan dengan aman, dan manfaat kinerjanya sangat berharga).

Software Terbaru Saat Ini



Aplikasi yang sedang trend saat ini

object oriented programming, programming language, programming adalah, web programming, belajar programming, tournament software, software, software adalah, contoh software, apa itu software, pengertian software, aplikasi, aplikasi penghasil uang, aplikasi bokep, aplikasi video, programming

#Salin #atau #tidak #salin #itu #pertanyaannya

Tinggalkan Balasan

Alamat email Anda tidak akan dipublikasikan. Ruas yang wajib ditandai *