একাধিক কলামে ডেটা ফ্রেম স্ট্রিং কলাম বিভক্ত করুন


245

আমি ফর্মের তথ্য নিতে চাই

before = data.frame(attr = c(1,30,4,6), type=c('foo_and_bar','foo_and_bar_2'))
  attr          type
1    1   foo_and_bar
2   30 foo_and_bar_2
3    4   foo_and_bar
4    6 foo_and_bar_2

এবং split()এই জাতীয় typeকিছু পেতে উপরের কলামে " " ব্যবহার করুন :

  attr type_1 type_2
1    1    foo    bar
2   30    foo  bar_2
3    4    foo    bar
4    6    foo  bar_2

আমি অবিশ্বাস্যরকম জটিল কিছু নিয়ে এসেছি যার সাথে কিছু অংশ জড়িত apply, তবে আমি তখন থেকে এটি ভুল জায়গায় রেখেছি। এটি সেরা উপায় হতে অনেক জটিল বলে মনে হয়েছিল। আমি strsplitনীচে হিসাবে ব্যবহার করতে পারি , কিন্তু তারপরে কীভাবে তথ্য ফ্রেমের 2 কলামে ফিরে যেতে পারব তা অস্পষ্ট।

> strsplit(as.character(before$type),'_and_')
[[1]]
[1] "foo" "bar"

[[2]]
[1] "foo"   "bar_2"

[[3]]
[1] "foo" "bar"

[[4]]
[1] "foo"   "bar_2"

কোন পয়েন্টার জন্য ধন্যবাদ। আমি এখনও আর তালিকাগুলি বেশ খাঁজনি।

উত্তর:


279

ব্যবহার stringr::str_split_fixed

library(stringr)
str_split_fixed(before$type, "_and_", 2)

2
এটি আমার সমস্যাটির জন্যও আজ খুব সুন্দরভাবে কাজ করেছে .. তবে এটি প্রতিটি সারির শুরুতে একটি 'সি' যুক্ত করেছিল। কোন ধারণা কেন যে ??? left_right <- str_split_fixed(as.character(split_df),'\">',2)
শিখুন

আমি এমন একটি প্যাটার্ন দিয়ে বিভক্ত করতে চাই যে "..." আছে, যখন আমি এই ফাংশনটি প্রয়োগ করি, এটি কিছুই দেয় না। কি সমস্যা হতে পারে. আমার
ধরণটি

2
@ ব্যবহারকারী3841581 - আপনার আমার পুরানো ক্যোয়ারী আমি জানি, তবে এটি ডকুমেন্টেশনে আচ্ছাদিত - আর্গুমেন্টের সাথে "একটি নির্দিষ্ট স্ট্রিং ম্যাচ করুন" str_split_fixed("aaa...bbb", fixed("..."), 2)দিয়ে কাজ fixed()করে pattern=.রেজেক্সের অর্থ 'কোনও চরিত্র'।
thelatemail

ধন্যবাদ হ্যাডলি, খুব দৃin়প্রতিজ্ঞ পদ্ধতি, তবে একটি জিনিস উন্নত হতে পারে, মূল কলামে এনএ থাকলে, বিচ্ছেদের পরে এটি ফলাফলের কলামগুলিতে সেভরাল খালি স্ট্রিং হয়ে যাবে, যা অযাচিত, আমি এনএকে পরেও এনএ রাখতে চাই বিভাজন
ক্লাউডসম্পিউটস

ভালো কাজ করে অর্থাৎ বিভাজক নিখোঁজ থাকলে! উদাহরণস্বরূপ, যদি আমার কাছে একটি ভেক্টর থাকে তবে 'একটি <-c ("1N", "2N")' যে আমি কলামগুলিতে পৃথক করতে চাই '1,1, "এন", "এন" "আমি চালিত" str_split_fixed (গুলি, ") ", 2) '। আমি এই বিষয়টিতে আমার নতুন কলামগুলির নাম কীভাবে করব তা ঠিক নিশ্চিত নই, 'কল 1 <-c (1,1)' এবং 'কল 2 <-c ("এন", "এন")'
মায়কা

