【问题标题】:Create df or other array that counts entries from another df meeting specific criteria创建 df 或其他数组来计算来自另一个 df 满足特定条件的条目
【发布时间】:2017-09-11 14:50:24
【问题描述】:

我有一个当前 df 包含这样的条目:

     date     tags     ease
0   'date1'  'tag1'    1
1   'date1'  'tag1'    2
2   'date1'  'tag1'    1
3   'date1'  'tag2'    2
4   'date1'  'tag2'    2
5   'date2'  'tag1'    3
6   'date2'  'tag1'    1
7   'date2'  'tag2'    1
8   'date2'  'tag3'    1

我想创建一个 df(或其他类型的数组,如果有更好的方法来解决这个问题 - 我对 Python 很满意,欢迎提出建议),它计算特定标签具有特定标签的次数轻松为 df 中的每个日期。例如,如果我想计算每个标签的轻松度为 1 的次数,它看起来像这样:

       date1    date2
tag1   2        1
tag2   1        2   
tag3   0        1 

我可以想办法使用循环来做到这一点,但我的最终输出将是大约 700 x 800,我需要为每个“轻松”制作一个。我觉得必须有一种使用索引的有效方法来做到这一点,这就是为什么我首先关注 pandas。正如我所说,我对 Python 很陌生,如果有其他方法或包我应该考虑使用,我愿意接受。

【问题讨论】:

  • 请发布您已经进行的任何尝试。
  • 我还没有尝试过索引。老实说,我很想收到一些关于我应该考虑使用的函数或其他包的想法,我可以从那里进行探索。我知道 SO 不是我可以使用的编码器的来源,我只是想知道前进的方向,以便我可以从那里自学。如有必要,我可以编辑帖子以反映这一点。
  • @jk3:不幸的是,SO 也不是关于库或包的推荐或建议的地方(答案往往过于基于意见。)
  • @DSM:我很抱歉……我以后不会再发这样的帖子了。对于将来在哪里可以找到特定项目的库或包记录有什么建议吗?再次感谢您的指导!
  • @jezrael 和 Psidom:感谢您的建议。我现在无法坐下来尝试您的建议,但今晚晚些时候我可以尝试时提供反馈。再次感谢!

标签: python arrays pandas dataframe


【解决方案1】:

我认为你需要boolean indexingcrosstab

df1 = df[df['ease'] == 1]
df = pd.crosstab(df1['tags'], df1['date'])
print (df)
date    'date1'  'date2'
tags                    
'tag1'        2        1
'tag2'        0        1
'tag3'        0        1

另一个解决方案,而不是 crosstab 使用 groupbysize 并重塑 unstack

df = df[df['ease'] == 1].groupby(["date", "tags"]).size().unstack(level=0, fill_value=0)
print (df)
date    'date1'  'date2'
tags                    
'tag1'        2        1
'tag2'        0        1
'tag3'        0        1

编辑:

经过测试我发布的解决方案是必要的添加函数reindexsort_index,因为如果过滤非1的值,它会删除最终DataFrame中的行。

print (df[df['ease'] == 1].groupby(["date", "tags"])
                          .size()
                          .unstack(level=0, fill_value=0)
                          .reindex(index=df.tags.unique(), columns=df.date.unique(), fill_value=0)
                          .sort_index()
                          .sort_index(axis=1))

还有第二种解决方案:

df1 = df[df['ease'] == 1]
df2 = pd.crosstab(df1['tags'], df1['date'])
        .reindex(index=df.tags.unique(), columns=df.date.unique(), fill_value=0)
        .sort_index()
        .sort_index(axis=1)

时间安排

(Psidom 的第二种解决方案在一般情况下是错误的,所以我从时序中省略了它)

np.random.seed(123)
N = 10000
dates = pd.date_range('2017-01-01', periods=100)
tags = ['tag' + str(i) for i in range(100)]
ease = range(10)
df = pd.DataFrame({'date':np.random.choice(dates, N), 
                   'tags': np.random.choice(tags, N),
                   'ease': np.random.choice(ease, N)})
df = df.reindex_axis(['date','tags','ease'], axis=1)
#[10000 rows x 3 columns]
#print (df)
print (df.groupby(["date", "tags"]).agg({"ease": lambda x: (x == 1).sum()}).ease.unstack(level=0).fillna(0))

print (df[df['ease'] == 1].groupby(["date", "tags"]).size().unstack(level=0, fill_value=0).reindex(index=df.tags.unique(), columns=df.date.unique(), fill_value=0).sort_index().sort_index(axis=1))

def jez(df):
    df1 = df[df['ease'] == 1]
    return pd.crosstab(df1['tags'], df1['date']).reindex(index=df.tags.unique(), columns=df.date.unique(), fill_value=0).sort_index().sort_index(axis=1)

print (jez(df))

#Psidom solution
In [56]: %timeit (df.groupby(["date", "tags"]).agg({"ease": lambda x: (x == 1).sum()}).ease.unstack(level=0).fillna(0))
1 loop, best of 3: 1.94 s per loop

In [57]: %timeit (df[df['ease'] == 1].groupby(["date", "tags"]).size().unstack(level=0, fill_value=0).reindex(index=df.tags.unique(), columns=df.date.unique(), fill_value=0).sort_index().sort_index(axis=1))
100 loops, best of 3: 5.74 ms per loop

In [58]: %timeit (jez(df))
10 loops, best of 3: 54.5 ms per loop

【讨论】:

  • 请检查已编辑的答案,我为相同的输出添加了 reindex 和 sort_index 函数,还添加了计时。在我看来有很大的不同,因为更快的是首先过滤较小的 df,其中应用通常较慢的groupby 函数作为通过agg 过滤每个组。
【解决方案2】:

您可以考虑使用 DataFrame 上的 pivot_table 方法和您自己的函数来做一些只有在您想要的条件为真时才有意义的事情。然后,这也应该在没有数据的情况下使用 0 填充标签和日期。类似于:

def calc(column):
    total = 0
    for e in column:
        if e == 1:
            total += 1
    return total

check_res = df.pivot_table(index='tags',columns='date', values='ease', aggfunc=calc, fill_value=0)

【讨论】:

    【解决方案3】:

    这是一种选择;使用groupby.agg计算count,然后unstack将结果转换为宽格式:

    (df.groupby(["date", "tags"])
       .agg({"ease": lambda x: (x == 1).sum()})
       .ease.unstack(level=0).fillna(0))
    

    或者如果你喜欢使用crosstab:

    pd.crosstab(df.tags, df.date, df.ease == 1, aggfunc="sum").fillna(0)
    
    # date  'date1' 'date2'
    # tags      
    #'tag1'   2.0   1.0
    #'tag2'   0.0   1.0
    #'tag3'   0.0   1.0
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-04-06
      • 2018-04-04
      • 2023-03-07
      • 1970-01-01
      • 1970-01-01
      • 2020-10-24
      • 1970-01-01
      • 2021-01-27
      相关资源
      最近更新 更多