एक वेक्टर को R में विखंडू में विभाजित करें


227

मुझे आर में समान आकार के एन चंक्स में एक वेक्टर को विभाजित करना है। मुझे ऐसा करने के लिए कोई आधार फ़ंक्शन नहीं मिला। इसके अलावा Google मुझे कहीं नहीं मिला। तो यहाँ है कि मैं क्या लेकर आया हूँ, उम्मीद है कि यह किसी को कुछ मदद करता है।

x <- 1:10
n <- 3
chunk <- function(x,n) split(x, factor(sort(rank(x)%%n)))
chunk(x,n)
$`0`
[1] 1 2 3

$`1`
[1] 4 5 6 7

$`2`
[1]  8  9 10

किसी भी टिप्पणी, सुझाव या सुधार वास्तव में स्वागत और सराहना है।

चीयर्स, सेबस्टियन


5
हां, यह बहुत अस्पष्ट है कि आपको जो मिलता है वह "समान आकार के एन चंक्स" का समाधान है। लेकिन शायद यह आपको वहाँ भी मिलता है: x <- 1:10; एन <- 3; विभाजन (x, कट (x, n, लेबल = FALSE))
mdsumner

प्रश्न में दोनों समाधान, और पूर्ववर्ती टिप्पणी में समाधान गलत हैं, इसमें वे काम नहीं कर सकते हैं, अगर वेक्टर ने प्रविष्टियों को दोहराया है। यह कोशिश करें:> फू <- सी (प्रतिनिधि (1, 12), प्रतिनिधि (2,3), प्रतिनिधि (3,3)) [1] 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 3 3 3> chunk (foo, 2) (गलत परिणाम देता है)> chunk (foo, 3) (भी गलत)
mathheadinclouds

(जारी पूर्ववर्ती टिप्पणी) क्यों? रैंक (x) को पूर्णांक> रैंक (c (1,1,2,3)) [1] 1.5 1.5 3.0 4.0 होने की आवश्यकता नहीं है, इसलिए प्रश्न में विधि विफल हो जाती है। यह एक काम करता है (नीचे हैरलन के लिए धन्यवाद)> chunk2 <- function (x, n) विभाजन (x, कट (seq_along (x), n, लेबल = FALSE))
mathheadinclouds

2
> विभाजन (फू, कट (फू, 3, लेबल = FALSE)) (भी गलत)
mathheadinclouds

1
जैसा कि @mathheadinclouds सुझाव देते हैं, उदाहरण डेटा एक बहुत ही विशेष मामला है। ऐसे उदाहरण जो अधिक सामान्य हैं वे अधिक उपयोगी और बेहतर परीक्षण होंगे। उदाहरण x <- c(NA, 4, 3, NA, NA, 2, 1, 1, NA ); y <- letters[x]; z <- factor(y)गायब डेटा के साथ उदाहरण देता है, दोहराया मान, जो पहले से ही सॉर्ट नहीं किए गए हैं, और विभिन्न वर्गों (पूर्णांक, चरित्र, कारक) में हैं।
कलिन

जवाबों:


313

एक-लाइनर बंटवारे घ में आकार 20:

split(d, ceiling(seq_along(d)/20))

अधिक जानकारी: मुझे लगता है कि आप सभी की जरूरत है seq_along(), split()और ceiling():

> d <- rpois(73,5)
> d
 [1]  3  1 11  4  1  2  3  2  4 10 10  2  7  4  6  6  2  1  1  2  3  8  3 10  7  4
[27]  3  4  4  1  1  7  2  4  6  0  5  7  4  6  8  4  7 12  4  6  8  4  2  7  6  5
[53]  4  5  4  5  5  8  7  7  7  6  2  4  3  3  8 11  6  6  1  8  4
> max <- 20
> x <- seq_along(d)
> d1 <- split(d, ceiling(x/max))
> d1
$`1`
 [1]  3  1 11  4  1  2  3  2  4 10 10  2  7  4  6  6  2  1  1  2

$`2`
 [1]  3  8  3 10  7  4  3  4  4  1  1  7  2  4  6  0  5  7  4  6

$`3`
 [1]  8  4  7 12  4  6  8  4  2  7  6  5  4  5  4  5  5  8  7  7

