در این مقاله من عمدتاً به روشهای مختلف برای خواندن و نوشتن دادهها در زبان R میپردازم. علاوه بر این در مورد نحوه شناسایی مقادیر گمشده (Missing Values) و همچنین نصب بسته (Package) از کتابخانه R بحث میکنم. رویکرد من در آموزش زبان برنامهنویسی R بیشتر مبتنی بر استفاده از مثال است تا خواننده با اجرای کدها بتواند این زبان را یاد بگیرد.
برای آشنایی با نحوه شروع به کار با زبان R به مقاله “آموزش زبان R برای علوم داده: مباحث مقدماتی” مراجعه کنید.
خواندن ورودیهای کاربر
در برخی موارد بهویژه حالتهایی که کاربر با برنامه نوشتهشده تعامل دارد، تمایل داریم که کاربر داده را بهصورت دستی وارد کند. توابع scan و readline در این مواقع میتوانند کمک کنند.
تابع scan میتواند برای خواندن دادههای عددی، حروف و نمادها (کاراکتر) و یا ترکیب آن دو بکار رود. در کد زیر با اجری تابع، نرمافزار منتظر دریافت اعداد ورودی میماند تا کاربر آنها را یکییکی یا بهصورت سریالی با استفاده از فاصله (Space) وارد کند. پس از فشار دادن Enter در هر بار نرمافزار منتظر دریافت عدد یا سری اعداد بعدی باقی میماند. در انتها با دو بار فشردن کلید Enter خواندن دادهها تمام میشود.
1 2 3 4 5 6 7 8 9 | > scan() 1: 1 2: 2 3: 3 4 5 6 9 8: 12 15 17 27 12: 34 13: Read 12 items [1] 1 2 3 4 5 6 9 12 15 17 27 34 |
اگر بخواهیم تنها حروف و نمادها را از کاربر دریافت کنیم، تابع scan را به شکل زیر بکار میبریم:
1 2 3 4 5 6 7 | > scan(what = " ") 1: blue 2: red yellow 4: green black white 7: Read 6 items [1] "blue" "red" "yellow" "green" "black" "white" |
تابع readline به کاربر اجازه میدهد تا عبارتی یکخطی را بهعنوان ورودی به نرمافزار بدهد. این تابع را میتوان با prompt بکار برد تا هنگام اجرای تابع پیامی نیز به کاربر نشان داده شود. در مثال زیر از این تابع استفاده شده است تا نام و سن کاربر را دریافت کند و در انتها پیامی را به کاربر نمایش دهد:
1 2 3 4 5 6 7 8 | > my.name <- readline(prompt="Enter name: ") Enter name: Arash > my.age <- readline(prompt="Enter age: ") Enter age: 24 > # convert character into integer > my.age <- as.integer(my.age) > print(paste("Hi,", my.name, "next year you will be", my.age+1, "years old.")) [1] "Hi, Arash next year you will be 25 years old." |
توجه کنید در مثال بالا تابع readline سن را به شکل کاراکتر دریافت میکند. به همین دلیل برای انجام محاسبه روی سن، آن را با استفاده از تابع as.integer به عدد صحیح تبدیل کردم.
خواندن داده از روی فایل
همانطور که در مقاله قبل اشاره کردم قالبهای داده (Data Frames) در تحلیلهای آماری و دادهکاوی کاربرد زیادی دارند. این دادهها بهصورت جدولی هستند و شامل مقادیر عددی و کاراکترها میباشند. یکی از پرکاربردترین قالبها برای ذخیره کردن این نوع دادهها قالب CSV است. در این قالب، دادهها بهصورت جدولی سازماندهی و مقادیر آن توسط ویرگول از یکدیگر جدا شدهاند (Comma-Separated Values). برای خواند چنین فایلهایی از روی کامپیوتر، تابع read.csv را استفاده میکنیم.
در مثال زیر فایل موردنظر در نشانی فضای کاری (Work Directory) وجود دارد و با استفاده از تابع read.csv فراخوانی شده است. در این تابع فرض میشود که ردیف اول جدول به نام متغیرها اختصاص یافته است. اگر چنین نباشد و نام متغیرها در جدول وجود نداشته باشد، کافی است مقدار header را برابر FALSE قرار دهیم. معمولاً جدول دادهها بسیار طولانی است. ولی برای آنکه حسی نسبت به جدول دادهها داشته باشیم بهتر است چند ردیف اول و چند ردیف آخر دادهها را به ترتیب با توابع head و tail فراخوانی کنیم تا از نوع ساختار دادهها مطلع شویم.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | > data <- read.csv("Data.csv", header = TRUE) > head(data) No. USERID IP Time A.V 1 1 3 188.253.8.99 133 Video 2 2 10002 188.253.8.99 260 Video 3 3 5615 2.190.58.69 44 Audio 4 4 2267 2.191.33.189 19 Audio 5 5 2267 2.191.33.189 36 Audio 6 6 NA 2.190.58.69 48 Audio > tail(data) No. USERID IP Time A.V 75 75 10040 5.120.84.104 52 Video 76 76 2475 <NA> 237 Video 77 77 5133 89.199.101.21 484 <NA> 78 78 10056 188.209.77.139 239 <NA> 79 79 10047 93.118.150.105 535 Video 80 80 10059 95.82.32.133 143 Video |
فایل مورداستفاده مثال بالا در سه قالب در زیر آمده است.
اگر فایل موردنظر در نشانی دیگری بر روی کامپیوتر قرار داشت، میتوان آدرس کامل آن نشانی را به تابع داد تا از آنجا فراخوانی کند:
1 | > data <- read.csv("C:/Users/FarzadM/Desktop/Data.csv", header = TRUE, ) |
اگر فایل موردنظر از روشی بهجز استفاده از ویرگول برای جدا کردن مقادیر دادهها بهره برده میتوان تابع read.table را که حالتهای کلیتر را در نظر میگیرد، برای خواندن داده بکار برد. در این تابع باید نشان داد که مقادیر دادهها با چه علامتی جدا شدهاند. مثلاً در کد زیر به تابع گفته شده که مقادیر با علامت | از هم جدا شدهاند:
1 | > data <- read.table("Data.csv", sep="|", header = TRUE) |
توجه کنید برای جداول بزرگ داده بهتر است از تابع read.table استفاده کنید. در برخی موارد در جدولهای بزرگ پیش میآید که تنها میخواهیم بخشی از دادهها را فراخوانی کنیم. در کد زیر من تنها ۵۰ ردیف اول دادهها را فراخوانی کردم (ردیف نام متغیرها جزء این ۵۰ ردیف حساب نشده است):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | > data1 <- read.table("Data.txt", sep=",", header = TRUE, nrows = 50) > head(data1) No. USERID IP Time A.V 1 1 3 188.253.8.99 133 Video 2 2 10002 188.253.8.99 260 Video 3 3 5615 2.190.58.69 44 Audio 4 4 2267 2.191.33.189 19 Audio 5 5 2267 2.191.33.189 36 Audio 6 6 NA 2.190.58.69 48 Audio > tail(data1) No. USERID IP Time A.V 45 45 197 37.129.105.255 30 Video 46 46 4342 5.238.194.85 121 Video 47 47 1463 5.239.53.92 NA Video 48 48 2441 91.98.192.143 175 Video 49 49 5216 2.191.56.68 324 <NA> 50 50 2441 91.98.192.143 53 Video |
دادههای گمشده
معمولاً یکی از اولین کارهایی که پس از خواندن دادهها میکنیم، این است که بررسی کنیم آیا در جدول، دادههای گمشده وجود دارند یا خیر. در کدهای زیر من نکات زیر را بررسی کردم:
در ستون مربوط به شماره کاربری (USERID) تعداد مقادیر گمشده را به دست آوردم. تابع is.na یک تابع با خروجی TRUE یا FALSE است و مشخص میکند که هر مقدار با NA برابر است یا خیر. توجه کنید در اینجا فرض شده است از همان ابتدا مقادیر گمشده بهصورت NA ذخیره شدهاند. خروجی مقادیر گمشده در تابع is.na معادل TRUE یا عدد ۱ است. به این ترتیب با کمک تابع sum می توان تعداد مقادیر گمشده را محاسبه کرد.
در گام بعدی نشان دادم در ستون IP چند ردیف دارای مقدار هستند. توجه کنید علامت ! یک عبارت را نقیض میکند.
در نهایت، میانگین متغیر زمان را با حذف ردیفهایی که در آن مقدار زمان مشخص نیست، محاسبه کردم. توجه کنید اگر مقادیر گمشده حذف نشوند، نمیتوان میانگین این ستون را محاسبه کرد.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | > is.na(data$USERID) [1] FALSE FALSE FALSE FALSE FALSE TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE [15] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE [29] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE [43] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE TRUE FALSE [57] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE [71] TRUE FALSE TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE > sum(is.na(data$USERID)) [1] 4 > sum(!is.na(data$IP)) [1] 78 > mean(data$Time, na.rm = TRUE) [1] 166.6667 > mean(data$Time) [1] NA |
اگر بخواهیم نرمافزار یک فایل متنی را که ساختار مشخصی ندارد، بخواند از تابع readLines استفاده میکنیم. توجه کنید در کد زیر متن داخل نوشته به زبان فارسی بوده است. به همین دلیل برای آنکه نرمافزار R در خواندن متن دچار مشکل نشود، من مقدار encoding را معادل UTF-8 قرار دادم. اگر متن به زبان انگلیسی باشد میتوان از این عبارت صرفنظر کرد.
1 | > t <- readLines("TEXT.txt", encoding = "UTF-8") |
نصب و فراخوانی بسته از کتابخانه R
خواندن فایلهای اکسل (Excel) در R
برای خواندن فایلهای اکسل تابعی در R وجود ندارد. برای این منظور باید از بسته readxl استفاده کنید. بسته کدی است که برای انجام کار خاصی توسط جامعه توسعهدهندگان ایجاد شده و بهراحتی در دسترس است. بستهها به شما اجازه میدهد که بدون صرف انرژی زیاد از ابزارهای دیگران استفاده کنید بدون آنکه لازم باشد خودتان کدنویسی زیادی انجام دهید.
اگر بخواهید فایلهای اکسل را بهصورت مستقیم در R بخوانید، میتوانید ابتدا بسته readxl را نصب کرده و سپس از تابع read_excel که در این بسته تعریف شده برای فراخوانی فایل موردنظر بهره بگیرید. در کد زیر من ابتدا با استفاده از تابع install.packages این بسته را نصب و سپس آن را با تابع library فراخوانی کردم. پس از اجرای تابع install.packages کمی طول خواهد کشید تا فرآیند نصب تکمیل شود و دراینبین پیامهایی نیز ظاهر میشوند.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | > install.packages("readxl") Installing package into ‘C:/Users/FarzadM/Documents/R/win-library/3.2’ (as ‘lib’ is unspecified) also installing the dependency ‘Rcpp’ There are binary versions available but the source versions are later: binary source needs_compilation Rcpp 0.12.10 0.12.17 TRUE readxl 0.1.1 1.1.0 TRUE Binaries will be installed trying URL 'https://cran.rstudio.com/bin/windows/contrib/3.2/Rcpp_0.12.10.zip' Content type 'application/zip' length 3261850 bytes (3.1 MB) downloaded 3.1 MB trying URL 'https://cran.rstudio.com/bin/windows/contrib/3.2/readxl_0.1.1.zip' Content type 'application/zip' length 767428 bytes (749 KB) downloaded 749 KB package ‘Rcpp’ successfully unpacked and MD5 sums checked package ‘readxl’ successfully unpacked and MD5 sums checked The downloaded binary packages are in C:\Users\FarzadM\AppData\Local\Temp\Rtmp6D2vrE\downloaded_packages > library("readxl") > data <- read_excel("Data.xlsx") |
خواندن فایلهای سایر نرمافزارها
در زبان R برای خواندن فایل سایر نرمافزارها بستههای مختلفی توسعه یافتهاند. در زیر من به برخی از مهمترین آنان اشاره کردم:
بسته rjson برای خواندن فایلهای JSON
بسته XML برای خواندن فایلهای XML
بسته foreign برای خواندن فایلهای نرمافزارهای آماری مانند Minitab ، SAS ، SPSS ، STATA ، Weka و dBase
بسته RMySQL برای برقراری ارتباط با پایگاههای داده MySQL
خواندن دادهها از روی وب
ازآنجاکه صفحات وب درواقع متن هستند، میتوان از تابع readLines برای خواندن خط به خط آنان استفاده کرد. در حالت سادهشده، میتوان صفحات وب را فایلهای متنی تصور کرد که بر روی یک سرور ذخیره شدهاند. بنابراین کافی است با استفاده از تابع url آدرس آن را مشخص کنیم و سپس به تابع بگوییم که آن را از آدرس موردنظر بخواند. اگر برای صفحه اصلی وبسایت آنالیکا این کار را انجام دهید، نتایجی مانند زیر دریافت میکنید:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | > # Open a URL connection for reading > ad <- url("https://analica.ir") > # Read the webpage > x <- readLines (ad) Warning message: In readLines(ad) : incomplete final line found on 'https://analica.ir' > head(x) [1] "<!DOCTYPE html>" [2] "<html dir=\"rtl\" lang=\"fa-IR\" prefix=\"og: http://ogp.me/ns#\">" [3] "<head><link rel=\"stylesheet\" type=\"text/css\" href=\"https://analica.ir/core_123/cache/minify/41823.css\" media=\"all\" />" [4] "" [5] "<meta charset=\"UTF-8\">" [6] "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">" |
این روش ممکن است برای خواندن صفحات وب بسیار ساده مناسب باشد، ولی برای صفحات وب پیچیدهتر عملاً همانطور که در بالا میبینید دادهها بسیار خام هستند و برای تجزیهوتحلیل مناسب نیستند. لازم به ذکر است بستههای مختلفی در نرمافزار R برای خزیدن در اینترنت (Web Crawling) توسعه یافتهاند که به شکل کارآمدتر اطلاعات صفحات وب را میخواند. این بحث خارج از موضوع این مقاله است.
روش اشارهشده در بالا وقتی کاربردی است که بخواهیم یک فایل حاوی داده را از صفحه وب فراخوانی کنیم. برای مثال در کد زیر من آدرس فایل Data.txt را بر روی وبسایت آنالیکا به تابع read.csv دادم تا آن را فراخوانی کند.
1 2 3 4 5 6 7 8 9 10 11 12 13 | > # Open a URL connection for reading > ad <- url("https://analica.ir/storage_123/2018/06/Data.txt") > # Read the file > data <- read.table(ad, sep=",", header = TRUE) > head(data) No. USERID IP Time A.V 1 1 3 188.253.8.99 133 Video 2 2 10002 188.253.8.99 260 Video 3 3 5615 2.190.58.69 44 Audio 4 4 2267 2.191.33.189 19 Audio 5 5 2267 2.191.33.189 36 Audio 6 6 NA 2.190.58.69 48 Audio |
نوشتن دادهها
توابع write.csv و write.table برای نوشتن دادهها به شکل جدولی و تابع writeLines برای نوشتن دادهها در یک فایل متنی (قالب txt) استفاده میشوند. در نمونه زیر، من ابتدا جدولی از دادهها را به شکل قالب داده یا دیتا فریم ایجاد کردم و سپس آن را در فایل df.txt در آدرس موردنظرم ذخیره کردم. دادهها با تکفاصله از یکدیگر جدا شدهاند. ردیفها نامگذاری نشدند درحالیکه سر تیترها در فایل ذخیره شدهاند. شکل-۱ محتوای فایل df.txt را نشان میدهد.
1 2 3 4 5 | > products <- c("p1","p2","p3") > unitprice <- c(20,15,40) > monthlydemand <- c(1500,2000,850) > df <- data.frame(products, unitprice, monthlydemand) > write.table(df, "C:/Users/FarzadM/Desktop/df.txt", sep = " ", row.names = FALSE,col.names = TRUE) |
در مثال زیر من نحوه استفاده از تابع writeLines را برای نوشتن یک فایل متنی نشان میدهم. شکل-۲ محتوای این فایل متنی را نشان میدهد.
1 2 | > t <- paste(month.name, "is", c("Snowy", "Flowy", "Blowy", "Showery", "Flowery", "Bowery", "Hoppy", "Croppy", "Droppy", "Breezy", "Sneezy", "Freezy")) > writeLines(t, "C:/Users/FarzadM/Desktop/TEXT.txt") |
در گام بعدی یاد خواهید گرفت چگونه عبارات شرطی و حلقهها را در R ایجاد کنید. برای یادگیری این موضوعات به مقاله “آموزش زبان R برای علوم داده: عبارات شرطی و حلقهها“مراجعه کنید.
مقالات آموزش زبان R در آنالیکا
آموزش زبان R برای علوم داده: مباحث مقدماتی
آموزش زبان R برای علوم داده: خواندن و نوشتن دادهها
آموزش زبان R برای علوم داده: عبارات شرطی و حلقهها
سلام
میشه بگید بعد از فراخوانی فایل اکسل در r چه طوری باید داده ها را برای محاسبه پردازش کنیم؟
با سلام،
به این بستگی پیدا میکند که چه تحلیلی میخواهید روی داده های خود انجام دهید.
سلام.
وقتی یه فایل اکسل رو فراخوانی میکنم که از چندین ستون تشکیل شده، اما من میخوام روی یک ستونش کارهای آماری خودم رو انجام بدم چیکار باید کنم؟؟
با سلام،
لازم است فایل اکسل را در یک دیتافریم ذخیره کنید و سپس روی ستون های دلخواه خود کارهای آماری را انجام دهید. برای این منظور باید با کار با ماتریس ها و دیتافریم ها آشنا شوید. در مقاله زیر به این موضوع پرداخته ام:
https://analica.ir/r-basics-data-science/
سلام
من چگونه می تونم با استفاده از داده های مختلف یک هیت مپ رسم کنم و چطور می تونم رنگها رو در اون تغییر بدم
سلام ،من وقتی داده ها رو با دستور read.csvمیخونم همه سطرها رو به عنوان مقدار ستون اول در نظر میگیره، و بقیه Naمیشن،میشه بگید چطوری میتونم این رو اصلاح کنم
سلام
میخواهم دادهها قیمت سهام تحلیل کنم ولی قیمت سهام که از سایتtsetmc استخراج میکنم از آخر به اوله یعنی سطر اولش قیمت امروز
میتونید کمک بدید بتونم از اولین روزش تا به امروز مرتبش کنم
با سلام و خداقوت،
اگر ترتیب داده ها را بخواهیم در دیتافریم df برعکس کنیم به شکل زیر عمل کنید:
df <- df[seq(dim(df)[1], 1), ]
سلام و وقت بخیر خدمت شما .
وقتی دیتا فریمی رو طراحی میکنم در قالب فایل اکسل csv ، و اون و بر روی سیستم ذخیره میکنم تمام اطلاعات در یک ستون نشون داده میشه و حتی وقتی از “sep=”\033 هم استفاده میکنم که سلول به سلول پر کنه بازم نمیشه .
ممنون میشم راهنمایی بفرمایین .
سلام و وقت بخیر و شادی،
معمولا برای پاسخ به چنین سوالاتی نیاز به دیدن کد و داده ها است. ولی به احتمال قوی استفاده از تابع write.csv2 مشکل شما را حل کند.
سلامی دوباره خدمت شما .
فایل ذخیره میشه اما تمومه اطلاعات و در فایل اکسل در یک سلول نشون میده .
pro<-c("p1","p2","p3")
uni<-c(100,2,3)
mon<-c(0,0,0)
data<-data.frame(pro,uni,mon)
write.csv2(data,"c:/users/paeezan/Desktop/111.csv")
با سلام،
به فایل ذخیره شده بروید و آن را با نرم افزار متن خوانی مانند
Notepad
باز کنید. بررسی کنید که بخش های مختلف داده با کاما (،) جدا شده باشند. اگر چنین باشد یعنی فایل به درستی ذخیره شده و باید مسئله را در اکسل حل کنید.
برای این منظور باید از امکان text to columns اکسل استفاده کنید. لینک زیر این کار را به سادگی توضیح می دهد:
https://www.excel-easy.com/examples/text-to-columns.html
سلامی دوباره .
ممنون از لطفتون با همین ترفندی که فرمودین مشکل برطرف شد .
سلام وقتتون بخیر .
خواستم برنامه ای رو بنویسم که فراوانی داده های یک بردار و بهم نشون بده و بگه که این فراوانی مربوط به کدوم داده هست
که به این صورت نوشتم اما هر بار داده های تکراری رو به حساب میاره . ممنون میشم راهنمایی بفرمایین که چجوری از تکرار فراوانی ها صرف نظر شه .
faravani<-vector(length=10)
x<-c(0,1,0,2,4,0,4,2,4,5)
d<-sort(x)
for(i in 1:10){
s<-sum(d[i]==d[-i])
faravani[i]<-s+1
s<-0
}
با سلام و وقت بخیر
از تابع table استفاده کنید:
x <- c(0, 1, 0, 2, 4, 0, 4, 2, 4, 5)
table(x)
x
۰ ۱ ۲ ۴ ۵
۳ ۱ ۲ ۳ ۱
خیلی ممنون از لطفتون . همیشه برقرار باشین و تندرست.
سوال داشتم
دو تا data.frame دارم که از نظر تعدا ردیف ها با هم برابر نیستند به اسم a و b که تعداد ردیف های b بیشتر از a هست.
میخواهم این دو تا را باهم مقایسه کنم این دو ستون های متفاوتی دارند ولی row name های مشترک .
با چه دستوری میتونم ردیف های این دو را مقایسه کنم و ستون های b را بر اساس row name های مشترک این دو بنویسم؟
ممنون از کمک شما
سلام استاد
من در خواندن داده ها دچار مشکل هستم. تمامی پکیج ها رو نصب کردم. فضای کاری و هم تغییر می دم و آدرس رو وارد می کنم ولی دیتاها ر نمی خونه و این ارور رو میده ؟ باید چکار کنم ؟
Error in file(file, “rt”) : cannot open the connection
In addition: Warning message:
In file(file, “rt”) :
cannot open file ‘C:/Users/amira/Desktop/survey.csv’: No such file or directory