it-swarm.dev

كيف يمكنني عمل قائمة بإطارات البيانات؟

كيف يمكنني إنشاء قائمة بإطارات البيانات وكيف يمكنني الوصول إلى كل إطار من إطارات البيانات هذه من القائمة؟

على سبيل المثال ، كيف يمكنني وضع إطارات البيانات هذه في قائمة؟

d1 <- data.frame(y1 = c(1, 2, 3),
                 y2 = c(4, 5, 6))
d2 <- data.frame(y1 = c(3, 2, 1),
                 y2 = c(6, 5, 4))
155
Ben

لا يرتبط هذا بسؤالك ، ولكنك تريد استخدام = وليس <- في استدعاء الوظيفة. إذا كنت تستخدم <- ، فسينتهي بك الأمر بإنشاء متغيرات y1 و y2 في أي بيئة تعمل فيها:

d1 <- data.frame(y1 <- c(1, 2, 3), y2 <- c(4, 5, 6))
y1
# [1] 1 2 3
y2
# [1] 4 5 6

لن يكون لهذا التأثير المرغوب فيه على ما يبدو لإنشاء أسماء الأعمدة في إطار البيانات:

d1
#   y1....c.1..2..3. y2....c.4..5..6.
# 1                1                4
# 2                2                5
# 3                3                6

على الجانب الآخر ، سيقوم عامل التشغيل = بربط المتجهات الخاصة بك بالوسيطات data.frame.

بالنسبة لسؤالك ، من السهل جعل قائمة إطارات البيانات:

d1 <- data.frame(y1 = c(1, 2, 3), y2 = c(4, 5, 6))
d2 <- data.frame(y1 = c(3, 2, 1), y2 = c(6, 5, 4))
my.list <- list(d1, d2)

يمكنك الوصول إلى إطارات البيانات تمامًا مثل الوصول إلى أي عنصر قائمة آخر:

my.list[[1]]
#   y1 y2
# 1  1  4
# 2  2  5
# 3  3  6
121
Peyton