$`4`
 [1]  7  6  2  4  3  3  8 11  6  6  1  8  4

34
प्रश्न nसमान आकार के चूजों के लिए पूछता है । यह आपको आकार की एक अज्ञात संख्या मिलती है n। मुझे भी यही समस्या थी और @mathheadinclouds के समाधान का उपयोग किया।
आरआरएस

4
जैसा कि कोई d1 के आउटपुट से देख सकता है, यह उत्तर d को समान आकार के समूहों में विभाजित नहीं करता है (4 स्पष्ट रूप से छोटा है)। इस प्रकार यह प्रश्न का उत्तर नहीं देता है।
कैलिमो

9
@ आरएस: विभाजन (डी, छत (seq_along (d) / (लंबाई (d) / n)))
gkcn

मुझे पता है कि यह काफी पुराना है लेकिन यह उन लोगों के लिए मददगार हो सकता है जो यहां ठोकर खाते हैं। हालांकि ओपी का प्रश्न समान आकार के विखंडू में विभाजित करना था, अगर वेक्टर भाजक के एक से अधिक नहीं होता है, तो अंतिम चिन चंक की तुलना में एक अलग आकार होगा। n-chunksमैं इस्तेमाल में विभाजित करने के लिए max <- length(d)%/%n। मैंने 31 तार के वेक्टर के साथ इसका उपयोग किया और 10 वाक्यों में से 3 और 1 वाक्य में से 3 वैक्टर की सूची प्राप्त की।
सालू 12


36
simplified version...
n = 3
split(x, sort(x%%n))

मुझे यह पसंद है क्योंकि यह आपको उन चंक्स देता है जो समान रूप से संभव हैं (बड़े कार्य को विभाजित करने के लिए अच्छा है। जैसे कि सीमित रैम को समायोजित करने के लिए या कई थ्रेड्स में कार्य चलाने के लिए)।
एलेक्स्विकेयरिंग

3
यह उपयोगी है, लेकिन ध्यान रखें कि यह केवल संख्यात्मक वैक्टर पर काम करेगा।
कीथ ह्यूजिट

@KeithHughitt को कारकों के साथ हल किया जा सकता है और संख्यात्मक के रूप में स्तरों को वापस किया जा सकता है। या कम से कम यह है कि मैंने इसे कैसे लागू किया।
ड्रमरियोड

20

Ggplot2 फ़ंक्शन आज़माएं cut_number:

library(ggplot2)
x <- 1:10
n <- 3
cut_number(x, n) # labels = FALSE if you just want an integer result
#>  [1] [1,4]  [1,4]  [1,4]  [1,4]  (4,7]  (4,7]  (4,7]  (7,10] (7,10] (7,10]
#> Levels: [1,4] (4,7] (7,10]

# if you want it split into a list:
split(x, cut_number(x, n))
#> $`[1,4]`
#> [1] 1 2 3 4
#> 
#> $`(4,7]`
#> [1] 5 6 7
#> 
#> $`(7,10]`
#> [1]  8  9 10

2
इस बंटवारे के लिए काम नहीं करता है ऊपर x, y, या zमें परिभाषित किया गया इस टिप्पणी । विशेष रूप से, यह परिणामों को क्रमबद्ध करता है, जो आवेदन के आधार पर ठीक हो सकता है या नहीं भी हो सकता है।
कलिन


18

यह आपके पास जो कुछ भी है उसे अलग तरह से विभाजित करेगा, लेकिन फिर भी मुझे लगता है कि यह एक अच्छी सूची संरचना है:

chunk.2 <- function(x, n, force.number.of.groups = TRUE, len = length(x), groups = trunc(len/n), overflow = len%%n) { 
  if(force.number.of.groups) {
    f1 <- as.character(sort(rep(1:n, groups)))
    f <- as.character(c(f1, rep(n, overflow)))
  } else {
    f1 <- as.character(sort(rep(1:groups, n)))
    f <- as.character(c(f1, rep("overflow", overflow)))
  }

  g <- split(x, f)

  if(force.number.of.groups) {
    g.names <- names(g)
    g.names.ordered <- as.character(sort(as.numeric(g.names)))
  } else {
    g.names <- names(g[-length(g)])
    g.names.ordered <- as.character(sort(as.numeric(g.names)))
    g.names.ordered <- c(g.names.ordered, "overflow")
  }

  return(g[g.names.ordered])
}

