Convert API JSON format to data frame - arrays

Im trying to create a new subset data frame from this site using R.
#load libraries
library(dplyr)
library(jsonlite)
library(tidyr)
#source file
url = "http://api.us.socrata.com/api/catalog/v1 q=nasa&domains=data.nasa.gov&offset=0&limit=500"
metadata <- fromJSON(url)
#Create a new data frame
nasa_api <- data.frame(id = metadata$results$resource$id,
title = metadata$results$resource$name,
description = metadata$results$resource$description,
download_count = metadata$results$resource$download_count,
domain_category = metadata$results$classification$domain_category,
link = metadata$results$link,
permlink = metadata$results$permalink)
I notice that metadata object contains nested lists. I need to create a new dataset for classifications which is a data frame nested inside metadata. So ideally I want this new data frame to contain "id" so that I can join these 2 datasets later.
I think it will be an easy task but I am new to R. Please can you help?

I noticed there is a problem in your URL (v1 q=nasa should be v1?q=nasa). As such, I have illustrated how you might solve this problem with the tidyjson package. It can be a lot of typing, but it gives you a solid tidy data_frame afterwards. I recommend the development version from devtools::install_github('jeremystan/tidyjson'), which has some features not yet on CRAN.
In any case, since you did not articulate which nested arrays you are interested in, I just picked one (classification/domain_metadata).
## devtools::install_github('jeremystan/tidyjson')
library(dplyr)
library(tidyjson)
j <- as.tbl_json("http://api.us.socrata.com/api/catalog/v1?q=nasa&domains=data.nasa.gov&offset=0&limit=500")
base <- j %>% enter_object(results) %>% gather_array()
nasa_api <- base %>% spread_values(id = jstring(resource, id), title = jstring(resource,
name), description = jstring(resource, description), download_count = jstring(resource,
download_count), domain_category = jstring(classification, domain_category),
link = jstring(link), permlink = jstring(permlink))
print(nasa_api)
#> # A tbl_json: 500 x 9 tibble with a "JSON" attribute
#> `attr(., "JSON")` document.id array.index id
#> <chr> <int> <int> <chr>
#> 1 "{\"resource\":{\"d..." 1 1 gvk9-iz74
#> 2 "{\"resource\":{\"d..." 1 2 scmi-np9r
#> 3 "{\"resource\":{\"d..." 1 3 gquh-watm
#> 4 "{\"resource\":{\"d..." 1 4 dtgb-tk9p
#> 5 "{\"resource\":{\"d..." 1 5 j6wr-4xhn
#> 6 "{\"resource\":{\"d..." 1 6 357b-ra7j
#> 7 "{\"resource\":{\"d..." 1 7 e2ud-kf5m
#> 8 "{\"resource\":{\"d..." 1 8 uwnx-gns8
#> 9 "{\"resource\":{\"d..." 1 9 fzmj-dfnj
#> 10 "{\"resource\":{\"d..." 1 10 szzb-kefa
#> # ... with 490 more rows, and 6 more variables: title <chr>,
#> # description <chr>, download_count <chr>, domain_category <chr>,
#> # link <chr>, permlink <chr>
## explore the json_types of one of the objects
base %>% enter_object("classification") %>% .[1, ] %>% gather_object() %>% json_types()
#> # A tbl_json: 5 x 4 tibble with a "JSON" attribute
#> `attr(., "JSON")` document.id array.index name
#> <chr> <int> <int> <chr>
#> 1 [] 1 1 categories
#> 2 [] 1 1 tags
#> 3 "\"Management/Ope..." 1 1 domain_category
#> 4 [] 1 1 domain_tags
#> 5 "[{\"value\":\"\",\"k..." 1 1 domain_metadata
#> # ... with 1 more variables: type <fctr>
## example of an ancillary table
base %>% spread_values(id = jstring(resource, id)) %>% enter_object("classification") %>%
enter_object("domain_metadata") %>% gather_array("domain_metadata_id") %>%
spread_values(key = jstring(key), value = jstring(value)) %>% select(document.id,
array.index, id, key, value) %>% as_data_frame()
#> # A tibble: 6,343 x 5
#> document.id array.index id key
#> * <int> <int> <chr> <chr>
#> 1 1 1 gvk9-iz74 Common-Core_Contact-Email
#> 2 1 1 gvk9-iz74 Common-Core_License
#> 3 1 1 gvk9-iz74 Common-Core_System-of-Records
#> 4 1 1 gvk9-iz74 Common-Core_Program-Code
#> 5 1 1 gvk9-iz74 Common-Core_Described-By
#> 6 1 1 gvk9-iz74 Common-Core_Public-Access-Level
#> 7 1 1 gvk9-iz74 Common-Core_Temporal-Applicability
#> 8 1 1 gvk9-iz74 Common-Core_Is-Quality-Data
#> 9 1 1 gvk9-iz74 Common-Core_Language
#> 10 1 1 gvk9-iz74 Common-Core_References
#> # ... with 6,333 more rows, and 1 more variables: value <chr>