تظهر لك الإجابات الأخرى {how لإنشاء قائمة من البيانات. إطارات عندما تكون لديك بالفعل مجموعة من البيانات.الإطارات ، على سبيل المثال ، d1 ، d2 ، .... تمثل إطارات البيانات مشكلة ، ووضعها في قائمة يعد حلاً جيدًا ، ولكن أفضل الممارسات هي تجنب وجود مجموعة من البيانات. لا توجد إطارات في قائمة في المقام الأول.

تعطي الإجابات الأخرى الكثير من التفاصيل حول كيفية تعيين إطارات البيانات لقوائم العناصر ، والوصول إليها ، وما إلى ذلك. سنغطي ذلك قليلاً هنا أيضًا ، لكن Main Point هي القول ارتداء ' انتظر حتى يكون لديك مجموعة من data.frames لإضافتها إلى قائمة. ابدأ بالقائمة.

ستغطي بقية هذه الإجابة بعض الحالات الشائعة التي قد تُغري فيها لإنشاء متغيرات متسلسلة ، وتوضح لك كيفية الانتقال مباشرة إلى القوائم. إذا كنت جديدًا على القوائم في R ، فقد ترغب أيضًا في قراءة ما الفرق بين [[ و [ في الوصول إلى عناصر القائمة؟ .


قوائم من البداية

لا تقم أبدًا بإنشاء d1d2d3، ...، dn في المقام الأول. إنشاء قائمة d مع عناصر n.

قراءة ملفات متعددة في قائمة إطارات البيانات

يتم ذلك بسهولة عند القراءة في الملفات. ربما لديك ملفات data1.csv, data2.csv, ... في دليل. هدفك هو قائمة من البيانات. إطارات تسمى mydata. أول ما تحتاجه هو ناقل مع جميع أسماء الملفات. يمكنك إنشاء هذا باستخدام اللصق (على سبيل المثال ، my_files = paste0("data", 1:5, ".csv")) ، ولكن من المحتمل أن يكون من الأسهل استخدام list.files للحصول على جميع الملفات المناسبة: my_files <- list.files(pattern = "\\.csv$"). يمكنك استخدام التعبيرات العادية لمطابقة الملفات ، وقراءة المزيد حول التعبيرات العادية في أسئلة أخرى إذا كنت بحاجة إلى مساعدة هناك. وبهذه الطريقة ، يمكنك الحصول على جميع ملفات CSV حتى إذا كانت لا تتبع نظام تسمية لطيف. أو يمكنك استخدام نمط fexier regex إذا كنت بحاجة إلى اختيار بعض ملفات CSV من مجموعة منها.

في هذه المرحلة ، سيستخدم معظم مبتدئين R حلقة for ، ولا يوجد شيء خاطئ في ذلك ، فهو يعمل بشكل جيد.

my_data <- list()
for (i in seq_along(my_files)) {
    my_data[[i]] <- read.csv(file = my_files[i])
}

هناك طريقة أكثر شبهاً بـ R للقيام بذلك هي lapply ، وهو اختصار لما ذكر أعلاه

my_data <- lapply(my_files, read.csv)

بالطبع ، استبدل وظيفة استيراد البيانات الأخرى لـ read.csv بالشكل المناسب. سيكون readr::read_csv أو data.table::fread أسرع ، أو قد تحتاج أيضًا إلى وظيفة مختلفة لنوع ملف مختلف.

في كلتا الحالتين ، من السهل تسمية عناصر القائمة لتتناسب مع الملفات

names(my_data) <- gsub("\\.csv$", "", my_files)
# or, if you prefer the consistent syntax of stringr
names(my_data) <- stringr::str_replace(my_files, pattern = ".csv", replacement = "")

تقسيم إطار البيانات إلى قائمة إطارات البيانات

هذا سهل للغاية ، الوظيفة الأساسية split() تفعل ذلك لك. يمكنك تقسيم عمود (أو أعمدة) من البيانات ، أو أي شيء آخر تريده

mt_list = split(mtcars, f = mtcars$cyl)
# This gives a list of three data frames, one for each value of cyl

هذه أيضًا طريقة رائعة لتقسيم إطار البيانات إلى أجزاء للتحقق من الصحة. ربما تريد تقسيم mtcars إلى تدريب واختبار والتحقق من الصحة.

groups = sample(c("train", "test", "validate"),
                size = nrow(mtcars), replace = TRUE)
mt_split = split(mtcars, f = groups)
# and mt_split has appropriate names already!

محاكاة قائمة إطارات البيانات

ربما كنت تحاكي البيانات ، شيء مثل هذا:

my_sim_data = data.frame(x = rnorm(50), y = rnorm(50))

ولكن من يقوم بمحاكاة واحدة فقط؟ تريد أن تفعل هذا 100 مرة ، 1000 مرة ، أكثر! لكنك {لا تريد 10،000 إطار بيانات في مساحة العمل الخاصة بك. استخدم replicate ووضعها في قائمة:

sim_list = replicate(n = 10,
                     expr = {data.frame(x = rnorm(50), y = rnorm(50))},
                     simplify = F)

في هذه الحالة على وجه الخصوص ، يجب أن تفكر أيضًا فيما إذا كنت تحتاج حقًا إلى إطارات بيانات منفصلة ، أم أن إطار بيانات واحد مع عمود "مجموعة" سيعمل أيضًا؟ باستخدام data.table أو dplyr ، من السهل جدًا القيام بالأشياء "حسب المجموعة" في إطار البيانات.

لم أضع بياناتي في قائمة :( سأفعل في المرة القادمة ، لكن ماذا أفعل الآن؟

إذا كانت مجموعة متنوعة غريبة (وهو أمر غير عادي) ، يمكنك ببساطة تعيينها:

mylist <- list()
mylist[[1]] <- mtcars
mylist[[2]] <- data.frame(a = rnorm(50), b = runif(50))
...

إذا كان لديك إطارات بيانات مسماة بنمط ، على سبيل المثال ، df1 ، df2 ، df3 ، وتريدها في قائمة ، يمكنك get إذا كان يمكنك كتابة تعبير منتظم لمطابقة الأسماء. شيء مثل

df_list = mget(ls(pattern = "df[0-9]"))
# this would match any object with "df" followed by a digit in its name
# you can test what objects will be got by just running the
ls(pattern = "df[0-9]")
# part and adjusting the pattern until it gets the right objects.

بشكل عام ، يتم استخدام mget للحصول على كائنات متعددة وإعادتها في قائمة مسماة. يستخدم نظيره get للحصول على كائن واحد وإعادته (وليس في قائمة).

دمج قائمة إطارات البيانات في إطار بيانات واحد

تتمثل المهمة الشائعة في دمج قائمة إطارات البيانات في إطار بيانات كبير واحد. إذا كنت ترغب في تكديسها فوق بعضها البعض ، فستستخدم rbind لزوجين منهم ، لكن للحصول على قائمة بإطارات البيانات ، توجد ثلاثة خيارات جيدة:

# base option - slower but not extra dependencies
big_data = do.call(what = rbind, args = df_list)

# data table and dplyr have Nice functions for this
# they will be faster and can also add id columns to identify
# which list item they came from. They can also fill in
# missing values if some data frames have more columns than others
big_data = data.table::rbindlist(df_list)
big_data = dplyr::bind_rows(df_list)

(بالمثل ، استخدم cbind أو dplyr::bind_cols للأعمدة.)

لدمج (انضمام) قائمة بإطارات البيانات ، يمكنك رؤية هذه الإجابات . غالبًا ما تكون الفكرة هي استخدام Reduce مع merge (أو وظيفة الانضمام الأخرى) لجمعها معًا.

لماذا وضع البيانات في قائمة؟

ضع البيانات المتشابهة في القوائم لأنك ترغب في القيام بأشياء مشابهة لكل إطار بيانات ، والدالات مثل lapply و sapplydo.call و الحزمة purrr ، ووظائف plyrl*ply القديمة تجعل من السهل القيام بذلك. أمثلة على الأشخاص الذين يقومون بأشياء بسهولة باستخدام القوائم موجودة في جميع أنحاء SO.

حتى إذا كنت تستخدم حلقة منخفضة للحلقة ، فمن الأسهل بكثير تنفيذ حلقة فوق عناصر القائمة أكثر من إنشاء أسماء متغيرة باستخدام paste والوصول إلى الكائنات باستخدام get. أسهل في التصحيح ، أيضًا.

فكر في قابلية التوسع . إذا كنت بحاجة إلى ثلاثة متغيرات فقط ، فمن الجيد استخدام d1 و d2 و d3. ولكن إذا تبين أنك تحتاج حقًا إلى 6 ، فهذا كثيرًا في الكتابة. وفي المرة القادمة ، عندما تحتاج إلى 10 أو 20 ، تجد نفسك تقوم بنسخ ولصق سطور من التعليمات البرمجية ، وربما تستخدم find/replace لتغيير d14 إلى d15 ، وتفكر في هذه ليست الطريقة التي ينبغي أن تكون بها البرمجة. إذا كنت تستخدم قائمة ، فإن الفرق بين 3 حالات و 30 حالة و 300 حالة على الأكثر سطر واحد من التعليمات البرمجية --- لا تغيير على الإطلاق إذا تم اكتشاف عدد الحالات تلقائيًا بواسطة ، على سبيل المثال ، كم عدد ملفات .csv الموجودة في دليلك.

يمكنك تسمية عناصر القائمة ، إذا كنت ترغب في استخدام شيء آخر غير المؤشرات الرقمية للوصول إلى إطارات البيانات الخاصة بك (ويمكنك استخدام الاثنين ، فهذا ليس اختيار XOR).

بشكل عام ، يؤدي استخدام القوائم إلى كتابة تعليمات برمجية أنظف وأسهل في القراءة ، مما يؤدي إلى تقليل الأخطاء وتقليل التشويش.

297
Gregor

يمكنك أيضًا الوصول إلى أعمدة وقيم محددة في كل عنصر من عناصر القائمة باستخدام [ و [[. هنا بضعة أمثلة. أولاً ، لا يمكننا الوصول إلا إلى العمود الأول من كل إطار بيانات في القائمة باستخدام lapply(ldf, "[", 1) ، حيث يشير 1 إلى رقم العمود.

ldf <- list(d1 = d1, d2 = d2)  ## create a named list of your data frames
lapply(ldf, "[", 1)
# $d1
#   y1
# 1  1
# 2  2
# 3  3
#
# $d2
#   y1
# 1  3
# 2  2
# 3  1

وبالمثل ، يمكننا الوصول إلى القيمة الأولى في العمود الثاني باستخدام

lapply(ldf, "[", 1, 2)
# $d1
# [1] 4
# 
# $d2
# [1] 6

ثم يمكننا أيضًا الوصول إلى قيم الأعمدة مباشرةً ، كمتجه ، باستخدام [[

lapply(ldf, "[[", 1)
# $d1
# [1] 1 2 3
#
# $d2
# [1] 3 2 1
17
Rich Scriven

إذا كان لديك عدد كبير من إطارات البيانات المسماة بالتسلسل ، يمكنك إنشاء قائمة بالمجموعة الفرعية المطلوبة من إطارات البيانات مثل هذا:

d1 <- data.frame(y1=c(1,2,3), y2=c(4,5,6))
d2 <- data.frame(y1=c(3,2,1), y2=c(6,5,4))
d3 <- data.frame(y1=c(6,5,4), y2=c(3,2,1))
d4 <- data.frame(y1=c(9,9,9), y2=c(8,8,8))

my.list <- list(d1, d2, d3, d4)
my.list

my.list2 <- lapply(paste('d', seq(2,4,1), sep=''), get)
my.list2

حيث my.list2 تُرجع قائمة تحتوي على إطارات البيانات الثانية والثالثة والرابعة.

[[1]]
  y1 y2
1  3  6
2  2  5
3  1  4

[[2]]
  y1 y2
1  6  3
2  5  2
3  4  1

[[3]]
  y1 y2
1  9  8
2  9  8
3  9  8

لاحظ ، مع ذلك ، أن إطارات البيانات في القائمة أعلاه لم تعد مسماة. إذا كنت ترغب في إنشاء قائمة تحتوي على مجموعة فرعية من إطارات البيانات وتريد الاحتفاظ بأسمائها ، يمكنك تجربة ذلك:

list.function <-  function() { 

     d1 <- data.frame(y1=c(1,2,3), y2=c(4,5,6))
     d2 <- data.frame(y1=c(3,2,1), y2=c(6,5,4))
     d3 <- data.frame(y1=c(6,5,4), y2=c(3,2,1))
     d4 <- data.frame(y1=c(9,9,9), y2=c(8,8,8))

     sapply(paste('d', seq(2,4,1), sep=''), get, environment(), simplify = FALSE) 
} 

my.list3 <- list.function()
my.list3

الذي يعود:

> my.list3
$d2
  y1 y2
1  3  6
2  2  5
3  1  4

$d3
  y1 y2
1  6  3
2  5  2
3  4  1

$d4
  y1 y2
1  9  8
2  9  8
3  9  8

> str(my.list3)
List of 3
 $ d2:'data.frame':     3 obs. of  2 variables:
  ..$ y1: num [1:3] 3 2 1
  ..$ y2: num [1:3] 6 5 4
 $ d3:'data.frame':     3 obs. of  2 variables:
  ..$ y1: num [1:3] 6 5 4
  ..$ y2: num [1:3] 3 2 1
 $ d4:'data.frame':     3 obs. of  2 variables:
  ..$ y1: num [1:3] 9 9 9
  ..$ y2: num [1:3] 8 8 8

> my.list3[[1]]
  y1 y2
1  3  6
2  2  5
3  1  4

> my.list3$d4
  y1 y2
1  9  8
2  9  8
3  9  8
13
Mark Miller

مع الأخذ في الاعتبار أن لديك عددًا "كبيرًا" من البيانات. إطارات بأسماء متشابهة (هنا d # حيث # هو عدد صحيح موجب) ، فيما يلي تحسين طفيف لطريقة @ mark-miller. هو أكثر مقتضب وإرجاع اسمه قائمة data.frames ، حيث يكون كل اسم في القائمة هو اسم data.frame الأصلي المقابل.

المفتاح يستخدم mget مع ls. إذا كانت إطارات البيانات d1 و d2 المقدمة في السؤال هي الكائنات الوحيدة التي لها أسماء d # في البيئة ، إذن

my.list <- mget(ls(pattern="^d[0-9]+"))

التي ستعود

my.list
$d1
  y1 y2
1  1  4
2  2  5
3  3  6

$d2
  y1 y2
1  3  6
2  2  5
3  1  4

تستفيد هذه الطريقة من وسيطة النقش في ls ، والتي تتيح لنا استخدام تعبيرات منتظمة لإجراء تحليل أفضل لأسماء الكائنات في البيئة. بديل "^d[0-9]+$" هو regex "^d\\d+$".

كماgregor يشير ، من الأفضل بشكل عام إعداد عملية إنشاء البيانات الخاصة بك بحيث يتم وضع إطارات البيانات في قوائم مسماة في البداية.

البيانات

d1 <- data.frame(y1 = c(1,2,3),y2 = c(4,5,6))
d2 <- data.frame(y1 = c(3,2,1),y2 = c(6,5,4))
9
lmo

قد يكون هذا متأخرا بعض الشيء ولكن بالعودة إلى مثالك ، اعتقدت أني سأقدم الإجابة مجرد صبي.

 D1 <- data.frame(Y1=c(1,2,3), Y2=c(4,5,6))
 D2 <- data.frame(Y1=c(3,2,1), Y2=c(6,5,4))
 D3 <- data.frame(Y1=c(6,5,4), Y2=c(3,2,1))
 D4 <- data.frame(Y1=c(9,9,9), Y2=c(8,8,8))

ثم قمت بإعداد قائمتك بسهولة:

mylist <- list(D1,D2,D3,D4)

الآن لديك قائمة ولكن بدلاً من الوصول إلى القائمة بالطريقة القديمة مثل

mylist[[1]] # to access 'd1'

يمكنك استخدام هذه الوظيفة للحصول على & dataframe من اختيارك.

GETDF_FROMLIST <- function(DF_LIST, ITEM_LOC){
   DF_SELECTED <- DF_LIST[[ITEM_LOC]]
   return(DF_SELECTED)
}

الآن الحصول على واحد تريد.

D1 <- GETDF_FROMLIST(mylist, 1)
D2 <- GETDF_FROMLIST(mylist, 2)
D3 <- GETDF_FROMLIST(mylist, 3)
D4 <- GETDF_FROMLIST(mylist, 4)

نأمل أن يساعد قليلا اضافية.

في صحتك!

3
ML_for_now

بسيط جدا ! إليكم اقتراحي:

إذا كنت ترغب في تحديد dataframes في مساحة العمل الخاصة بك ، فجرب هذا:

Filter(function(x) is.data.frame(get(x)) , ls())

أو

ls()[sapply(ls(), function(x) is.data.frame(get(x)))]

كل هذه سوف تعطي نفس النتيجة.

يمكنك تغيير is.data.frame للتحقق من الأنواع الأخرى من المتغيرات مثل is.function

1
CHAMI Soufiane