Metadata di DataFrames.jl: mengapa dan bagaimana? – Beragampengetahuan
Oleh: Blog Bogumił Kamiński
Repost dari:
Dalam posting saya baru-baru ini, saya membahas fitur-fitur baru yang ditambahkan ke DataFrames.jl.
Salah satunya adalah penanganan metadata. Hari ini saya ingin membahas lebih detail
mengapa metadata berguna dalam praktik dan bagaimana hal itu didukung. saya akan menutupi
topik berikut:
- Mengapa memiliki dukungan metadata sangat membantu.
- Baca dan tulis bingkai data dengan metadata ke disk.
- Aturan propagasi metadata.
Posting ini menggunakan banyak fitur ekosistem manajemen data Julia, jadi
daftar dependensinya panjang. Saya telah menggunakan:
- Julia 1.8.2
- CSV.jl 0.10.7
- DataFrames.jl 1.4.3
- Laminate Flooring2.jl 0.2.2
- Plots.jl 1.36.6
- ReadStatTables.jl 0.2.0
- StatBase.jl 0.33.21
- TableMetadataTools.jl @ 9ce81f87
- ZipFile.jl 0.10.1
Perhatikan bahwa paket TableMetadataTools.jl masih dalam versi beta
tahap, di mana kami menunggu umpan balik pengguna tentang fungsinya. Itu
adalah mengapa itu tidak dirilis dan statusnya diwakili oleh hash Git:
(@v1.8) pkg> st TableMetadataTools
Status `C:\Users\bogum\.julia\environments\v1.8\Project.toml`
[9ce81f87] TableMetadataTools v0.1.0
`
Sebelum kami mulai mengunduh semua paket yang diperlukan:
julia> using CSV
julia> using DataFrames
julia> import Downloads
julia> using Parquet2
julia> using Plots
julia> import ReadStatTables
julia> using TableMetadataTools
julia> using Serialization
julia> using StatsBase
julia> using ZipFile
Masalah hari ini adalah membuat konspirasi berapa persen dari biaya pengobatan
dalam PDB Amerika Serikat telah berubah selama bertahun-tahun.
Misalkan seseorang memberi tahu Anda bahwa informasi ini dapat ditemukan dalam dokumen Bank Dunia
Kumpulan data Indeks Pembangunan Dunia tersedia di situs web ini.
Di pos, saya akan mengikuti semua langkah yang diperlukan untuk membuat plot.
Kami pertama-tama mengambil data dan membongkar file yang menyimpannya:
julia> WDI_URL = "
world-bank-s-world-development-indicators-wdi/\
WDI2009.zip";
julia> if !isfile("WDI2009.dta")
isfile("WDI2009.zip") || Downloads.download(WDI_URL, "WDI2009.zip");
zip = ZipFile.Reader("WDI2009.zip")
open("WDI2009.dta", "w") do io
write(io, read(only(zip.files)))
end
close(zip)
end
Perhatikan bahwa dalam kode saya hanya mengunduh dan mendekompresi data jika diperlukan.
Karena aktivitas kami, kami telah menulis ke disk WDI2009.dta mengajukan
dengan data. File tersebut dalam format Stata.
julia> df = "WDI2009.dta" |> ReadStatTables.readstat |> DataFrame
11123×872 DataFrame
Row │ country wbcode year AG_AGR_TRAC_NO AG_CON_FERT_MT AG_CON_FER ⋯
│ String String Int16 Float64? Float64? Float64? ⋯
───────┼──────────────────────────────────────────────────────────────────────
1 │ Aruba ABW 1960 missing missing missing ⋯
2 │ Aruba ABW 1961 missing missing missing
3 │ Aruba ABW 1962 missing missing missing
4 │ Aruba ABW 1963 missing missing missing
5 │ Aruba ABW 1964 missing missing missing ⋯
6 │ Aruba ABW 1965 missing missing missing
⋮ │ ⋮ ⋮ ⋮ ⋮ ⋮ ⋮ ⋱
11118 │ Zimbabwe ZWE 2003 24000.0 146032.0 453
11119 │ Zimbabwe ZWE 2004 24000.0 86352.0 268
11120 │ Zimbabwe ZWE 2005 24000.0 85018.0 264 ⋯
11121 │ Zimbabwe ZWE 2006 24000.0 132661.0 missing
11122 │ Zimbabwe ZWE 2007 missing missing missing
11123 │ Zimbabwe ZWE 2008 missing missing missing
867 columns and 11111 rows omitted
julia> describe(df, :min, :max, :nmissing)
872×4 DataFrame
Row │ variable min max nmissing
│ Symbol Any Any Int64
─────┼──────────────────────────────────────────────────────
1 │ country Afghanistan Zimbabwe 0
2 │ wbcode ABW ZWE 0
3 │ year 1960 2008 0
4 │ AG_AGR_TRAC_NO 1.0 2.79193e7 2294
5 │ AG_CON_FERT_MT 0.0 5.59256e7 3755
6 │ AG_CON_FERT_ZS 0.0 1.57833e5 3295
⋮ │ ⋮ ⋮ ⋮ ⋮
867 │ TX_VAL_OTHR_ZS_WT -3.84e-13 100.0 5792
868 │ TX_VAL_SERV_CD_WT 0.0 3.81092e12 5713
869 │ TX_VAL_TECH_CD 0.0 1.80719e12 8696
870 │ TX_VAL_TECH_MF_ZS 0.0 74.9541 8574
871 │ TX_VAL_TRAN_ZS_WT 0.000332059 100.0 5938
872 │ TX_VAL_TRVL_ZS_WT 0.113351 100.0 5913
860 rows omitted
Kami mencatat bahwa kumpulan data cukup luas. Ini memiliki hampir 900 kolom.
Selain itu, kami menemukan bahwa nama kolom tidak terlalu informatif.
Ini adalah situasi umum saat bekerja dengan tabel lebar. Penulis seperti ini
tupel sering mencoba menggunakan nama variabel yang relatif pendek.
Bagaimana kita dapat menemukan kolom yang mewakili persentase biaya pengobatan
dalam PDB AS? Kami jelas membutuhkan metadata untuk tabel ini.
Untungnya, ada dalam kumpulan data ini, jadi mari kita selidiki. Sebelum
Kami mulai menekankan bahwa ada dua jenis metadata di DataFrames.jl:
- metadata tingkat tabel: pasangan kunci-nilai ditambahkan ke bingkai data sebagai
penuh; kunci harus berupa string dan nilai dapat berupa data arbitrer (tetapi itu
merekomendasikan menggunakan string jika interoperabilitas penting, karena beberapa penyimpanan
format hanya dapat menyimpan nilai string); - metadata tingkat kolom: pasangan kunci-nilai yang dilampirkan ke kolom tertentu
dalam kerangka data (pertimbangan yang sama untuk tipe data kunci dan nilai
berlaku untuk metadata tingkat tabel).
Periksa terlebih dahulu metadata tingkat tabel:
julia> metadata(df) Dict{String, Any} dengan 13 entri: "file_ext" => ".dta" "modified_time" => DateTime("2010-01-08T11:17:00") "file_format_version" => 114 "file_format_is_64bit" => salah "table_name" => "" "note" => ["2", "dataset coded for stata as in Catini, Pani…
"file_encoding" => ""
"file_label" => ""
"var_count" => 872
"row_count" => 11123
"creation_time" => DateTime("2010-01-08T11:17:00")
"endianness" => READSTAT_ENDIAN_LITTLE
"compression" => READSTAT_COMPRESS_NONE
julia> metadata(df, "notes")
3-element Vector{String}:
"2"
"dataset coded for stata as in Catini, Panizza and Saade. Macro Data 4 Stata"
"December 2009"
We can see that the data set was created on Jan 9, 2010 by Catini, Panizza and
Saade in Macro Data 4 Stata project. We also have information that the data
frame should have 11123 rows and 872 columns, and indeed above we see that this
information is consistent.
Let me comment here on one important distinction:
- metadata such as
"var_countor"row_count"is volatile; most likely
transformation of thedfdata frame will invalidate it; - metadata such as
"notes"most likely will not be invalidated whendf
is transformed.
DataFrames.jl distinguishes these both scenarios and I discuss how it is done
below.
Now check column-level metadata:
julia> colmetadata(df)
Dict{Symbol, Dict{String, Any}} with 872 entries:
:GC_XPN_OTHR_ZS => Dict("label"=>"Other expense (% of expense)", "for…
:SH_DYN_AIDS_ZS => Dict("label"=>"Prevalence of HIV, total (% of popu…
:EP_PMP_DESL_CD => Dict("label"=>"Pump price for diesel fuel (US\$ pe…
:SL_TLF_PRIM_ZS => Dict("label"=>"Labor force with primary education …
:NE_CON_PRVT_PC_KD_ZG => Dict("label"=>"Household final consumption expendi…
:PA_NUS_PPP => Dict("label"=>"PPP conversion factor, GDP (LCU per…
:DT_NFL_WFPG_CD => Dict("label"=>"UN net multilateral flows, WFP (cur…
:AG_LND_CREL_HA => Dict("label"=>"Land under cereal production (hecta…
:EE_BOD_TOTL_KG => Dict("label"=>"Organic water pollutant (BOD) emiss…
:SH_DYN_CHLD_MA => Dict("label"=>"Mortality rate, male child (per 1,0…
:ER_LND_PTLD_ZS => Dict("label"=>"Nationally protected areas (% of to…
:IP_JRN_ARTC_SC => Dict("label"=>"Scientific and technical journal ar…
:NY_GDP_DEFL_KD_ZG => Dict("label"=>"Inflation, GDP deflator (annual %)"…
:IT_NET_SECR_P6 => Dict("label"=>"Secure Internet servers (per 1 mill…
:SE_SEC_ENRL_FE_ZS => Dict("label"=>"Secondary education, pupils (% fema…
:FR_INR_LNDP => Dict("label"=>"Interest rate spread (lending rate …
⋮ => ⋮
julia> colmetadata(df, :country)
Dict{String, Any} with 8 entries:
"label" => "CountryName"
"format" => "%44s"
"display_width" => 44
"measure" => READSTAT_MEASURE_UNKNOWN
"alignment" => READSTAT_ALIGNMENT_RIGHT
"type" => READSTAT_TYPE_STRING
"storage_width" => 0x000000000000002d
"vallabel" => Symbol("")
As you can see there is a lot of metadata for each column, but most of it is
technical (and most likely volatile) except for "label" which gives us useful
information about the interpretation of data in the column (and this information
is not invalidated under simple operations on a data frame like dropping rows
or columns).
TableMetadataTools.jl provides a convenience functions label and labels that
extract "label" metadata from a column and all columns respectively:
julia> label(df, :country)
"CountryName"
julia> labels(df)
872-element Vector{String}:
"CountryName"
""
""
"Agricultural machinery, tractors"
"Fertilizer consumption (metric tons)"
"Fertilizer consumption (100 grams per hectare of arable land)"
"Agricultural land (sq. km)"
"Agricultural land (% of land area)"
⋮
"Merchandise exports (current US\$)"
"Export value index (2000 = 100)"
"Computer, communications and other services (% of commercial service exports)"
"Commercial service exports (current US\$)"
"High-technology exports (current US\$)"
"High-technology exports (% of manufactured exports)"
"Transport services (% of commercial service exports)"
"Travel services (% of commercial service exports)"
Now we could search in the vector returned by labels for a column containing
information about percentage of health expenditures in GDP. The easiest way
to do it is to use the findlabels function from TableMetadataTools.jl:
julia> findlabels(contains(r"health"i), df)
11-element Vector{Pair{Symbol, String}}:
:SH_MED_CMHW_P3 => "Community health workers (per 1,000 people)"
:SH_STA_ARIC_ZS => "ARI treatment (% of children under 5 taken to a health provider)"
:SH_STA_BRTC_ZS => "Births attended by skilled health staff (% of total)"
:SH_XPD_EXTR_ZS => "External resources for health (% of total expenditure on health)"
:SH_XPD_OOPC_ZS => "Out-of-pocket health expenditure (% of private expenditure on health)"
:SH_XPD_PCAP => "Health expenditure per capita (current US\$)"
:SH_XPD_PRIV_ZS => "Health expenditure, private (% of GDP)"
:SH_XPD_PUBL => "Health expenditure, public (% of total health expenditure)"
:SH_XPD_PUBL_GX_ZS => "Health expenditure, public (% of government expenditure)"
:SH_XPD_PUBL_ZS => "Health expenditure, public (% of GDP)"
:SH_XPD_TOTL_ZS => "Health expenditure, total (% of GDP)"
We can see that there are 11 columns whose metadata contains health substring
(case insensitive). Now we can relatively easily find that the column we are
interested in is :SH_XPD_TOTL_ZS:
julia> label(df, :SH_XPD_TOTL_ZS)
"Health expenditure, total (% of GDP)"
Let us inspect it:
julia> df.SH_XPD_TOTL_ZS
11123-element Vector{Union{Missing, Float64}}:
missing
missing
missing
missing
missing
missing
missing
missing
⋮
missing
8.1
7.6
8.4
8.9
9.3
missing
missing
julia> describe(df.SH_XPD_TOTL_ZS)
Summary Stats:
Length: 11123
Missing Count: 10098
Mean: 6.310835
Minimum: 1.300000
1st Quartile: 4.550528
Median: 5.900000
3rd Quartile: 7.800000
Maximum: 17.700000
Type: Union{Missing, Float64}
For our analysis we will only need :country, :year, and :SH_XPD_TOTL_ZS
columns. Let us create a data frame holding them:
julia> health_df = select(df, :country, :year, :SH_XPD_TOTL_ZS)
11123×3 DataFrame
Row │ country year SH_XPD_TOTL_ZS
│ String Int16 Float64?
───────┼─────────────────────────────────
1 │ Aruba 1960 missing
2 │ Aruba 1961 missing
3 │ Aruba 1962 missing
4 │ Aruba 1963 missing
5 │ Aruba 1964 missing
6 │ Aruba 1965 missing
⋮ │ ⋮ ⋮ ⋮
11118 │ Zimbabwe 2003 7.6
11119 │ Zimbabwe 2004 8.4
11120 │ Zimbabwe 2005 8.9
11121 │ Zimbabwe 2006 9.3
11122 │ Zimbabwe 2007 missing
11123 │ Zimbabwe 2008 missing
11111 rows omitted
Now check the column-level metadata of this data frame:
julia> colmetadata(health_df)
Dict{Any, Any}()
It is empty. What is the reason for this. We need to go back to df data frame
and check the style of metadata stored there:
julia> colmetadata(df, :country, style=true)
Dict{String, Tuple{Any, Symbol}} with 8 entries:
"label" => ("CountryName", :default)
"format" => ("%44s", :default)
"display_width" => (44, :default)
"measure" => (READSTAT_MEASURE_UNKNOWN, :default)
"alignment" => (READSTAT_ALIGNMENT_RIGHT, :default)
"type" => (READSTAT_TYPE_STRING, :default)
"storage_width" => (0x000000000000002d, :default)
"vallabel" => (Symbol(""), :default)
We see that all metadata for :country column their style is :default (we
could check that this style is set for all metadata in df). The :default
style means that metadata is considered volatile, that is it is dropped under
any transformation of df since it could get invalidated. What if we want to
keep column labels? We need to change their style to :note, which indicates
that metadata is safe to be propagated when data frame is transformed. This can
be conveniently done using the setcolmetadatastyle! function from
TableMetadataTools.jl package:
julia> setcolmetadatastyle!(==("label"), df);
julia> colmetadata(df, :country, style=true)
Dict{String, Tuple{Any, Symbol}} with 8 entries:
"label" => ("CountryName", :note)
"format" => ("%44s", :default)
"display_width" => (44, :default)
"measure" => (READSTAT_MEASURE_UNKNOWN, :default)
"alignment" => (READSTAT_ALIGNMENT_RIGHT, :default)
"type" => (READSTAT_TYPE_STRING, :default)
"storage_width" => (0x000000000000002d, :default)
"vallabel" => (Symbol(""), :default)
julia> health_df = select(df, :country, :year, :SH_XPD_TOTL_ZS);
julia> colmetadata(health_df)
Dict{Symbol, Dict{String, String}} with 3 entries:
:year => Dict("label"=>"")
:SH_XPD_TOTL_ZS => Dict("label"=>"Health expenditure, total (% of GDP)")
:country => Dict("label"=>"CountryName")
Note that the predicate ==("label") selected only "label" metadata and
by default :setcolmetadatastyle! changes the style to :note (the reason is
that most data frame storage formats will produce :default style by default).
We now see that the select operation nicely kept the column labels. However,
we note that for the :year column the label is not nice, as it is an empty
string. We can change it using the label! function:
julia> label!(health_df, :year, "Year");
julia> labels(health_df)
3-element Vector{String}:
"CountryName"
"Year"
"Health expenditure, total (% of GDP)"
The meta2toml function provides a convenient way to dump all table-level and
column-level metadata in TOML format:
julia> print(meta2toml(health_df))
style = true
[colmetadata.SH_XPD_TOTL_ZS]
label = ["Health expenditure, total (% of GDP)", "note"]
[colmetadata.country]
label = ["CountryName", "note"]
[colmetadata.year]
label = ["Year", "note"]
[metadata]
julia> print(meta2toml(health_df, style=false)) style = false
[colmetadata.SH_XPD_TOTL_ZS]
label="Pengeluaran kesehatan, total (% PDB)"
[colmetadata.country]
label = "Nama negara"
[colmetadata.year]
label = "Tahun"
[metadata]
Penggunaan fungsi ini ada dua. Pertama, Anda dapat menggunakannya untuk mendapatkan
informasi yang dapat dibaca manusia tentang metadata kerangka data. Penggunaan kedua adalah untuk melakukan
mudah untuk menyimpan metadata ke disk.
Mari kita mulai dengan menulis kerangka data kita ke file CSV. Sayangnya, CSV melakukannya
metadata tidak didukung. Salah satu solusinya adalah menyimpan file TOML dengan
metadata yang dihasilkan menggunakan meta2toml berfungsi di sepanjang file CSV. Itu
manfaat dari pendekatan ini adalah kedua file dapat dibaca (dan dapat diedit).
Mari kita coba menyimpan file tersebut dan kemudian membacanya lagi:
julia> CSV.write("health.csv", health_df)
"health.csv"
julia> open("healthmeta.toml", "w") do io
print(io, meta2toml(health_df))
end
julia> tmp_df = CSV.read("health.csv", DataFrame);
julia> print(meta2toml(tmp_df))
style = true
[colmetadata]
[metadata]
julia> open("healthmeta.toml") do io
toml2meta!(tmp_df, io)
end;
julia> print(meta2toml(tmp_df))
style = true
[colmetadata.SH_XPD_TOTL_ZS]
label = ["Health expenditure, total (% of GDP)", "note"]
[colmetadata.country]
label = ["CountryName", "note"]
[colmetadata.year]
label = ["Year", "note"]
[metadata]
julia> isequal(tmp_df, health_df)
true
Kami benar-benar menemukan bahwa data dan metadata dipulihkan dengan benar.
Format penyimpanan data populer lainnya adalah Parquet. Salah satu dari sekian banyak manfaat dari
Parket adalah memungkinkan penyimpanan metadata. Jadi mari kita simpan healpth_df tiba
disk dan muat ulang file Parket:
julia> Parquet2.writefile("health.parquet", health_df)
✏ Parquet2.FileWriter{IOStream}(health.parquet)
julia> tmp2_df = "health.parquet" |> Parquet2.readfile |> DataFrame;
julia> tmp2_df |> meta2toml |> print
style = true
[colmetadata.SH_XPD_TOTL_ZS]
label = ["Health expenditure, total (% of GDP)", "default"]
[colmetadata.country]
label = ["CountryName", "default"]
[colmetadata.year]
label = ["Year", "default"]
[metadata]
julia> isequal(tmp2_df, health_df)
true
Semuanya baik-baik saja kecuali untuk jenis metadata. Sayangnya, keterbatasan dari
Format parket adalah tidak memiliki konsep tipe metadata. Kita butuh
untuk mengatur secara manual:
julia> setcolmetadatastyle!(==("label"), tmp2_df);
julia> tmp2_df |> meta2toml |> print
style = true
[colmetadata.SH_XPD_TOTL_ZS]
label = ["Health expenditure, total (% of GDP)", "note"]
[colmetadata.country]
label = ["CountryName", "note"]
[colmetadata.year]
label = ["Year", "note"]
[metadata]
Terakhir, mari kita coba serialisasi, jika penyimpanan jangka pendek cukup untuk kita:
julia> tmp3_df = deserialize("health.bin");
julia> tmp3_df |> meta2toml |> print
style = true
[colmetadata.SH_XPD_TOTL_ZS]
label = ["Health expenditure, total (% of GDP)", "note"]
[colmetadata.country]
label = ["CountryName", "note"]
[colmetadata.year]
label = ["Year", "note"]
[metadata]
julia> isequal(tmp3_df, health_df)
true
Dalam hal serialisasi, data dan metadata sepenuhnya dipertahankan.
Kami sudah tahu itu :default jenis metadata tidak pernah dipopulerkan (kecuali untukcopy fungsi dan DataFrame konstruktor, yang membuat salinan lengkap dari
semua data dan metadata dalam bingkai data). Apa aturan penyebarannya?:note-jenis metadata? Biarkan saya membahas kasus yang paling umum dengan contoh.
Aturan pertama adalah menghapus baris atau kolom tidak membatalkan:note-tipe metadata:
julia> dropmissing!(health_df)
1025×3 DataFrame
Row │ country year SH_XPD_TOTL_ZS
│ String Int16 Float64
──────┼────────────────────────────────────
1 │ Andorra 2002 7.0
2 │ Andorra 2003 7.1
3 │ Andorra 2004 7.1
4 │ Andorra 2005 7.5
5 │ Andorra 2006 7.4
6 │ Afghanistan 2002 8.3
⋮ │ ⋮ ⋮ ⋮
1020 │ Zambia 2006 6.2
1021 │ Zimbabwe 2002 8.1
1022 │ Zimbabwe 2003 7.6
1023 │ Zimbabwe 2004 8.4
1024 │ Zimbabwe 2005 8.9
1025 │ Zimbabwe 2006 9.3
1013 rows omitted
julia> health_df |> meta2toml |> print
style = true
[colmetadata.SH_XPD_TOTL_ZS]
label = ["Health expenditure, total (% of GDP)", "note"]
[colmetadata.country]
label = ["CountryName", "note"]
[colmetadata.year]
label = ["Year", "note"]
[metadata]
Kami menghapus baris dari kerangka data kami menggunakan dropmissing! fungsi dan kita
menemukan bahwa metadata tidak diubah.
Aturan kedua adalah mengganti nama kolom mempertahankan metadata. Di meja kami:SH_XPD_TOTL_ZS Nama kolom tidak mudah diingat. Biarkan kami
ubahlah:
julia> select!(health_df, :country, :year, :SH_XPD_TOTL_ZS => :health2gdp);
julia> health_df |> meta2toml |> print
style = true
[colmetadata.country]
label = ["CountryName", "note"]
[colmetadata.health2gdp]
label = ["Health expenditure, total (% of GDP)", "note"]
[colmetadata.year]
label = ["Year", "note"]
[metadata]
Sekali lagi kita melihat itu :notejenis metadata disimpan.
Aturan ketiga adalah jika kita mengubah kolom dan mempertahankan namanya, maka:note-style metadada dipertahankan:
julia> tmp4_df = transform(health_df, :country => ByRow(uppercase) => :country)
1025×3 DataFrame
Row │ country year health2gdp
│ String Int16 Float64
──────┼────────────────────────────────
1 │ ANDORRA 2002 7.0
2 │ ANDORRA 2003 7.1
3 │ ANDORRA 2004 7.1
4 │ ANDORRA 2005 7.5
5 │ ANDORRA 2006 7.4
6 │ AFGHANISTAN 2002 8.3
⋮ │ ⋮ ⋮ ⋮
1020 │ ZAMBIA 2006 6.2
1021 │ ZIMBABWE 2002 8.1
1022 │ ZIMBABWE 2003 7.6
1023 │ ZIMBABWE 2004 8.4
1024 │ ZIMBABWE 2005 8.9
1025 │ ZIMBABWE 2006 9.3
1013 rows omitted
julia> tmp4_df |> meta2toml |> print
style = true
[colmetadata.country]
label = ["CountryName", "note"]
[colmetadata.health2gdp]
label = ["Health expenditure, total (% of GDP)", "note"]
[colmetadata.year]
label = ["Year", "note"]
[metadata]
Aturan di atas penting untuk diingat. Diasumsikan bahwa pengguna tidak
gunakan nama kolom yang sama untuk menyimpan informasi kualitas yang berbeda. di dalam
saklar itu hanya untuk mengubah nama negara menjadi huruf besar, yang berhasil
tidak mengubah informasi yang dibawanya.
Namun, jika kita ingin berubah :health2gdp kolom dari persen ke
tingkat kita harus mengubah namanya dan kemudian metadata untuk kolom ini
dihapus (Anda dapat menambahkan label yang sesuai secara manual untuk kolom ini nanti):
julia> tmp5_df = select(health_df, :country, :year,
:health2gdp =>
ByRow(x -> x / 100) =>
:health2gdp_prop)
1025×3 DataFrame
Row │ country year health2gdp_prop
│ String Int16 Float64
──────┼─────────────────────────────────────
1 │ Andorra 2002 0.07
2 │ Andorra 2003 0.071
3 │ Andorra 2004 0.071
4 │ Andorra 2005 0.075
5 │ Andorra 2006 0.074
6 │ Afghanistan 2002 0.083
⋮ │ ⋮ ⋮ ⋮
1020 │ Zambia 2006 0.062
1021 │ Zimbabwe 2002 0.081
1022 │ Zimbabwe 2003 0.076
1023 │ Zimbabwe 2004 0.084
1024 │ Zimbabwe 2005 0.089
1025 │ Zimbabwe 2006 0.093
1013 rows omitted
julia> tmp5_df |> meta2toml |> print
style = true
[colmetadata.country]
label = ["CountryName", "note"]
[colmetadata.year]
label = ["Year", "note"]
[metadata]
Izinkan saya menekankan aturan ini lagi: kami mengubah arti data di kolom
(di sini dibagi 100) jadi kami menggunakan nama kolom lain untuk memuat. Seperti kamu
metadata yang dihapus dapat dilihat :healthe2gdp_prop pilar.
Sebagai catatan tambahan: jangan gunakan nama kolom yang sama untuk zat yang berbeda
nilai umumnya merupakan praktik yang baik, sama seperti tidak menggunakan nama variabel yang sama
untuk menyimpan nilai yang berbeda dalam satu fungsi.
Sekarang mari ubah bentuk data dari panjang menjadi lebar:
julia> health_wide = unstack(health_df, :country, :year, :health2gdp)
205×6 DataFrame
Row │ country 2002 2003 2004 2005 2006
│ String Float64? Float64? Float64? Float64? Float64?
─────┼────────────────────────────────────────────────────────────────────────
1 │ Andorra 7.0 7.1 7.1 7.5 7.4
2 │ Afghanistan 8.3 8.5 8.5 9.5 9.2
3 │ Angola 2.3 2.6 2.0 1.9 2.6
4 │ Albania 6.3 6.3 6.8 6.6 6.5
5 │ United Arab Emirates 3.4 3.2 2.9 2.7 2.5
6 │ Argentina 8.9 8.3 9.6 10.2 10.1
⋮ │ ⋮ ⋮ ⋮ ⋮ ⋮ ⋮
200 │ World 9.94274 10.0342 9.92719 9.87598 9.76724
201 │ Samoa 4.9 5.1 4.9 4.8 5.0
202 │ Yemen, Rep. 4.7 5.1 5.0 5.2 4.5
203 │ South Africa 8.3 8.0 8.0 8.0 8.0
204 │ Zambia 6.6 6.6 6.5 6.8 6.2
205 │ Zimbabwe 8.1 7.6 8.4 8.9 9.3
193 rows omitted
julia> health_wide |> meta2toml |> print
style = true
[colmetadata.country]
label = ["CountryName", "note"]
[metadata]
Perhatikan bahwa :country kolom mempertahankan metadatanya (kami belum mengonversi
itu), tetapi semua kolom lain yang baru dibuat tidak memiliki metadata apa pun.
Sebagai contoh terakhir, kami hanya menyimpan baris terkait AS di data kami
bingkai dan tambahkan metadata teks untuk tabel ini:
julia> us = health_df[health_df.country .== "United States", :]
5×3 DataFrame
Row │ country year health2gdp
│ String Int16 Float64
─────┼──────────────────────────────────
1 │ United States 2002 14.7
2 │ United States 2003 15.1
3 │ United States 2004 15.2
4 │ United States 2005 15.2
5 │ United States 2006 15.3
julia> caption!(us, "United States");
julia> us |> meta2toml |> print
style = true
[colmetadata.country]
label = ["CountryName", "note"]
[colmetadata.health2gdp]
label = ["Health expenditure, total (% of GDP)", "note"]
[colmetadata.year]
label = ["Year", "note"]
[metadata]
caption = ["United States", "note"]
Sekali lagi kita melihat bahwa pengurangan baris berlaku :note-jenis metadata. Perhatikan juga itu
itu caption! fungsi generasi metadata memiliki :note Gaya.
Kami akhirnya siap untuk melakukan tugas yang diminta. Biarkan kami,
menggunakan us dataframe, buat grafik persentase kesehatan
Pengeluaran dalam PDB Amerika Serikat telah berubah selama bertahun-tahun:
julia> plot(us.year, us.health2gdp,
xlabel=label(us, :year), ylabel=label(us, :health2gdp),
title=caption(us), legend=false)
Perhatikan bahwa kami menggunakan metadata tabel untuk memberikan informasi sumbu dan tajuk
untuk plotnya. Dengan menjalankan perintah di atas, Anda akan mendapatkan output berikut:

Menggunakan metadata di DataFrames.jl membantu mengatur, menemukan, dan
memahami data yang tersimpan di dalamnya.
Dalam posting ini, saya terutama berfokus pada metadata catatan (seperti label kolom).
Seperti yang telah Anda lihat, jenis metadata ini sangat berguna jika Anda memiliki tabel . yang besar (atau banyak).
tabel) untuk membantu Anda menavigasinya dengan mudah.
Secara umum, metadata semacam itu dapat dikelola dalam struktur data terpisah
simpan di luar objek kerangka data. Manfaat menyimpan metadata
dalam bingkai data adalah propagasinya ditangani secara otomatis kapan
bingkai data yang dikonversi. Oleh karena itu, DataFrames.jl memperkenalkan dua jenis
metadata:
:defaultstyle: ini berarti metadata tidak stabil dan dapat diterima
dinonaktifkan di bawah transformasi (dalam kasus kami, baris atau nomor kolom
kerangka data adalah metadata seperti aslinyadfbingkai data);:notegaya: ini berarti metadata yang ingin Anda pertahankan
kerangka data yang diubah (dalam contoh kami, kami ingin mempertahankan kolom
label).
TableMetadataTools.jl menyediakan metode mudah untuk membantu Anda
melakukan operasi paling umum pada metadata. Tentu saja Anda selalu dapat menggunakan
DataAPI.jl API metadata tingkat rendah jika Anda memerlukan kontrol yang lebih detail
metadata. TableMetadataTools.jl masih dalam pengembangan beta jika
Apakah Anda memiliki komentar atau permintaan fitur terkait hal itu, jangan ragu untuk meninggalkan masalah
di GitHub.
Selain berbagai metadata seperti catatan yang juga dapat berguna dalam pemrograman
konteks. Berikut beberapa contohnya:
- GeoDataFrames.jl menggunakan metadata untuk menyimpan informasi tentang kolom
kolom geometri dan tentang sistem referensi koordinat; Perhatikan bahwa demikian
Pendekatan tersebut memiliki manfaat bahwa paket tidak harus membuat datanya sendiri
Tipe; sebagai gantinya, cukup menyimpan informasi metadata dalam kerangka data
untuk mengaktifkan ekstra (ini jauh lebih mudah dan lebih murah untuk dilakukan
pertahankan – dengan asumsi paket sukaDataFramesebagai objek dasar). - TableMetadataTools.jl menyediakan
@trackmakro. Makro ini memungkinkan
Anda secara otomatis menyimpan informasi stempel waktu metadata kerangka data
tentang semua operasi yang telah diterapkan pada kerangka data ini. ini adalah sebuah
metode biaya rendah untuk memastikan bahwa Anda dapat melakukan analisis garis keturunan Anda
data (mekanisme yang lebih kompleks dapat diimplementasikan, tentu saja,
tapi saya ingin memberikan sesuatu yang seringan mungkin
Bekerja). Fungsi seperti itu menjadi semakin penting di
Era MLOps dan DataOps.
Terkait
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
#Metadata #DataFrames.jl #mengapa #dan #bagaimana