Related

loop Tukey post hoc letters extraction

I need to apply a tukey post hoc test to a dataset with 80 columns/variables based on 3 groups/treatments. Is there any way to get a table with all variables in which common characters identify levels or groups that are not significantly different (based on p-values) in an automated way with a loop function?
Does this work for you?
# packages and function conflicts
library(conflicted)
library(emmeans)
library(multcomp)
library(multcompView)
library(tidyverse)
conflict_prefer("select", winner = "dplyr")
#> [conflicted] Will prefer dplyr::select over any other package
# Create example data
dat <- PlantGrowth %>%
transmute(
group = group,
y1 = weight,
y2 = weight * runif(30, 0.8, 1.2),
y3 = weight * runif(30, 0.8, 1.2)
) %>%
as_tibble()
dat
#> # A tibble: 30 x 4
#> group y1 y2 y3
#> <fct> <dbl> <dbl> <dbl>
#> 1 ctrl 4.17 4.22 3.53
#> 2 ctrl 5.58 6.19 6.46
#> 3 ctrl 5.18 5.95 5.66
#> 4 ctrl 6.11 5.36 7.19
#> 5 ctrl 4.5 4.41 5.11
#> 6 ctrl 4.61 3.93 4.89
#> 7 ctrl 5.17 4.36 4.67
#> 8 ctrl 4.53 4.53 4.72
#> 9 ctrl 5.33 4.64 5.86
#> 10 ctrl 5.14 5.34 4.89
#> # ... with 20 more rows
# Loop setup
var_names <- names(dat)[-1]
loop_out <- list()
# Loop
for (var_i in var_names) {
dat_i <- dat %>%
rename(y_i = !!var_i) %>%
select(group, y_i)
mod_i <- lm(y_i ~ group, data = dat_i)
emm_i <- emmeans(mod_i, "group") %>%
cld(Letters = letters)
loop_out[[var_i]] <- emm_i %>%
as_tibble() %>%
select(group, emmean, .group) %>%
rename_with(.cols = -group,
.fn = ~ paste(., var_i, sep = "_"))
}
# Join loop results
loop_out %>% reduce(full_join, by='group')
#> # A tibble: 3 x 7
#> group emmean_y1 .group_y1 emmean_y2 .group_y2 emmean_y3 .group_y3
#> <fct> <dbl> <chr> <dbl> <chr> <dbl> <chr>
#> 1 trt1 4.66 " a " 4.46 " a " 4.64 " a"
#> 2 ctrl 5.03 " ab" 4.89 " ab" 5.30 " a"
#> 3 trt2 5.53 " b" 5.74 " b" 5.39 " a"
Created on 2022-08-08 by the reprex package (v2.0.1)
Check out my summary on the compact letter display for more background.

Permutations of 3 elements within 6 positions