173

আর একটি বিকল্প নতুন tidyr প্যাকেজ ব্যবহার করা হয়।

library(dplyr)
library(tidyr)

before <- data.frame(
  attr = c(1, 30 ,4 ,6 ), 
  type = c('foo_and_bar', 'foo_and_bar_2')
)

before %>%
  separate(type, c("foo", "bar"), "_and_")

##   attr foo   bar
## 1    1 foo   bar
## 2   30 foo bar_2
## 3    4 foo   bar
## 4    6 foo bar_2

পৃথক সহ বিভাজনের সংখ্যা সীমাবদ্ধ করার কোনও উপায় কি? ধরা যাক আমি একবার '_' এ বিভক্ত করতে চাই (বা এটি দিয়ে str_split_fixedএবং বিদ্যমান ডেটাফ্রেমে কলামগুলি যুক্ত করা)?
জেলেনাউকলিনা

66

5 বছর পরে বাধ্যতামূলক data.tableসমাধান যুক্ত করুন

library(data.table) ## v 1.9.6+ 
setDT(before)[, paste0("type", 1:2) := tstrsplit(type, "_and_")]
before
#    attr          type type1 type2
# 1:    1   foo_and_bar   foo   bar
# 2:   30 foo_and_bar_2   foo bar_2
# 3:    4   foo_and_bar   foo   bar
# 4:    6 foo_and_bar_2   foo bar_2

আমরা উভয় নিশ্চিত করুন যে ফলে কলাম সঠিক ধরনের থাকবে বানাতে পারে এবং যোগ করে পারফরম্যান্সের উন্নতি type.convertএবং fixedআর্গুমেন্ট (যেহেতু "_and_"সত্যিই একটি Regex নয়)

setDT(before)[, paste0("type", 1:2) := tstrsplit(type, "_and_", type.convert = TRUE, fixed = TRUE)]

যদি আপনার '_and_'নিদর্শনগুলির সংখ্যা পৃথক হয়, আপনি সর্বাধিক সংখ্যক মিল (যেমন ভবিষ্যতের কলামগুলি)max(lengths(strsplit(before$type, '_and_')))
স্ক্যাচারের সাথে

এটি আমার প্রিয় উত্তর, খুব ভাল কাজ করে! আপনি কিভাবে দয়া করে তা ব্যাখ্যা করতে পারেন। কেন স্থানান্তর (স্টারস্প্লিট (…)) এবং সংযোগকারী স্ট্রিংগুলির জন্য পেস্ট0 নয় - তাদের বিভাজন নয় ...
গেকো

1
@ গেকো আমি নিশ্চিত নই যে প্রশ্নটি কী। আপনি যদি কেবলমাত্র এটি ব্যবহার করেন তবে strsplitএটি প্রতিটি স্লটে 2 টি মান সহ একটি একক ভেক্টর তৈরি করে, তাই একে একে প্রতিটি মানের সাথে 2 ভেক্টরে tstrsplitস্থানান্তরিত করে। paste0কলামের নামগুলি তৈরি করতে কেবল ব্যবহৃত হয়, এটি মানগুলিতে ব্যবহৃত হয় না। সমীকরণের এলএইচএসে কলামের নামগুলি রয়েছে, আরএইচএসে কলামে স্প্লিট + ট্রান্সপোজ অপারেশন রয়েছে। :=" স্থানে এসাইন্ট " এর অর্থ দাঁড়ায় , সুতরাং আপনি <-সেখানে অ্যাসাইনমেন্ট অপারেটরটি দেখতে পাবেন না ।
ডেভিড আরেনবুর্গ

57

তবুও অন্য পদ্ধতি: ব্যবহার rbindকরুন out:

before <- data.frame(attr = c(1,30,4,6), type=c('foo_and_bar','foo_and_bar_2'))  
out <- strsplit(as.character(before$type),'_and_') 
do.call(rbind, out)

     [,1]  [,2]   
[1,] "foo" "bar"  
[2,] "foo" "bar_2"
[3,] "foo" "bar"  
[4,] "foo" "bar_2"