जो आपको निम्नलिखित देगा, यह इस बात पर निर्भर करता है कि आप इसे कैसे स्वरूपित करना चाहते हैं:

> x <- 1:10; n <- 3
> chunk.2(x, n, force.number.of.groups = FALSE)
$`1`
[1] 1 2 3

$`2`
[1] 4 5 6

$`3`
[1] 7 8 9

$overflow
[1] 10

> chunk.2(x, n, force.number.of.groups = TRUE)
$`1`
[1] 1 2 3

$`2`
[1] 4 5 6

$`3`
[1]  7  8  9 10

इन सेटिंग्स का उपयोग करके कुछ समय चल रहा है:

set.seed(42)
x <- rnorm(1:1e7)
n <- 3

फिर हमारे पास निम्नलिखित परिणाम हैं:

> system.time(chunk(x, n)) # your function 
   user  system elapsed 
 29.500   0.620  30.125 

> system.time(chunk.2(x, n, force.number.of.groups = TRUE))
   user  system elapsed 
  5.360   0.300   5.663 

EDIT: मेरे फ़ंक्शन में as.factor () से as.character () तक बदलते हुए इसे दो बार तेजी से बनाया गया।


13

ढेर के कुछ और रूप ...

> x <- 1:10
> n <- 3

ध्यान दें, factorयहां आपको फ़ंक्शन का उपयोग करने की आवश्यकता नहीं है, लेकिन आप अभी भी sortअपना पहला वेक्टर ओ / डब्ल्यू करना चाहते हैं 1 2 3 10:

> chunk <- function(x, n) split(x, sort(rank(x) %% n))
> chunk(x,n)
$`0`
[1] 1 2 3
$`1`
[1] 4 5 6 7
$`2`
[1]  8  9 10

या आप वर्ण सूचकांकों को असाइन कर सकते हैं, ऊपर दिए गए बाएं टिक में संख्याओं को उल्टा कर सकते हैं:

> my.chunk <- function(x, n) split(x, sort(rep(letters[1:n], each=n, len=length(x))))
> my.chunk(x, n)
$a
[1] 1 2 3 4
$b
[1] 5 6 7
$c
[1]  8  9 10

या आप वेक्टर में संग्रहीत सादे नाम का उपयोग कर सकते हैं। ध्यान दें कि लेबल sortको xवर्णमाला में लगातार मान प्राप्त करने के लिए उपयोग करना :

> my.other.chunk <- function(x, n) split(x, sort(rep(c("tom", "dick", "harry"), each=n, len=length(x))))
> my.other.chunk(x, n)
$dick
[1] 1 2 3
$harry
[1] 4 5 6
$tom
[1]  7  8  9 10

12

आधार आर का उपयोग करना rep_len:

x <- 1:10
n <- 3

split(x, rep_len(1:n, length(x)))
# $`1`
# [1]  1  4  7 10
# 
# $`2`
# [1] 2 5 8
# 
# $`3`
# [1] 3 6 9

और जैसा कि पहले ही उल्लेख किया गया है कि यदि आप क्रमबद्ध सूचकांक चाहते हैं, तो:

split(x, sort(rep_len(1:n, length(x))))
# $`1`
# [1] 1 2 3 4
# 
# $`2`
# [1] 5 6 7
# 
# $`3`
# [1]  8  9 10

9

आप विभाजित / कटौती को जोड़ सकते हैं, जैसा कि mdsummer द्वारा सुझाया गया है, क्वांटाइल के साथ भी समूह बनाने के लिए:

split(x,cut(x,quantile(x,(0:n)/n), include.lowest=TRUE, labels=FALSE))

यह आपके उदाहरण के लिए समान परिणाम देता है, लेकिन तिरछे चर के लिए नहीं।


7

split(x,matrix(1:n,n,length(x))[1:length(x)])

शायद यह अधिक स्पष्ट है, लेकिन एक ही विचार:
split(x,rep(1:n, ceiling(length(x)/n),length.out = length(x)))

