如何在pandas中跨多个数据帧列进行“选择不同”操作?

192
我在寻找一种类似于SQL中的操作方法。
SELECT DISTINCT col1, col2 FROM dataframe_table

pandas的sql比较中并没有关于distinct的内容。

.unique()只适用于单列,所以我想我可以将列连接起来,或者将它们放在一个列表/元组中进行比较,但这似乎不是pandas更本地的方式。

我是否漏掉了一些明显的东西,或者根本没有办法做到这一点?


你需要做类似于 df.apply(pd.Series.unique) 这样的操作,但是如果每列的唯一值数量不同,这种方法就行不通了,所以你需要构建一个字典,将列名作为键,唯一值作为值。 - EdChum
SO文档 - user2314737
8个回答

297
您可以使用 drop_duplicates 方法获取 DataFrame 中的唯一行:
In [29]: df = pd.DataFrame({'a':[1,2,1,2], 'b':[3,4,3,5]})

In [30]: df
Out[30]:
   a  b
0  1  3
1  2  4
2  1  3
3  2  5

In [32]: df.drop_duplicates()
Out[32]:
   a  b
0  1  3
1  2  4
3  2  5

如果您只想使用某些列来确定唯一性,还可以提供 subset 关键字参数。请参见docstring


27
值得注意的是,默认情况下,df.drop_duplicates() 不是一个原地操作方法,因此会返回一个新的 DataFrame(不改变 df)。虽然这是相当标准的行为,但仍然值得指出。 - evophage

35

我尝试过不同的解决方案。首先是:

a_df=np.unique(df[['col1','col2']], axis=0)

它适用于非对象数据,并且效果良好。另一种避免出错的方法(适用于对象列类型)是应用drop_duplicates()。

a_df=df.drop_duplicates(['col1','col2'])[['col1','col2']]

你也可以使用SQL来完成这个任务,但在我的情况下它非常慢:

from pandasql import sqldf
q="""SELECT DISTINCT col1, col2 FROM df;"""
pysqldf = lambda q: sqldf(q, globals())
a_df = pysqldf(q)

13
为了解决类似的问题,我正在使用 groupby
print(f"Distinct entries: {len(df.groupby(['col1', 'col2']))}")

不过,这是否合适取决于您想要对结果做什么(在我的情况下,我只想要与 COUNT DISTINCT 相当的结果,如所示)。


9

如果每列的唯一值数量相同,则可以使用以下代码:df.apply(pd.Series.unique),但是如果不是这样,则会出现错误。另一种方法是将值存储在以列名为键的字典中:

In [111]:
df = pd.DataFrame({'a':[0,1,2,2,4], 'b':[1,1,1,2,2]})
d={}
for col in df:
    d[col] = df[col].unique()
d

Out[111]:
{'a': array([0, 1, 2, 4], dtype=int64), 'b': array([1, 2], dtype=int64)}

能否检查多列的唯一性? - Anoop D
使用numpy np.unique(df[['column1','column2']].values) 在另一个SO问题中找到了答案。 - Anoop D

9

1
我认为以下是最干净的方法:
df.filter(items=['Column A', 'Column B']).drop_duplicates()

0

你可以取两列的集合,然后从大的集合中减去小的集合:

distinct_values = set(df['a'])-set(df['b'])

0
我在寻找使用Apache Spark for .NET (C#)解决同样问题时偶然发现了这个问题。
以下是对我有效的解决方法(假设有一个包含CSV文件列表的文件夹):
string filePath = "file:///Users/me/dups/*";

var opts = new Dictionary<string, string>();
opts.Add("header", "true");
opts.Add("quote", "\"");
opts.Add("multiLine", "true");
opts.Add("sep", ",");

// load data
DataFrame df1 = spark.Read()
   .Options(opts)
   .Csv(filePath);

// columns to distinct on. in my case, there was 1 column I knew that was distinct per row so I listed all columns below minus that one.
Column[] columns = {
    Col("MyColumn1"),
    Col("MyColumn2"),
    // etc.
};

var distinctCount = df1
    .Select(columns)
    .Distinct()
    .Count();

Console.WriteLine(distinctCount);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接