এবং একত্রিত করতে:

data.frame(before$attr, do.call(rbind, out))

4
নতুন আর সংস্করণগুলির আরেকটি বিকল্প হ'লstrcapture("(.*)_and_(.*)", as.character(before$type), data.frame(type_1 = "", type_2 = ""))
অ্যালেক্সিস_লাজ

36

লক্ষ্য করুন যে "[" এর সাথে স্যাপলি সেই তালিকায় প্রথম বা দ্বিতীয় আইটেমগুলি নিষ্ক্রিয় করতে ব্যবহার করা যেতে পারে:

before$type_1 <- sapply(strsplit(as.character(before$type),'_and_'), "[", 1)
before$type_2 <- sapply(strsplit(as.character(before$type),'_and_'), "[", 2)
before$type <- NULL

এবং এখানে একটি জিএসব পদ্ধতি রয়েছে:

before$type_1 <- gsub("_and_.+$", "", before$type)
before$type_2 <- gsub("^.+_and_", "", before$type)
before$type <- NULL

31

আনিকোর সমাধান হিসাবে একই লাইন বরাবর একটি লাইনার এখানে রয়েছে, তবে হ্যাডলির স্ট্রিংয়ের প্যাকেজটি ব্যবহার করে:

do.call(rbind, str_split(before$type, '_and_'))

1
ভাল ধরা, আমার জন্য সেরা সমাধান। stringrপ্যাকেজের তুলনায় কিছুটা ধীর হলেও ।
মেলকা

20

বিকল্পগুলিতে যুক্ত করতে, আপনি আমার splitstackshape::cSplitফাংশনটিও এর মতো ব্যবহার করতে পারেন :

library(splitstackshape)
cSplit(before, "type", "_and_")
#    attr type_1 type_2
# 1:    1    foo    bar
# 2:   30    foo  bar_2
# 3:    4    foo    bar
# 4:    6    foo  bar_2

3 বছর পরে - এই বিকল্পটি আমার মতো একই সমস্যার জন্য সবচেয়ে ভাল কাজ করছে - তবে আমি যে ডেটাফ্রেমে কাজ করছি তার মধ্যে 54 টি কলাম রয়েছে এবং সেগুলি দুটিতে বিভক্ত করা দরকার। এই পদ্ধতিটি ব্যবহার করে কী করার কোনও উপায় আছে - উপরের কমান্ডটি টাইপ না করে সংক্ষিপ্ত 54 বার? অনেক ধন্যবাদ, নিকি।
নিকি

@ নিকি, আপনি কি কলামের নাম বা কলামের অবস্থানগুলির ভেক্টর সরবরাহ করার চেষ্টা করেছেন? এটি করা উচিত ....
A5C1D2H2I1M1N2O1R2T1

এটি কেবল কলামগুলির নাম পরিবর্তন করছিল না - আমার ডিএফের কলামের সংখ্যা কার্যকরভাবে দ্বিগুণ করার সাথে সাথে আমার উপরে আক্ষরিকভাবে কলামগুলি বিভক্ত করা দরকার। নীচে আমি শেষটিতে যা ব্যবহার করেছি: df2 <- cSplit (df1, splitCols = 1:54, "/")
নিকি

14

একটি সহজ উপায় হ'ল ব্যবহার sapply()এবং [ফাংশন:

before <- data.frame(attr = c(1,30,4,6), type=c('foo_and_bar','foo_and_bar_2'))
out <- strsplit(as.character(before$type),'_and_')

উদাহরণ স্বরূপ:

> data.frame(t(sapply(out, `[`)))
   X1    X2
1 foo   bar
2 foo bar_2
3 foo   bar
4 foo bar_2

sapply()এর ফলাফলটি একটি ম্যাট্রিক্স এবং একটি ডেটা ফ্রেমে ট্রান্সপোজিং এবং কাস্টিং প্রয়োজন। এটি তখন কিছু সাধারণ ম্যানিপুলেশন যা ফলাফলটি চেয়েছিল:

after <- with(before, data.frame(attr = attr))
after <- cbind(after, data.frame(t(sapply(out, `[`))))
names(after)[2:3] <- paste("type", 1:2, sep = "_")

এই মুহুর্তে, afterআপনি কি চেয়েছিলেন

> after
  attr type_1 type_2
1    1    foo    bar
2   30    foo  bar_2
3    4    foo    bar
4    6    foo  bar_2

12

বিষয়টি প্রায় ক্লান্ত হয়ে পড়েছে, আমি চাই আপনি কিছুটা সাধারণ সংস্করণে এমন কোনও সমাধানের প্রস্তাব দিতে চাই যেখানে আপনি আউটপুট কলামগুলির সংখ্যা জানেন না, একটি অগ্রাধিকার। উদাহরণস্বরূপ আপনার আছে

before = data.frame(attr = c(1,30,4,6), type=c('foo_and_bar','foo_and_bar_2', 'foo_and_bar_2_and_bar_3', 'foo_and_bar'))
  attr                    type
1    1             foo_and_bar
2   30           foo_and_bar_2
3    4 foo_and_bar_2_and_bar_3
4    6             foo_and_bar

আমরা ডিপি্লায়ার ব্যবহার করতে separate()পারি না কারণ বিভক্ত হওয়ার আগে আমরা ফলাফল কলামগুলির সংখ্যা জানি না, তাই আমি তখন একটি ফাংশন stringrতৈরি করেছি যা উত্পন্ন কলামগুলির জন্য প্যাটার্ন এবং একটি নাম উপস্থাপনার ভিত্তিতে একটি কলাম বিভক্ত করতে ব্যবহার করে। আমি আশা করি ব্যবহৃত কোডিংয়ের ধরণগুলি সঠিক।

split_into_multiple <- function(column, pattern = ", ", into_prefix){
  cols <- str_split_fixed(column, pattern, n = Inf)
  # Sub out the ""'s returned by filling the matrix to the right, with NAs which are useful
  cols[which(cols == "")] <- NA
  cols <- as.tibble(cols)
  # name the 'cols' tibble as 'into_prefix_1', 'into_prefix_2', ..., 'into_prefix_m' 
  # where m = # columns of 'cols'
  m <- dim(cols)[2]

  names(cols) <- paste(into_prefix, 1:m, sep = "_")
  return(cols)
}

এরপরে আমরা split_into_multipleনিম্নরূপে একটি dplyr পাইপ ব্যবহার করতে পারেন :

after <- before %>% 
  bind_cols(split_into_multiple(.$type, "_and_", "type")) %>% 
  # selecting those that start with 'type_' will remove the original 'type' column
  select(attr, starts_with("type_"))

>after
  attr type_1 type_2 type_3
1    1    foo    bar   <NA>
2   30    foo  bar_2   <NA>
3    4    foo  bar_2  bar_3
4    6    foo    bar   <NA>

এবং তারপরে আমরা gatherপরিপাটি করার জন্য ব্যবহার করতে পারি ...

after %>% 
  gather(key, val, -attr, na.rm = T)

   attr    key   val
1     1 type_1   foo
2    30 type_1   foo
3     4 type_1   foo
4     6 type_1   foo
5     1 type_2   bar
6    30 type_2 bar_2
7     4 type_2 bar_2
8     6 type_2   bar
11    4 type_3 bar_3

চিয়ার্স, আমি মনে করি এটি অত্যন্ত কার্যকর।
তেজেবো

8

এখানে একটি বেস আর ওয়ান লাইন রয়েছে যা পূর্ববর্তী বেশ কয়েকটি সমাধানকে ওভারল্যাপ করে, তবে সঠিক নাম দিয়ে একটি ডেটা ফ্রেম দেয়।

out <- setNames(data.frame(before$attr,
                  do.call(rbind, strsplit(as.character(before$type),
                                          split="_and_"))),
                  c("attr", paste0("type_", 1:2)))
out
  attr type_1 type_2
1    1    foo    bar
2   30    foo  bar_2
3    4    foo    bar
4    6    foo  bar_2