यदि आप इसे ऑर्डर करना चाहते हैं, तो इसके चारों ओर एक प्रकार फेंक दें


6

मुझे उसी फ़ंक्शन की आवश्यकता थी और पिछले समाधानों को पढ़ा है, हालांकि मुझे भी अंत में होने के लिए असंतुलित चंक होने की आवश्यकता है अर्थात यदि मेरे पास 10 तत्व हैं उन्हें प्रत्येक 3 के वैक्टर में विभाजित करने के लिए, तो मेरे परिणाम में 3 के साथ वैक्टर होना चाहिए, क्रमशः 3,4 तत्व। इसलिए मैंने निम्नलिखित का उपयोग किया (मैंने पठनीयता के लिए कोड को नहीं छोड़ा, अन्यथा कई चर रखने की आवश्यकता नहीं है):

chunk <- function(x,n){
  numOfVectors <- floor(length(x)/n)
  elementsPerVector <- c(rep(n,numOfVectors-1),n+length(x) %% n)
  elemDistPerVector <- rep(1:numOfVectors,elementsPerVector)
  split(x,factor(elemDistPerVector))
}
set.seed(1)
x <- rnorm(10)
n <- 3
chunk(x,n)
$`1`
[1] -0.6264538  0.1836433 -0.8356286

$`2`
[1]  1.5952808  0.3295078 -0.8204684

$`3`
[1]  0.4874291  0.7383247  0.5757814 -0.3053884

6

यहाँ एक और संस्करण है।

नोट: इस नमूने के साथ आप दूसरे पैरामीटर में चुन आकार निर्दिष्ट कर रहे हैं

  1. सभी विखंडू एक समान हैं, अंतिम को छोड़कर;
  2. अंतिम सबसे छोटा होगा, जो कभी भी चंक के आकार से बड़ा नहीं होगा।

chunk <- function(x,n)
{
    f <- sort(rep(1:(trunc(length(x)/n)+1),n))[1:length(x)]
    return(split(x,f))
}

#Test
n<-c(1,2,3,4,5,6,7,8,9,10,11)

c<-chunk(n,5)

q<-lapply(c, function(r) cat(r,sep=",",collapse="|") )
#output
1,2,3,4,5,|6,7,8,9,10,|11,|

4

केवल अनुक्रमित का उपयोग करके एक वेक्टर को विभाजित करने का सरल कार्य - इसे जटिल करने की आवश्यकता नहीं है

vsplit <- function(v, n) {
    l = length(v)
    r = l/n
    return(lapply(1:n, function(i) {
        s = max(1, round(r*(i-1))+1)
        e = min(l, round(r*i))
        return(v[s:e])
    }))
}

3

अगर आपको पसंद नहीं है split() और आप इसे matrix()(झूलते हुए NAs के साथ) पसंद नहीं करते हैं , तो यह है:

chunk <- function(x, n) (mapply(function(a, b) (x[a:b]), seq.int(from=1, to=length(x), by=n), pmin(seq.int(from=1, to=length(x), by=n)+(n-1), length(x)), SIMPLIFY=FALSE))

जैसे split(), यह एक सूची देता है, लेकिन यह लेबल के साथ समय या स्थान बर्बाद नहीं करता है, इसलिए यह अधिक प्रदर्शनकारी हो सकता है।



2

यदि आपको पसंद नहीं है split()और आप बुरा नहीं मानते हैं, तो अपनी छोटी पूंछ बाहर रखें:

chunk <- function(x, n) { if((length(x)%%n)==0) {return(matrix(x, nrow=n))} else {return(matrix(append(x, rep(NA, n-(length(x)%%n))), nrow=n))} }

लौटाए गए मैट्रिक्स के कॉलम ([, 1: ncol]) आपके द्वारा खोजे जा रहे droids हैं।


2

मुझे एक फ़ंक्शन की आवश्यकता होती है जो डेटाटेबल (उद्धरण में) का तर्क लेता है और एक अन्य तर्क जो उस मूल डेटाटेबल के सबसेट में पंक्तियों की संख्या पर ऊपरी सीमा है। यह फ़ंक्शन उन सभी डेटा का उत्पादन करता है जो ऊपरी सीमा की अनुमति देता है।