I'm looking to permute (or combine) c("a","b","c") within six positions under the condition to have always sequences with alternate elements, e.g abcbab.
Permutations could easily get with:
abc<-c("a","b","c")
permutations(n=3,r=6,v=abc,repeats.allowed=T)
I think is not possible to do that with gtools, and I've been trying to design a function for that -even though I think it may already exist.
Since you're looking for permutations, expand.grid can work as well as permutations. But since you don't want like-neighbors, we can shorten the dimensionality of it considerably. I think this is legitimate random-wise!
Up front:
r <- replicate(6, seq_len(length(abc)-1), simplify=FALSE)
r[[1]] <- c(r[[1]], length(abc))
m <- t(apply(do.call(expand.grid, r), 1, cumsum) %% length(abc) + 1)
m[] <- abc[m]
dim(m)
# [1] 96 6
head(as.data.frame(cbind(m, apply(m, 1, paste, collapse = ""))))
# Var1 Var2 Var3 Var4 Var5 Var6 V7
# 1 b c a b c a bcabca
# 2 c a b c a b cabcab
# 3 a b c a b c abcabc
# 4 b a b c a b babcab
# 5 c b c a b c cbcabc
# 6 a c a b c a acabca
Walk-through:
since you want all recycled permutations of it, we can use gtools::permutations, or we can use expand.grid ... I'll use the latter, I don't know if it's much faster, but it does a short-cut I need (more later)
when dealing with constraints like this, I like to expand on the indices of the vector of values
however, since we don't want neighbors to be the same, I thought that instead of each row of values being the straight index, we cumsum them; by using this, we can control the ability of the cumulative sum to re-reach the same value ... by removing 0 and length(abc) from the list of possible values, we remove the possibility of (a) never staying the same, and (b) never increasing actually one vector-length (repeating the same value); as a walk-through:
head(expand.grid(1:3, 1:2, 1:2, 1:2, 1:2, 1:2), n = 6)
# Var1 Var2 Var3 Var4 Var5 Var6
# 1 1 1 1 1 1 1
# 2 2 1 1 1 1 1
# 3 3 1 1 1 1 1
# 4 1 2 1 1 1 1
# 5 2 2 1 1 1 1
# 6 3 2 1 1 1 1
Since the first value can be all three values, it's 1:3, but each additional is intended to be 1 or 2 away from it.
head(t(apply(expand.grid(1:3, 1:2, 1:2, 1:2, 1:2, 1:2), 1, cumsum)), n = 6)
# Var1 Var2 Var3 Var4 Var5 Var6
# [1,] 1 2 3 4 5 6
# [2,] 2 3 4 5 6 7
# [3,] 3 4 5 6 7 8
# [4,] 1 3 4 5 6 7
# [5,] 2 4 5 6 7 8
# [6,] 3 5 6 7 8 9
okay, that doesn't seem that useful (since it goes beyond the length of the vector), so we can invoke the modulus operator and a shift (since modulus returns 0-based, we want 1-based):
head(t(apply(expand.grid(1:3, 1:2, 1:2, 1:2, 1:2, 1:2), 1, cumsum) %% 3 + 1), n = 6)
# Var1 Var2 Var3 Var4 Var5 Var6
# [1,] 2 3 1 2 3 1
# [2,] 3 1 2 3 1 2
# [3,] 1 2 3 1 2 3
# [4,] 2 1 2 3 1 2
# [5,] 3 2 3 1 2 3
# [6,] 1 3 1 2 3 1
To verify this works, we can do a diff across each row and look for 0:
m <- t(apply(expand.grid(1:3, 1:2, 1:2, 1:2, 1:2, 1:2), 1, cumsum) %% 3 + 1)
any(apply(m, 1, diff) == 0)
# [1] FALSE
to automate this to an arbitrary vector, we enlist the help of replicate to generate the list of possible vectors:
r <- replicate(6, seq_len(length(abc)-1), simplify=FALSE)
r[[1]] <- c(r[[1]], length(abc))
str(r)
# List of 6
# $ : int [1:3] 1 2 3
# $ : int [1:2] 1 2
# $ : int [1:2] 1 2
# $ : int [1:2] 1 2
# $ : int [1:2] 1 2
# $ : int [1:2] 1 2
and then do.call to expand it.
one you have the matrix of indices,
head(m)
# Var1 Var2 Var3 Var4 Var5 Var6
# [1,] 2 3 1 2 3 1
# [2,] 3 1 2 3 1 2
# [3,] 1 2 3 1 2 3
# [4,] 2 1 2 3 1 2
# [5,] 3 2 3 1 2 3
# [6,] 1 3 1 2 3 1
and then replace each index with the vector's value:
m[] <- abc[m]
head(m)
# Var1 Var2 Var3 Var4 Var5 Var6
# [1,] "b" "c" "a" "b" "c" "a"
# [2,] "c" "a" "b" "c" "a" "b"
# [3,] "a" "b" "c" "a" "b" "c"
# [4,] "b" "a" "b" "c" "a" "b"
# [5,] "c" "b" "c" "a" "b" "c"
# [6,] "a" "c" "a" "b" "c" "a"
and then we cbind the united string (via apply and paste)
Performance:
library(microbenchmark)
library(dplyr)
library(tidyr)
library(stringr)
microbenchmark(
tidy1 = {
gtools::permutations(n = 3, r = 6, v = abc, repeats.allowed = TRUE) %>%
data.frame() %>%
unite(united, sep = "", remove = FALSE) %>%
filter(!str_detect(united, "([a-c])\\1"))
},
tidy2 = {
filter(unite(data.frame(gtools::permutations(n = 3, r = 6, v = abc, repeats.allowed = TRUE)),
united, sep = "", remove = FALSE),
!str_detect(united, "([a-c])\\1"))
},
base = {
r <- replicate(6, seq_len(length(abc)-1), simplify=FALSE)
r[[1]] <- c(r[[1]], length(abc))
m <- t(apply(do.call(expand.grid, r), 1, cumsum) %% length(abc) + 1)
m[] <- abc[m]
},
times=10000
)
# Unit: microseconds
# expr min lq mean median uq max neval
# tidy1 1875.400 2028.8510 2446.751 2165.651 2456.051 12790.901 10000
# tidy2 1745.402 1875.5015 2284.700 2000.051 2278.101 50163.901 10000
# base 796.701 871.4015 1020.993 919.801 1021.801 7373.901 10000
I tried the infix (non-%>%) tidy2 version just for kicks, and though I was confident it would theoretically be faster, I didn't realize it would shave over 7% off the run-times. (The 50163 is likely R garbage-collecting, not "real".) The price we pay for readability/maintainability.
There are probably cleaner methods, but here ya go:
abc <- letters[1:3]
library(tidyverse)
res <- gtools::permutations(n = 3, r = 6, v = abc, repeats.allowed = TRUE) %>%
data.frame() %>%
unite(united, sep = "", remove = FALSE) %>%
filter(!str_detect(united, "([a-c])\\1"))
head(res)
united X1 X2 X3 X4 X5 X6
1 ababab a b a b a b
2 ababac a b a b a c
3 ababca a b a b c a
4 ababcb a b a b c b
5 abacab a b a c a b
6 abacac a b a c a c
If you want a vector, you can use res$united or add %>% pull(united) as an additional step at the end of the pipes above.