এটি ব্যবহার করে strsplitপরিবর্তনশীল ভেঙ্গে, এবং data.frameসঙ্গে do.call/ rbindএকটি data.frame ডেটা ফিরে করা। অতিরিক্ত বর্ধিত উন্নতি হ'ল setNamesডেটা.ফ্রেমে পরিবর্তনশীল নাম যুক্ত করা।


6

এই প্রশ্নটি বেশ পুরানো তবে আমি যে সমাধানটি পেয়েছি সেটিতে আমি এখন সবচেয়ে সহজ হব।

library(reshape2)
before = data.frame(attr = c(1,30,4,6), type=c('foo_and_bar','foo_and_bar_2'))
newColNames <- c("type1", "type2")
newCols <- colsplit(before$type, "_and_", newColNames)
after <- cbind(before, newCols)
after$type <- NULL
after

ডিএফ ভেক্টর পরিচালনার ক্ষেত্রে এটি এখন পর্যন্ত সবচেয়ে সহজ
এপ্রিকট

5

আর সংস্করণ 3.4.0 যেহেতু আপনি ব্যবহার করতে পারেন strcapture()থেকে utils প্যাকেজ (বেস আর ইনস্টলেশনের সঙ্গে অন্তর্ভুক্ত), অন্যান্য কলাম (গুলি) সম্মুখের দিকে আউটপুট বাঁধাই।

out <- strcapture(
    "(.*)_and_(.*)",
    as.character(before$type),
    data.frame(type_1 = character(), type_2 = character())
)

cbind(before["attr"], out)
#   attr type_1 type_2
# 1    1    foo    bar
# 2   30    foo  bar_2
# 3    4    foo    bar
# 4    6    foo  bar_2

4

আপনি যদি আটকে থাকতে চান তবে অন্য একটি পদ্ধতি strsplit()হ'ল unlist()কমান্ডটি ব্যবহার করা । এই লাইন বরাবর একটি সমাধান এখানে।

tmp <- matrix(unlist(strsplit(as.character(before$type), '_and_')), ncol=2,
   byrow=TRUE)
after <- cbind(before$attr, as.data.frame(tmp))
names(after) <- c("attr", "type_1", "type_2")

4

বেস কিন্তু সম্ভবত ধীর:

n <- 1
for(i in strsplit(as.character(before$type),'_and_')){
     before[n, 'type_1'] <- i[[1]]
     before[n, 'type_2'] <- i[[2]]
     n <- n + 1
}

##   attr          type type_1 type_2
## 1    1   foo_and_bar    foo    bar
## 2   30 foo_and_bar_2    foo  bar_2
## 3    4   foo_and_bar    foo    bar
## 4    6 foo_and_bar_2    foo  bar_2

1

এখানে অন্য বেস আর সমাধান। আমরা ব্যবহার করতে পারি read.tableতবে যেহেতু এটি কেবলমাত্র একটি বাইট sepআর্গুমেন্ট গ্রহণ করে এবং এখানে আমাদের কাছে মাল্টি-বাইট বিভাজক রয়েছে আমরা gsubমাল্টবাইট বিভাজককে যে কোনও একটি বাইট বিভাজককে প্রতিস্থাপন করতে পারি এবং sepযুক্তি হিসাবে এটি ব্যবহার করতে পারিread.table

cbind(before[1], read.table(text = gsub('_and_', '\t', before$type), 
                 sep = "\t", col.names = paste0("type_", 1:2)))

#  attr type_1 type_2
#1    1    foo    bar
#2   30    foo  bar_2
#3    4    foo    bar
#4    6    foo  bar_2

এই ক্ষেত্রে, আমরা এটির পরিবর্তে ডিফল্ট sepযুক্তি দিয়ে এটি আরও সংক্ষিপ্ত করতে পারি যাতে আমাদের এটি স্পষ্টভাবে উল্লেখ করতে হবে না

cbind(before[1], read.table(text = gsub('_and_', ' ', before$type), 
                 col.names = paste0("type_", 1:2)))
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.