library(data.table)    
split_dt <- function(x,y) 
    {
    for(i in seq(from=1,to=nrow(get(x)),by=y)) 
        {df_ <<- get(x)[i:(i + y)];
            assign(paste0("df_",i),df_,inherits=TRUE)}
    rm(df_,inherits=TRUE)
    }

यह फ़ंक्शन मुझे मूल data.table से नाम में प्रारंभिक पंक्ति के साथ df_ [संख्या] नामक data.tables की एक श्रृंखला देता है। अंतिम data.table छोटा हो सकता है और NA से भरा हो सकता है इसलिए आपको यह सब्मिट करना होगा कि जो भी डेटा बचा है वह वापस आ जाए। इस प्रकार का फ़ंक्शन उपयोगी है क्योंकि कुछ जीआईएस सॉफ़्टवेयर में सीमा होती है कि आप कितने पता पिन आयात कर सकते हैं, उदाहरण के लिए। इसलिए डेटाटाइबल्स को छोटे चंक्स में स्लाइस करने की सिफारिश नहीं की जा सकती है, लेकिन यह संभव नहीं है।


2

क्षमा करें यदि यह उत्तर इतनी देर से आता है, लेकिन हो सकता है कि यह किसी और के लिए उपयोगी हो। वास्तव में इस समस्या का एक बहुत ही उपयोगी समाधान है, विभाजन के अंत में समझाया गया।

> testVector <- c(1:10) #I want to divide it into 5 parts
> VectorList <- split(testVector, 1:5)
> VectorList
$`1`
[1] 1 6

$`2`
[1] 2 7

$`3`
[1] 3 8

$`4`
[1] 4 9

$`5`
[1]  5 10

3
यदि प्रत्येक समूह में असमान संख्याएँ हैं तो यह टूट जाएगा!
मतिफॉ सिप

2

फिर भी splitIndicesपैकेज से एक और संभावना है parallel:

library(parallel)
splitIndices(20, 3)

देता है:

[[1]]
[1] 1 2 3 4 5 6 7

[[2]]
[1]  8  9 10 11 12 13

[[3]]
[1] 14 15 16 17 18 19 20

0

वाह, इस प्रश्न को उम्मीद से अधिक कर्षण मिला।

सभी विचारों के लिए धन्यवाद। मैं इस समाधान के साथ आया हूँ:

require(magrittr)
create.chunks <- function(x, elements.per.chunk){
    # plain R version
    # split(x, rep(seq_along(x), each = elements.per.chunk)[seq_along(x)])
    # magrittr version - because that's what people use now
    x %>% seq_along %>% rep(., each = elements.per.chunk) %>% extract(seq_along(x)) %>% split(x, .) 
}
create.chunks(letters[1:10], 3)
$`1`
[1] "a" "b" "c"

$`2`
[1] "d" "e" "f"

$`3`
[1] "g" "h" "i"

$`4`
[1] "j"

कुंजी seq (प्रत्येक = chunk.size) पैरामीटर का उपयोग करना है ताकि यह काम कर सके। मेरे पिछले समाधान में रैंक (x) की तरह seq_along कार्य करता है, लेकिन वास्तव में डुप्लिकेट प्रविष्टियों के साथ सही परिणाम देने में सक्षम है।


संबंधित लोगों के लिए कि rep (seq_along (x), प्रत्येक = elements.per.chunk) मेमोरी पर बहुत तनावपूर्ण हो सकता है: हाँ यह करता है। आप मेरे पिछले सुझाव का एक संशोधित संस्करण आज़मा सकते हैं: chunk <- function (x, n) विभाजन (x, फ़ैक्टर (seq_along (x) %% n))
सेबस्टियन

0

यह आकार spln / k 1 + 1 या ⌋n / k into के टुकड़ों में विभाजित होता है और O (n log n) सॉर्ट का उपयोग नहीं करता है।

get_chunk_id<-function(n, k){
    r <- n %% k
    s <- n %/% k
    i<-seq_len(n)
    1 + ifelse (i <= r * (s+1), (i-1) %/% (s+1), r + ((i - r * (s+1)-1) %/% s))
}

split(1:10, get_chunk_id(10,3))
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.