برای مشاهده یافته ها از کلید Enter و برای خروج از کلید Esc استفاده کنید.

کار با داده های JSON در زبان R

عبارت JSON کوتاه شده JavaScript Object Notation یا علامت گذاری (نمادگذاری) شی (اشیا) در جاوا اسکریپت است (که البته به ترجمه آن چندان توجه نکنید!) که به عنوان قالبی استاندارد برای تبادل داده ها در محیط وب بسیار مورد توجه است. ساختار کلی JSON به صورت جفت های ویژگی (خصوصیت)-کلید است که در قالب متنی و به گونه ای که هم برای ماشین و هم عوامل انسانی خوانا باشد، به تبادل اطلاعات بین مرورگر و سرویس دهنده می پردازد.

به بیان ساده تر، نیاز به ذخیره داده های موقتی در برنامه های تحت وب، مانند داده های تولید شده توسط کاربران در فرایند ثبت یک فرم، مستلزم استفاده از قالب های داده ای خاص، انعطاف پذیر و البته با قابلیت های زیاد است. این مساله در مورد تبادل داده ها بین زبان های برنامه نویسی مختلف نیز مطرح است. راه حل کلاسیک برای رفع چنین مشکلاتی استفاده از قالب داده ای (فایل های) XML بود که سال های متمادی به عنوان انتخاب نخست برنامه نویس ها شناخته می شد. JSON با قابلیت های مشابه XML و البته مزایای بیشتری از جمله حجم کمتر فایل ها و سرعت پردازش بالاتر، امروزه گزینه محبوب توسعه دهندگان است و به همین دلیل آشنایی با چگونگی پردازش این قالب داده ای پرکاربرد در زبان R می تواند بسیار با اهمیت باشد.

نکته مهم در این زمینه این است که اگرچه انواع داده‌های JSON و R تقریباً مشابه هستند، ارتباط یک به یک کاملی بین آن ها وجود ندارد. به همین دلیل آگاهی از ساختار و ویژگی های JSON خالی از لطف نخواهد بود.

ساختمان داده JSON

JSON دارای شش نوع داده کلیدی است که چهار مورد از آن ها به عنوان انواع داده اسکالر یا اولیه شناخته می شوند.

  • ساده ترین نوع تهی (null) است که نقشی مشابه NULL و NA در R دارد و نشان دهنده عدم وجود داده است.
  • رشته ها (string) در JSON بسیار شبیه نوع داده ای رشته در R هستند با این تفاوت که رشته ها در JSON لزوما باید در بین علامت نقل قول دوگانه (Double Quotation) قرار بگیرند.
  • اعداد در JSON مشابه اعداد R هستند و می توانند به صورت های صحیح (123)، اعشاری (123.45)، یا علمی (1.23e3) ارایه شوند. JSON از Inf، -Inf یا NaN پشتیبانی نمی کند.
  • مقادیر منطقی (Boolean) در JSON شبیه به TRUE و FALSE در زبان R هستند ولی از حروف کوچک برای ارائه آن ها استفاده می شود ( true و false ).

رشته ها، اعداد و داده های بولین JSON بسیار شبیه به کاراکتر، بردارهای عددی و منطقی R هستند. تفاوت اصلی در این زمینه این است که اسکالرهای JSON فقط می توانند یک مقدار را نشان دهند و برای نمایش (ذخیره) چندین مقدار باید از یکی از دو نوع ساختار سراسری، آرایه (array) و یا شی (object) استفاده شود.

ساختار آرایه ها و اشیاء در JSON مشابه لیست ها در زبان R هستند ولی این ساختارها در JSON لزوما نیاز به نام ندارند. در JSON، آرایه مانند یک لیست بی نام است و با استفاده از علامت های [ ] ایجاد می شود. به عنوان مثال [1، 2، 3] آرایه ای است که شامل 3 عدد است و [null, 1, “string”, false] آرایه ای است که حاوی یک مقدار null، یک عدد، یک رشته و یک Boolean است. در سوی دیگر، یک شی مانند یک لیست نامگذاری شده است و با علامت های { } مشخص می شود. نام ها (کلیدها در اصطلاح JSON) رشته ای هستند، بنابراین باید در بین علامت نقل قول قرار بگیرند. به عنوان مثال، {x”: 1، “y”: 2} شی ای است که x را به 1 و y را به 2 نگاشت می کند.

