从R中的数据框中删除重复的行

时间:2016-06-30 07:42:44

标签: r matrix reshape transpose reshape2

我有两列,只想保留非交换行。对于下面的数据,我的输出应该包含一个(1 2)的组合。即,对于我的查询(1 2)与(2 1)相同。有没有一种简单的方法在R中做到这一点。已经尝试过调换。并保留上部的traingular矩阵。但转移数据变得很痛苦。

<div id = "first">0</div>
<div id = "second">0</div>
<button type="button" id="but">
Shift 0,0
</button>

我的最终输出应该是:

A B prob
1 2 0.1
1 3 0.2
1 4 0.3
2 1 0.3
2 3 0.1
2 4 0.4

4 个答案:

答案 0 :(得分:7)

我们可以独立sort()每行,然后使用$a == $b duplicated()查找要保留的行:

!

数据

df[!duplicated(t(apply(df[1:2],1L,sort))),];
##   A B prob
## 1 1 2  0.1
## 2 1 3  0.2
## 3 1 4  0.3
## 5 2 3  0.1
## 6 2 4  0.4

解释

第一步是仅提取两个感兴趣的列:

df <- data.frame(A=c(1L,1L,1L,2L,2L,2L),B=c(2L,3L,4L,1L,3L,4L),prob=c(0.1,0.2,0.3,0.3,0.1,0.4
));

然后我们使用apply()df[1:2]; ## A B ## 1 1 2 ## 2 1 3 ## 3 1 4 ## 4 2 1 ## 5 2 3 ## 6 2 4

对每行进行独立排序
sort()

正如您所看到的,apply(df[1:2],1L,sort); ## [,1] [,2] [,3] [,4] [,5] [,6] ## [1,] 1 1 1 1 2 2 ## [2,] 2 3 4 2 3 4 会在意外转置中返回其结果,因此我们必须使用t()进行修复,以便为即将到来的apply()电话做准备:

duplicated()

现在我们可以使用t(apply(df[1:2],1L,sort)); ## [,1] [,2] ## [1,] 1 2 ## [2,] 1 3 ## [3,] 1 4 ## [4,] 1 2 ## [5,] 2 3 ## [6,] 2 4 来获取一个逻辑向量,指示哪些行与前一行重复:

duplicated()

然后我们用一个否定反转逻辑向量,得到那些重复任何前一行的行:

duplicated(t(apply(df[1:2],1L,sort)));
## [1] FALSE FALSE FALSE  TRUE FALSE FALSE

最后,我们可以使用生成的逻辑向量来索引!duplicated(t(apply(df[1:2],1L,sort))); ## [1] TRUE TRUE TRUE FALSE TRUE TRUE 的那些不与之前任何行重复的行:

df

因此,将保留每组排序后重复项的第一次次出现,其余部分将被删除。

来自@RichardScriven的优秀建议;我们可以使用df[!duplicated(t(apply(df[1:2],1L,sort))),]; ## A B prob ## 1 1 2 0.1 ## 2 1 3 0.2 ## 3 1 4 0.3 ## 5 2 3 0.1 ## 6 2 4 0.4 的{​​{1}}参数替换t()调用,这可能会稍快一点:

MARGIN

答案 1 :(得分:3)

我们可以使用data.table。转换&#39; data.frame&#39;到&#39; data.table&#39; (setDT(df1)),按pmin(A, B)pmax(A,B)分组,if行数大于1,我们得到第一行或else返回行。

 library(data.table)
 setDT(df1)[, if(.N >1) head(.SD, 1) else .SD ,.(A=pmin(A, B), B= pmax(A, B))]
 #   A B prob
 #1: 1 2  0.1
 #2: 1 3  0.2
 #3: 1 4  0.3
 #4: 2 3  0.1
 #5: 2 4  0.4

或者我们可以在duplicatedpmax输出上使用pmin来返回逻辑索引并根据该数据对数据进行子集化。

 setDT(df1)[!duplicated(cbind(pmax(A, B), pmin(A, B)))]
 #   A B prob
 #1: 1 2  0.1
 #2: 1 3  0.2
 #3: 1 4  0.3
 #4: 2 3  0.1
 #5: 2 4  0.4

答案 2 :(得分:1)

这应该有效:

import java.util.Date;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

public class TimeAgo {

    public static final Map<String, Long> times = new LinkedHashMap<>();

    static {
        times.put("year", TimeUnit.DAYS.toMillis(365));
        times.put("month", TimeUnit.DAYS.toMillis(30));
        times.put("week", TimeUnit.DAYS.toMillis(7));
        times.put("day", TimeUnit.DAYS.toMillis(1));
        times.put("hour", TimeUnit.HOURS.toMillis(1));
        times.put("minute", TimeUnit.MINUTES.toMillis(1));
        times.put("second", TimeUnit.SECONDS.toMillis(1));
    }

    public static String toRelative(long duration, int maxLevel) {
        StringBuilder res = new StringBuilder();
        int level = 0;
        for (Map.Entry<String, Long> time : times.entrySet()){
            long timeDelta = duration / time.getValue();
            if (timeDelta > 0){
                res.append(timeDelta)
                        .append(" ")
                        .append(time.getKey())
                        .append(timeDelta > 1 ? "s" : "")
                        .append(", ");
                duration -= time.getValue() * timeDelta;
                level++;
            }
            if (level == maxLevel){
                break;
            }
        }
        if ("".equals(res.toString())) {
            return "0 seconds ago";
        } else {
            res.setLength(res.length() - 2);
            res.append(" ago");
            return res.toString();
        }
    }

    public static String toRelative(long duration) {
        return toRelative(duration, times.size());
    }

    public static String toRelative(Date start, Date end){
        assert start.after(end);
        return toRelative(end.getTime() - start.getTime());
    }

    public static String toRelative(Date start, Date end, int level){
        assert start.after(end);
        return toRelative(end.getTime() - start.getTime(), level);
    }
}

请注意,这将使用模式的第一次出现。

答案 3 :(得分:0)

这是使用基础R的另一个解决方案。想法是在df的后半部分(使用sapply)搜索,如果有任何重复。然后我们返回secondHalf向量。我们会从df进一步删除这些行。

n <- nrow(df)
secondHalf <- sapply(seq(n/2), function(i) nrow(df[df$A==df[i,2] & df$B==df[i,1],]))
# [1] 1 0 0
toRemove <- ((floor(n/2)+1):n)*secondHalf
df <- df[-toRemove,]

  # A B prob
# 1 1 2  0.1
# 2 1 3  0.2
# 3 1 4  0.3
# 5 2 3  0.1
# 6 2 4  0.4