How to replace reshape2::melt for an array with tidyr?

I would like to convert a matrix/array (with dimnames) into a data frame. This can be done very easily using reshape2::melt but seems harder with tidyr, and in fact not really possible in the case of an array. Am I missing something? (In particular since reshape2 describes itself as being retired; see https://github.com/hadley/reshape).
For example, given the following matrix
MyScores <- matrix(runif(2*3), nrow = 2, ncol = 3,
dimnames = list(Month = month.name[1:2], Class = LETTERS[1:3]))
we can turn it into a data frame as follows
reshape2::melt(MyScores, value.name = 'Score') # perfect
or, using tidyr as follows:
as_tibble(MyScores, rownames = 'Month') %>%
gather(Class, Score, -Month)
In this case reshape2 and tidyr seem similar (although reshape2 is shorter if you are looking for a long-format data frame).
However for arrays, it seems harder. Given
EverybodyScores <- array(runif(2*3*5), dim = c(2,3,5),
dimnames = list(Month = month.name[1:2], Class = LETTERS[1:3], StudentID = 1:5))
we can turn it into a data frame as follows:
reshape2::melt(EverybodyScores, value.name = 'Score') # perfect
but using tidyr it's not clear how to do it:
as_tibble(EverybodyScores, rownames = 'Month') # looses month information and need to distange Class and StudentID
Is this a situation where the right solution is to stick to using reshape2?
One way I just found by playing around is to coerce via tbl_cube. I have never really used the class but it seems to do the trick in this instance.
EverybodyScores <- array(
runif(2 * 3 * 5),
dim = c(2, 3, 5),
dimnames = list(Month = month.name[1:2], Class = LETTERS[1:3], StudentID = 1:5)
)
library(tidyverse)
library(cubelyr)
EverybodyScores %>%
as.tbl_cube(met_name = "Score") %>%
as_tibble
#> # A tibble: 30 x 4
#> Month Class StudentID Score
#> <chr> <chr> <int> <dbl>
#> 1 January A 1 0.366
#> 2 February A 1 0.254
#> 3 January B 1 0.441
#> 4 February B 1 0.562
#> 5 January C 1 0.313
#> 6 February C 1 0.192
#> 7 January A 2 0.799
#> 8 February A 2 0.277
#> 9 January B 2 0.631
#> 10 February B 2 0.101
#> # ... with 20 more rows
Created on 2018-08-15 by the reprex package (v0.2.0).
Making a tibble drops the row names, but instead of going straight into a tibble, you can make the array into a base R data.frame, then use tidyr::rownames_to_column to make a column for months. Notice that converting to a data frame creates columns with names like A.1, sticking the class and ID together; you can separate these again with tidyr::separate. Calling as_tibble is optional, just for if you care about it being a tibble in the end, and also can come at any point in the workflow once you've made a column from the row names.
library(tidyverse)
EverybodyScores <- array(runif(2*3*5), dim = c(2,3,5),
dimnames = list(Month = month.name[1:2], Class = LETTERS[1:3], StudentID = 1:5))
EverybodyScores %>%
as.data.frame() %>%
rownames_to_column("Month") %>%
gather(key = class_id, value = value, -Month) %>%
separate(class_id, into = c("Class", "StudentID"), sep = "\\.") %>%
as_tibble()
#> # A tibble: 30 x 4
#> Month Class StudentID value
#> <chr> <chr> <chr> <dbl>
#> 1 January A 1 0.576
#> 2 February A 1 0.229
#> 3 January B 1 0.930
#> 4 February B 1 0.547
#> 5 January C 1 0.761
#> 6 February C 1 0.468
#> 7 January A 2 0.631
#> 8 February A 2 0.893
#> 9 January B 2 0.638
#> 10 February B 2 0.735
#> # ... with 20 more rows
Created on 2018-08-15 by the reprex package (v0.2.0).
Here is the new tidyr way to do the same:
library(tidyr)
EverybodyScores <- array(
runif(2 * 3 * 5),
dim = c(2, 3, 5),
dimnames = list(Month = month.name[1:2], Class = LETTERS[1:3], StudentID = 1:5)
)
as_tibble(EverybodyScores, rownames = "Month") %>%
pivot_longer(
cols = matches("^A|^B|^C"),
names_sep = "\\.",
names_to = c("Class", "StudentID")
)
#> # A tibble: 30 x 4
#> Month Class StudentID value
#> <chr> <chr> <chr> <dbl>
#> 1 January A 1 0.0325
#> 2 January B 1 0.959
#> 3 January C 1 0.593
#> 4 January A 2 0.0702
#> 5 January B 2 0.882
#> 6 January C 2 0.918
#> 7 January A 3 0.459
#> 8 January B 3 0.849
#> 9 January C 3 0.901
#> 10 January A 4 0.328
#> # … with 20 more rows
Created on 2021-02-23 by the reprex package (v1.0.0)

Fill the matrix entries using an array

I have a vector of elements
p1 p2 p3 p4 ...
and I'm trying to build, from them, the following matrix
p1 p2 p3 1 1 1 1 1 1 1 1 1 ...
p1 p2 p3 p4 p5 p6 1 1 1 1 1 1 ...
p1 p2 p3 p4 p5 p6 p7 p8 p9 1 1 1 ...
p1 p2 p3 p4 p5 p6 p7 p8 p9 p10 p11 p12 ...
and so on. I tried to use
blockmatrix
For example
p<-1:6
A<-head(p,3)
B<-c(1,1,1)
D<-tail(p,3)
blockmatrix(names=c("A","B","C","D"),A=A,C=B,B=A,D=D,dim=c(2,2))
But the problem is to obtain block matrices of larger size. (This code works only for two blocks, for three block I would add other labels in the field "names", and so on for four blocks, five...)
This is another solution, written after the read of answers:
x<-2:10
mat<- t(replicate(3, x))
mat[col(mat)>3*row(mat)] <- 1
This will give you a dataframe output, but you can transform it into a matrix.
library(dplyr)
library(tidyr)
# example vector
x = c(10,11,12,13,14,15)
expand.grid(id_row=1:length(x), x=x) %>% # combine vector values and a sequence of numbers (id = row positions)
group_by(id_row) %>% # for each row position
mutate(id_col = row_number()) %>% # create a vector of column positions (needed for reshaping later)
ungroup() %>% # forget the grouping
mutate(x = ifelse(id_col > id_row, 1, x), # replace values with 1 where necessary
id_col = paste0("Col_", id_col)) %>% # update names of this variable
spread(id_col, x) %>% # reshape data
select(-id_row) # remove unnecessary column
# # A tibble: 6 x 6
# Col_1 Col_2 Col_3 Col_4 Col_5 Col_6
# * <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
# 1 10 1 1 1 1 1
# 2 10 11 1 1 1 1
# 3 10 11 12 1 1 1
# 4 10 11 12 13 1 1
# 5 10 11 12 13 14 1
# 6 10 11 12 13 14 15
It is not clear about all the conditions. Here is a base R option
m1 <- t(replicate(length(x), x))
m1[upper.tri(m1)] <- 1
m1
# [,1] [,2] [,3] [,4] [,5] [,6]
#[1,] 10 1 1 1 1 1
#[2,] 10 11 1 1 1 1
#[3,] 10 11 12 1 1 1
#[4,] 10 11 12 13 1 1
#[5,] 10 11 12 13 14 1
#[6,] 10 11 12 13 14 15
data
x <- c(10,11,12,13,14,15)
this should give you desired output, in Base R
a<- c("p1","p2","p3","p4","p5","p6","p7","p8","p9","p10","p11","p12")
lena <- length(a)
b<- matrix(data=rep(a,lena%/%3),nrow=lena%/%3,ncol = lena,byrow=T)
for (i in (1:(nrow(b)-1)))
{
for (j in ((3*i+1):ncol(b)))
{
b[i,j] <- 1
}
}

storing value against variable name "QW1I5K20" in an array element Q[1,5,20] using R

I have an excel file (.csv) with a sorted column of variable names such as "QW1I1K5" and numerical values against them.
this list goes on for
W from 1 to 15
I from 1 to 4
K from 1 to 30
total elements = 15*4*30 = 1800
I want to store the numerical values against these variables in an array whose indices are derived from the variable name .
for example QW1I1K5 has a value 11 . this must be stored in an array element Q[1,1,5] = 11 ( index set of [1,1,5] corresponds to W1 , I1 , K5)
May be this helps
Q <- array(dat$Col2, dim=c(15,4,30))
dat$Col2[dat$Col1=='QW1I1K5']
#[1] 34
Q[1,1,5]
#[1] 34
dat$Col2[dat$Col1=='QW4I3K8']
#[1] 38
Q[4,3,8]
#[1] 38
If you want the index along with the values
library(reshape2)
d1 <- melt(Q)
head(d1,3)
# Var1 Var2 Var3 value
#1 1 1 1 12
#2 2 1 1 9
#3 3 1 1 29
Q[1,1,1]
#[1] 12
Q[3,1,1]
#[1] 29
Update
Suppose, your data is in the order as you described in the comments, which will be dat1
indx <- read.table(text=gsub('[^0-9]+', ' ', dat1$Col1), header=FALSE)
dat2 <- dat1[do.call(order, indx[,3:1]),]
Q1 <- array(dat2$Col2,dim=c(15,4,30))
Q1[1,1,2]
#[1] 20
dat2$Col2[dat2$Col1=='QW1I1K2']
#[1] 20
data
Col1 <- do.call(paste,c(expand.grid('QW', 1:15, 'I', 1:4, 'K',1:30),
list(sep='')))
set.seed(24)
dat <- data.frame(Col1, Col2=sample(1:40, 1800,replace=TRUE))
dat1 <- dat[order(as.numeric(gsub('[^0-9]+', '', dat$Col1))),]
row.names(dat1) <- NULL
I would suggest looking at using "data.table" and setting your key to the split columns. You can use cSplit from my "splitstackshape" function to easily split the column.
Sample Data:
df <- data.frame(
V1 = c("QW1I1K1", "QW1I1K2", "QW1I1K3",
"QW1I1K4", "QW2I1K5", "QW2I3K2"),
V2 = c(15, 20, 5, 6, 7, 9))
df
# V1 V2
# 1 QW1I1K1 15
# 2 QW1I1K2 20
# 3 QW1I1K3 5
# 4 QW1I1K4 6
# 5 QW2I1K5 7
# 6 QW2I3K2 9
Splitting the column:
library(splitstackshape)
out <- cSplit(df, "V1", "[A-Z]+", fixed = FALSE)
setnames(out, c("V2", "W", "I", "K"))
setcolorder(out, c("W", "I", "K", "V2"))
setkey(out, W, I, K)
out
# W I K V2
# 1: 1 1 1 15
# 2: 1 1 2 20
# 3: 1 1 3 5
# 4: 1 1 4 6
# 5: 2 1 5 7
# 6: 2 3 2 9
Extracting rows:
out[J(1, 1, 4)]
# W I K V2
# 1: 1 1 4 6
out[J(2, 3, 2)]
# W I K V2
# 1: 2 3 2 9

Resources