我希望生成一个列(Min),找到所选名称列的最小值,并提取列名作为其值。以下是示例数据框:
m = dict(zip([False, True], 'tf'))
f = lambda d: d.sort_values('diff').duplicated('pic_code').map(m)
df.eval('diff=abs(weight - mpe_wgt)').assign(keep=f)
pic_code weight mpe_wgt keep diff
0 1234 45 34 f 11.0
1 1234 32 23 t 9.0
2 45344 54 35 t 19.0
3 234 76 98 t 22.0
4 234 65 12 f 53.0
列u只是位于数据集末尾的列。数据集相当大,因此我试图找到一种有效的方法来生成列Min。
我想到的代码:
Amy Abe Donna Racheal Mike Min u
5 34 54 56 23 Amy 0
43 11 3 33 21 Donna 1
54 32 21 54 1 Mike 1
21 5 43 32 21 Abe 1
32 21 23 5 32 Racheal 0
43 2 2 13 45 Abe Donna 1
.
.
.
这只提取列的名称。我应该添加什么来使列能够比较每行中的值并选择具有最小值的列名?
答案 0 :(得分:3)
您的原始数据:
df1 <- structure(list(Amy = c(5L, 43L, 54L, 21L, 32L, 43L),
Abe = c(34L, 11L, 32L, 5L, 21L, 2L),
Donna = c(54L, 3L, 21L, 43L, 23L, 2L),
Racheal = c(56L, 33L, 54L, 32L, 5L, 13L),
Mike = c(23L, 21L, 1L, 21L, 32L, 45L),
u = c(0, 1, 1, 1, 0, 1)),
row.names = c(NA, -6L),
class = "data.frame")
我们可以使用tidyr
和dplyr
从宽转换为长,进行计算和聚合,然后在最后将它们全部重新组合在一起。
library(dplyr)
library(tidyr)
df1 %>%
gather(name, value, -u) %>% # convert from wide to long
group_by(name) %>%
mutate(idx = row_number()) %>% # add a grouping variable
ungroup() %>%
group_by(idx) %>%
mutate(Min = min(value)) %>% # calculate min per group (= per row)
filter(value == Min) %>% # keep names with value = Min
arrange(idx) %>% # order rows as original data
select(idx, Min = name) %>%
summarise(Min = paste(Min, collapse = ",")) %>% # combine names where Min tied
ungroup() %>%
select(Min) %>%
bind_cols(df1, .) # combine column Min (names) with
# original data
Amy Abe Donna Racheal Mike u Min
1 5 34 54 56 23 0 Amy
2 43 11 3 33 21 1 Donna
3 54 32 21 54 1 1 Mike
4 21 5 43 32 21 1 Abe
5 32 21 23 5 32 0 Racheal
6 43 2 2 13 45 1 Abe,Donna
答案 1 :(得分:2)
以下是我如何做到这一点:
library(tidyverse) # we use dplyr and tidyr
Data <- Data %>%
mutate(row = 1:length(u))
MinData <- Data %>%
gather(name, score, -u, -row, -Min) %>%
group_by(row) %>%
summarize(Min2 = paste(name[score == min(score)], collapse = " ")) %>% # called "Min2" to differentiate it from the "Min" column provided in the example.
left_join(df %>% mutate(row = 1:length(u)), .)
答案 2 :(得分:1)
我使用apply函数:)
设置我们的名字载体
person_names= names(df[,1:5]) #Presumably the column names are the names
1:5
就在那里,以防您在数据集中有其他列,您不想考虑进行最低限度的检查。
现在我们可以在自定义函数上使用apply,该函数返回每行中具有最低值的列的名称。
df$Min <- apply(df[,1:5], 1, function(x){person_names[which.min(x)]})
我们的自定义函数就像我已经描述过的那样,只需将函数应用于数据框或矩阵的每一列或每一行。第二个参数1
表示行,如果我们想要列,我们可以将其更改为2
。
which.min
只返回最小值所在的元素编号。 person_names
按顺序排列我们的名称,which.min
返回一个数字,表示哪个名称的值最小。
如果您想取消person_names
变量,可以将此全部压缩为单行解决方案。
df$Min <- apply(df[,1:5], 1, function(x){names(df[,1:5])[which.min(x)]})
如果您只有5个名称列,请删除1:5
,如果列中有列,只需将其替换为列名或数字的向量。
编辑:我看到你对另一个答案的评论。为了适应关系,我将更改自定义函数,以便检查具有最小x值的所有匹配项,然后将它们与一些自定义分隔符粘贴在一起。我还会修改你的数据,以便Donna和Racheal在第二行打成一条。
df <- read.table(text = 'Amy Abe Donna Racheal Mike Min u
5 34 54 56 23 Amy 0
43 11 3 3 21 Donna 1
54 32 21 54 1 Mike 1
21 5 43 32 21 Abe 1
32 21 23 5 32 Racheal 0', header = T)
person_names <- names(df[,1:5])
df$Min <- apply(df[,1:5], 1, function(x){paste(person_names[x == min(x)],
collapse = ", ")})
> df
Amy Abe Donna Racheal Mike Min u
1 5 34 54 56 23 Amy 0
2 43 11 3 3 21 Donna, Racheal 1
3 54 32 21 54 1 Mike 1
4 21 5 43 32 21 Abe 1
5 32 21 23 5 32 Racheal 0
我已将collapse
参数设置为&#34;,&#34;,这是我任意选择的分隔符。你可以调整这个只是一个空间&#34; &#34;,或分号,或任何你想要的。
同样,可以通过删除person_names
的单独行来将其压缩为一行答案。