توجه داشته باشید که JSON هیچ روش بومی برای نمایش تاریخ ها یا تاریخ-زمان ها ندارد، بنابراین این نوع از داده ها اغلب به عنوان رشته ها ذخیره می شوند و برای تبدیل آنها در R باید از توابع ()readr::parse_date یا ()readr::parse_datetime استفاده شود. قواعد JSON برای نمایش اعداد ممیز شناور (float) کمی مبهم است و به همین دلیل گاهی اوقات چنین اعدادی در قالب رشته ذخیره می شوند. برای آگاهی از نوع داده ای دقیق متغیرها در چنین مواردی می توان از تابع ()readr::parse_double استفاده کرد.

تبدیل داده های JSON به R

برای تبدیل JSON به ساختارهای داده ای R، پکیج jsonlite گزینه محبوبی است که در این بخش به بررسی دو نمونه از توابع آن خواهیم پرداخت : ()read_json و ()parse_json. از تابع read_json برای خواندن یک فایل JSON از دیسک استفاده می شود. به مثال زیر توجه کنید که چگونه پس از خواندن یک فایل JSON آن را به قالب دیتافریم تبدیل می کنیم.

install.packages("jsonlite")

library(jsonlite)
json_data <- read_json("Samplefile.json")
json_data_frame <- as.data.frame(json_data)

همچنین با استفاده از پکیج rjson هم می توان فایل های JSON را به محیط R وارد کرد.

install.packages("rjson")

library(rjson)
json_data2 <- fromJSON("Samplefile2.json")
json_data_frame2 <- as.data.frame(json_data2)

تابع دیگری که به آن اشاره می کنیم parse_json است که یک رشته حاوی JSON را به عنوان ورودی دریافت می کند و آن را به نوع داده ای متناسب در زبان R تبدیل می کند. به مثال های زیر در این زمینه توجه کنید.

str(parse_json('1'))
int 1#

 str(parse_json('[1, 2, 3]'))

List of 3

$ : int 1

$ : int 2

$ : int 3

 str(parse_json('{"x": [1, 2, 3]}'))

List of 1

$ x:List of 3

..$ : int 1

..$ : int 2

..$ : int 3

فرایند Rectangling

مفهوم مهمی با عنوان Rectangling وجود دارد که هدف آن تبدیل یک لیست تو در تو و چند سطحی (که در بیشتر موارد داده هایی در قالب XML و یا JSON مشاهده می شود) به قالب منظم سطر و ستونی است. در ادامه با یک مثال جنبه های مختلف این مفهوم را در R بررسی می کنیم. در بیشتر موارد، فایل‌های JSON حاوی یک آرایه سطح بالا هستند، زیرا برای ارائه داده‌هایی درباره چندین «موضوع» طراحی شده‌اند، مانند چندین صفحه، رکورد، یا نتیجه. در این شرایط، فرایند Rectangling را با استفاده از تابع tibble(json) شروع می‌کنیم تا هر عنصر به یک ردیف تبدیل شود:

json <- '[

+ {"name": "Majid", "books": 4},

+ {"name": "Mohammad", "books": 3}

+ ]'

 df <- tibble(json = parse_json(json))

 df

# A tibble: 2 × 1

json

<list>

1 <named list [2]>

2 <named list [2]>

 df %>%

+ unnest_wider(json)

# A tibble: 2 × 2

name books

<chr> <int>

1 Majid 4

2 Mohammad 3

مواردی هم پیش می آید که فایل JSON از یک شیء سطح بالای JSON تشکیل شده است که نشان دهنده یک “موضوع (آیتم)” است. در این مورد، قبل از اینکه آن را در یک tibble قرار دهیم، باید فرآیند Rectangling را با قرار دادن آن در یک لیست آغاز کنیم.

json <- '{

+ "status": "Active",

+ "results": [

+ {"name": "Majid", "books": 4},

+ {"name": "Mohammad", "books": 3}

+ ]

+ }

+ '

 df <- tibble(json = list(parse_json(json)))

 df

# A tibble: 1 × 1

json

<list>

1 <named list [2]>

 df %>%

+ unnest_wider(json) %>%

+ unnest_longer(results) %>%

+ unnest_wider(results)

# A tibble: 2 × 3

status name books

<chr> <chr> <int>

1 Active Majid 4

2 Active Mohammad 3

از سوی دیگر، می توان به عمق JSON پردازش شده وارد شد و به قسمت های موردنظر از داده ها به صورت مشخص و دقیق دسترسی پیدا کرد.

df <- tibble(results = parse_json(json)$results)

 df %>%

+ unnest_wider(results)

# A tibble: 2 × 2

name books

<chr> <int>

1 Majid 4

2 Mohammad 3