【问题标题】:Building separated columns for each category from columns that categories are mixed从类别混合的列中为每个类别构建单独的列
【发布时间】:2019-01-02 04:42:37
【问题描述】:

我有一个调查数据框,其中包含三个类别的评估。我确实希望在每一列中看到每个类别的评价,但它是这样混合的,

ID  q1 q2 q3 q4 q5 q6
1   c2 e1 c1 e1 c3 e2
2   c1 e1 c3 e2 c2 e0
3   c3 e0 c2 e2 c1 e1

我想得到的是:

ID  c1 c2 c3
1   e1 e1 e2
2   e1 e0 e2
3   e1 e2 e0

但是,通过 stringr 和 dplyr 尝试了几种方法,现在我只是卡在这里:

ID  a1    a2    a3
1   c1-e1 c2-e1 c3-e2
2   c1-e1 c2-e0 c3-e2
3   c1-e1 c2-e2 c3-e0

有谁知道如何解决这个问题?提前谢谢!

【问题讨论】:

  • 初始数据和你预期的输出背后的逻辑是什么?我不清楚这里发生了什么。
  • @thelatemail 感谢您的评论和我的解释道歉!我正在尝试为回归分析构建自变量。在这种情况下,每个类别(c1,c2,c3)的评估将是三个自变量。给你上下文就够了吗?
  • @thelatemill 所以这项调查询问了受访者对每个类别的评价。但是问题的顺序是随机的。他们按照 c2 > c1 > c3(第一个矩阵中的 id 1)的顺序询问某人,然后按照 c1 > c3 > c2(id 2)的顺序询问另一个人。调查组没有按类别排列这些数据。

标签: r dplyr data-cleaning stringr


【解决方案1】:

我们可以使用split 根据列名分隔列中的值。

如果您的列有限,您可以手动创建列(就像我一样),或者根据列的结构使用paste 和seq 以编程方式进行。

cols <- c("q1", "q3", "q5")
vals <- c("q2", "q4", "q6")
do.call("cbind.data.frame", split(unlist(df[vals]), unlist(df[cols])))

#    c1 c2 c3
#q22 e1 e1 e0
#q41 e1 e2 e2
#q63 e1 e0 e2

你可以cbind第一列得到ID列回来。

cbind(df[1], do.call("cbind.data.frame", split(unlist(df[vals]), unlist(df[cols]))))

#    ID c1 c2 c3
#q22  1 e1 e1 e0
#q41  2 e1 e2 e2
#q63  3 e1 e0 e2

正如@Farah Nazifa 所提到的,如果我们想保持每一列的行顺序,我们可以使用mapply,如下所示。

col_values <- unlist(df[cols])
data.frame(mapply(function(x, y) x[y], 
    split(unlist(df[vals]), col_values), split(row(df[vals]), col_values)))

#    c1 c2 c3
#q41 e1 e1 e2
#q22 e1 e0 e2
#q63 e1 e2 e0

【讨论】:

  • 答案相似但不准确。还有什么可以做的吗?
  • @FarahNazifa 答案中缺少什么?
  • c2 & c3 与预期输出不匹配
  • @FarahNazifa 谢谢,也许你是对的。我也更新了该案例的答案。
  • 不知道为什么,但“映射”部分对我不起作用。但我可以学习如何处理这种情况。非常感谢!
【解决方案2】:

看起来像一个很长的堆栈,然后将其整形为宽格式即可完成此操作。这个逻辑有大约 320 万种变体,但这里有一个:

tmp <- reshape(dat, idvar="ID", varying=list(c(2,4,6),c(3,5,7)),
               v.names=c("name","value"), direction="long", timevar=NULL)

#    ID name value
#1.1  1   c2    e1
#2.1  2   c1    e1
#3.1  3   c3    e0
#1.2  1   c1    e1
#2.2  2   c3    e2
#3.2  3   c2    e2
#1.3  1   c3    e2
#2.3  2   c2    e0
#3.3  3   c1    e1

这种长格式甚至可以用于建模目的。如果您确实需要宽格式,请再次整形:

reshape(tmp, idvar="ID", timevar="name", direction="wide")

#    ID value.c2 value.c1 value.c3
#1.1  1       e1       e1       e2
#2.1  2       e0       e1       e2
#3.1  3       e2       e1       e0

【讨论】:

  • 正是我想要的!我刚刚删除了 因为我之前已经设置过了。宽格式的评论也很有帮助。我的因变量超出了我上传的数据框,因此保持行号和顺序很重要。现在我将把它加入一个更大的数据集。非常感谢!
【解决方案3】:

我们可以从data.table使用melt/dcast

library(data.table)
dcast(melt(setDT(df1), measure = patterns('^q[135]', '^q[246]')),
           ID ~ value1, value.var = 'value2')
#    ID c1 c2 c3
#1:  1 e1 e1 e2
#2:  2 e1 e0 e2
#3:  3 e1 e2 e0

数据

df1 <- structure(list(ID = 1:3, q1 = c("c2", "c1", "c3"), q2 = c("e1", 
"e1", "e0"), q3 = c("c1", "c3", "c2"), q4 = c("e1", "e2", "e2"
 ), q5 = c("c3", "c2", "c1"), q6 = c("e2", "e0", "e1")), 
class = "data.frame", row.names = c(NA, -3L))

【讨论】:

  • 它显示了我想要的最接近的答案,但无法保持原始行顺序。能否请教您进一步的建议?
  • @Ji-WonLee 如果我检查您的预期输出,它是相同的顺序。你能说得更具体些吗
  • @Ji-WonLee 我假设您的评论是基于其他一些数据集。这是真的吗
  • (+) 没关系!我在其他人的评论中想到了这一点。感谢您的帮助。
猜你喜欢
  • 2017-08-28
  • 1970-01-01
  • 1970-01-01
  • 2021-08-12
  • 2019-01-07
  • 2018-03-20
  • 2018-06-09
  • 2020-02-13
  • 1970-01-01
相关资源
最近更新 更多