【问题标题】:Python: condensing arbitrarily large dataframe queryPython:压缩任意大的数据帧查询
【发布时间】:2017-06-07 16:22:41
【问题描述】:

我正在使用 pandas 数据框,并且正在迭代几列中所有可能的值组合。我使用itertools.combinationspandas.Series.unique() 来做到这一点:

query_fields = ['direction','subj_id','speed']
query_items = [df_reps[k].unique() for k in query_fields]

for a in itertools.product(*query_items):
    df = df_reps[(df_reps['subj_id']==a[0]) & (df_reps['direction']==a[1]) & (df_reps['speed']==a[2])]
    #Do something with df

我想知道是否有更 Pythonic 的方式来压缩我的数据框查询。如果我有更多可能的查询字段,那么这种方法将变得越来越不可用。一种可能的方法是遍历所有字段并单独应用每个查询(如漏斗) - 这可以通过列表理解来完成,例如:

df = df_reps[(df_reps[qf]==a[i]) for qf,i in enumerate(query_fields)] #Doesn't work

pandas 中是否已经存在此功能?

编辑

输入:一个DataFrame 和一个包含标题的列表。

输出:循环或类似循环,选择标题列表指定的列中的每个唯一值组合。

【问题讨论】:

  • 你没有使用 pandas.DataFrame.unique,你使用的是 pandas.Series.unique。

标签: python pandas dataframe combinations list-comprehension


【解决方案1】:

使用 pandas groupby 可以轻松解决“遍历几列中所有可能的值组合”的问题。 本质上,您根据所有列的值创建组,然后检索每个序列出现的数据部分。不涉及循环,它是单行的。

import pandas as pd
import numpy as np
import itertools

df = pd.DataFrame(np.random.randint(1,4, (100, 5)),
                  columns = ['direction','subj_id','speed','other1', 'other2'])

fields = ['direction','subj_id','speed']  

grouped_by_values = df.groupby(fields)
queries_results = {key: group for key, group in grouped_by_values }

这是一个结果示例:

for key, group in queries_results.iteritems():
#for key, group in grouped_by_values:  #Equivalent, probably better

    print key, group


(1, 1, 1)     direction  subj_id  speed  other1  other2
3           1        1      1       3       3
37          1        1      1       2       3
48          1        1      1       2       1
52          1        1      1       1       3
81          1        1      1       1       1
97          1        1      1       1       1
(1, 1, 2)     direction  subj_id  speed  other1  other2
25          1        1      2       2       3
62          1        1      2       3       1

如果您想知道如何“压缩数据帧查询”,这里有一种方法:生成 boolean masks 列表(每个条件一个),然后使用 @987654323 生成交集@。

这是一个例子:

import pandas as pd
import numpy as np

# Reproducible Example
df = pd.DataFrame(np.random.randint(1,4, (100, 3)), columns = ['A', 'B', 'C'])
query_fields = ['A','B','C']
query_items = [1,2,3]

# Individual masks
ind_masks = [df[key].eq(val) for key, val in zip(query_fields, query_items)]
# Combined Query
mask = reduce(lambda x, y: x & y, ind_masks)

query_result = df[mask]

【讨论】:

  • 使用包含标题的列表作为输入更新答案。
【解决方案2】:

使用 pandas.DataFrame.drop_duplicates;

unique_df = df_reps.drop_duplicates(['direction','subj_id','speed'])

您现在有了一个新的数据框,您可以继续按其他条件进行切片,例如;

unique_df[unique_df['direction'] == 'left']

【讨论】:

  • 虽然这可能是确定这些组合的更好解决方案,但我认为您可能误解了我的问题。我正在尝试找到一种“切片”数据框的方法,而不必像您所做的那样手动列出每个查询 - 我将它们存储在一个列表中,我希望在某种理解中利用它。
  • 如果没有预期的输入和预期的输出,很难知道你到底想做什么,因为没有上下文就很难理解你所写的内容。您引用 df_repsrep_df 时并没有说明它们的开头是什么样的,所以我真的没有办法推断发生了什么。
  • 我意识到我有点含糊,我很抱歉 - 我做了一些编辑希望澄清:)
  • 是的,这仍然没有意义。 query_items 是 pd.Series 对象的列表,您将获得笛卡尔积,其目的和目的与我刚刚向您展示的 unique_df 相同。然后,您反复将 df 分配给产品的原始 df 匹配元素的一部分,这些元素首先来自原始 df,因此您只是在绕圈子。如果你没有提供期望的输入和期望的输出,那么我们都在这里抓住了稻草。
  • 听起来你想要 pd.DataFrame.groupby
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-10-17
  • 2018-11-13
相关资源
最近更新 更多