问题:如何制作好的可复制熊猫实例

花了相当多的时间观看标签的问题我得到的是pandas问题不太可能包含可重复的数据。 R社区一直非常乐于鼓励,并感谢这个,新手可以在整理这些示例时获得一些帮助。能够阅读这些指南并获得可复制数据的人通常会很幸运地得到他们问题的答案。

我们如何为pandas问题创建良好的可复制示例?可以将简单的数据框放在一起,例如:

import pandas as pd
df = pd.DataFrame({'user': ['Bob', 'Jane', 'Alice'], 
                   'income': [40000, 50000, 42000]})

但是许多示例数据集需要更复杂的结构,例如:

  • datetime索引或数据
  • 多个分类变量(是否具有R的expand.grid()函数的等效项,该函数可生成某些给定变量的所有可能组合?)
  • MultiIndex或Panel数据

对于很难使用几行代码来模拟的数据集,是否有与R的dput()等效的功能,它允许您生成可复制粘贴的代码来重新生成数据结构?

标签:python,pandas

回答1:

注意:这里的想法对于Stack Overflow非常通用,实际上是问题

免责声明:写一个好问题是困难的。

善良

  • 包含小的*示例DataFrame,作为可运行代码:

    In [1]: df = pd.DataFrame([[1, 2], [1, 3], [4, 6]], columns=['A', 'B'])
    

    ,或使用pd.read_clipboard(sep='\ s \ s +'),您可以设置文本的格式以突出显示堆栈溢出并使用 Ctrl + K (或在每行前面添加四个空格),或在代码上方和下方放置三个波浪号,而无需缩进代码:

    In [2]: df
    Out[2]: 
       A  B
    0  1  2
    1  1  3
    2  4  6
    

    test pd.read_clipboard(sep='\s\s+')

    * 我的意思确实是 small ,绝大多数示例DataFrame可能少于6行需要引用,而我敢打赌我可以在5行中完成。您是否可以使用df=df.head()重现该错误,如果没有摆弄一下是否可以组成一个小的DataFrame

    * 每条规则都有一个例外,一个明显的例外是性能问题(在这种情况下,请务必使用%timeit并可能使用%prun ),您应该在其中生成(考虑使用np.random.seed,以便我们使用完全相同的帧):df=pd.DataFrame(np.random.randn(100000000,10))。这么说,"让我的代码快起来"并不是严格意义上的网站主题...

  • 写出您想要的结果(与上面类似)

    In [3]: iwantthis
    Out[3]: 
       A  B
    0  1  5
    1  4  6
    

    解释数字的来源:5是B列的和A为1的行。

  • 显示您尝试过的代码:

    In [4]: df.groupby('A').sum()
    Out[4]: 
       B
    A   
    1  5
    4  6
    

    但是请说出错误之处:索引而不是列。

  • 显示您已进行了一些研究(搜索文档搜索StackOverflow ),给出摘要:< / p>

    sum的文档字符串仅声明"计算组值的总和"

    groupby文档不要为此提供任何示例。

    此外:答案是使用df.groupby('A',as_index=False).sum()

  • 是否与您相关的时间戳列相关,例如您要进行重采样或其他操作,然后明确地对其应用pd.to_datetime以达到良好的效果**。

    df['date'] = pd.to_datetime(df['date']) # this column ought to be date..
    

    ** 有时这就是问题本身:它们是字符串。

坏人:

  • 不包括MultiIndex,我们无法复制和粘贴(请参见上文),这对熊猫默认显示有点不满,但很烦人:

    In [11]: df
    Out[11]:
         C
    A B   
    1 2  3
      2  6
    

    正确的方法是包括一个带有 set_index 调用:

    In [12]: df = pd.DataFrame([[1, 2, 3], [1, 2, 6]], columns=['A', 'B', 'C']).set_index(['A', 'B'])
    
    In [13]: df
    Out[13]: 
         C
    A B   
    1 2  3
      2  6
    
  • 在提供所需结果时确实可以洞察其含义:

       B
    A   
    1  1
    5  0
    

    请具体说明如何获取数字(它们是什么) ...仔细检查它们是否正确。

  • 如果您的代码引发错误,请包括整个堆栈跟踪(如果太吵,可以稍后编辑)。显示行号(以及代码所针对的行)。

丑陋的人

  • 不要链接到我们无权访问的CSV(理想情况下根本不要链接到外部源...)

    df = pd.read_csv('my_secret_file.csv')  # ideally with lots of parsing options
    

    大多数数据是专有的,我们得到的结果是:组成相似的数据,看看是否可以重现问题(很小的问题)。

  • 不要用语言模糊地解释这种情况,就像您有一个"大"的DataFrame一样,在传递时提及一些列名(请确保不要提及它们的dtypes)。尝试深入了解一些完全没有意义的细节,而无需查看实际上下文。大概没有人会读到本段末尾。

    论文很糟糕,使用小例子更容易。

  • 在涉及到您的实际问题之前,请勿包含10+(100+ ??)行数据处理。

    请注意,我们在日常工作中看到了足够多的数据。我们想提供帮助,但不喜欢这样... >
    剪切简介,并在引起麻烦的步骤中显示相关的DataFrame(或其中的小版本)。

无论如何,祝您学习Python,NumPy和Pandas玩得开心!

回答2:

如何创建示例数据集

这主要是通过提供有关如何创建示例数据框的示例来扩展@AndyHayden的答案。熊猫和(特别是)numpy为您提供了多种工具,您通常只需几行代码就可以为任何实际数据集创建合理的传真。

导入numpy和pandas之后,如果您希望人们能够准确地复制数据和结果,请确保提供随机种子。

import numpy as np
import pandas as pd

np.random.seed(123)

一个厨房水槽的例子

这是一个示例,显示了您可以执行的各种操作。各种有用的示例数据帧都可以从以下子集创建:

df = pd.DataFrame({ 

    # some ways to create random data
    'a':np.random.randn(6),
    'b':np.random.choice( [5,7,np.nan], 6),
    'c':np.random.choice( ['panda','python','shark'], 6),

    # some ways to create systematic groups for indexing or groupby
    # this is similar to r's expand.grid(), see note 2 below
    'd':np.repeat( range(3), 2 ),
    'e':np.tile(   range(2), 3 ),

    # a date range and set of random dates
    'f':pd.date_range('1/1/2011', periods=6, freq='D'),
    'g':np.random.choice( pd.date_range('1/1/2011', periods=365, 
                          freq='D'), 6, replace=False) 
    })

这将产生:

          a   b       c  d  e          f          g
0 -1.085631 NaN   panda  0  0 2011-01-01 2011-08-12
1  0.997345   7   shark  0  1 2011-01-02 2011-11-10
2  0.282978   5   panda  1  0 2011-01-03 2011-10-30
3 -1.506295   7  python  1  1 2011-01-04 2011-09-07
4 -0.578600 NaN   shark  2  0 2011-01-05 2011-02-27
5  1.651437   7  python  2  1 2011-01-06 2011-02-03

一些注意事项:

  1. np.repeatnp.tile(列de的列)对于创建组非常有用和索引以非常规则的方式对于2列,可以使用它轻松地复制r的expand.grid(),但在提供所有排列的子集的能力上也更加灵活。但是,对于3列或更多列,语法很快变得难以处理。
  2. 有关r的expand.grid()的更直接替代方法,请参见 itertools解决方案pandas-docs/version/0.16.1/cookbook.html#creating-example-data" rel="noreferrer">熊猫食谱或 np.meshgrid 解决方案显示为 此处。这些将允许任意数量的尺寸。
  3. 您可以使用np.random.choice做很多事情。例如,在g列中,我们从2011年开始随机选择6个日期。此外,通过设置replace=False,我们可以确保这些日期是唯一的-非常方便如果我们想将此作为具有唯一值的索引。

假股市数据

除了获取上述代码的子集之外,您还可以进一步结合这些技术来执行几乎所有操作。例如,这是一个简短的示例,结合了np.tiledate_range来创建涵盖相同日期的4只股票的样本报价数据:

stocks = pd.DataFrame({ 
    'ticker':np.repeat( ['aapl','goog','yhoo','msft'], 25 ),
    'date':np.tile( pd.date_range('1/1/2011', periods=25, freq='D'), 4 ),
    'price':(np.random.randn(100).cumsum() + 10) })

现在,我们有一个示例数据集,其中包含100行(每个行情记录25个日期),但是我们只用了4行就可以做到,这使得其他所有人都可以轻松复制而无需复制和粘贴100行代码。然后,如果可以帮助解释您的问题,则可以显示数据的子集:

>>> stocks.head(5)

        date      price ticker
0 2011-01-01   9.497412   aapl
1 2011-01-02  10.261908   aapl
2 2011-01-03   9.438538   aapl
3 2011-01-04   9.515958   aapl
4 2011-01-05   7.554070   aapl

>>> stocks.groupby('ticker').head(2)

         date      price ticker
0  2011-01-01   9.497412   aapl
1  2011-01-02  10.261908   aapl
25 2011-01-01   8.277772   goog
26 2011-01-02   7.714916   goog
50 2011-01-01   5.613023   yhoo
51 2011-01-02   6.397686   yhoo
75 2011-01-01  11.736584   msft
76 2011-01-02  11.944519   msft

回答3:

答录人日记

我提出问题的最佳建议是发挥回答问题者的心理。作为这些人之一,我可以深入了解为什么我回答某些问题以及为什么我不回答其他问题。

动机

出于各种原因,我有动机回答问题

  1. Stackoverflow.com对我来说是非常宝贵的资源。我想回馈。
  2. 在回馈的过程中,我发现此站点是比以前更强大的资源。回答问题对我来说是一种学习经历,我喜欢学习。 阅读此答案,并请其他兽医发表评论。这种互动使我感到高兴。
  3. 我喜欢积分!
  4. 请参阅#3。
  5. 我喜欢有趣的问题。

我所有最纯粹的意图都是伟大的,但如果我回答1个问题或30个问题,我就会感到满意。是什么决定了我的选择,要回答的问题具有极大的分数最大化。 / p>

我还将花一些时间解决有趣的问题,但这之间相差无几,而且对于需要解决无趣问题的提问者没有帮助。让我回答问题的最佳选择是将问题解答放在一个成熟的平台上,让我尽可能少地回答。如果我在看两个问题,一个有代码,我可以复制粘贴以创建我需要的所有变量...我要使用那个!如果有时间,我会再回到另一个。

主要建议

使人们回答问题变得容易

  • 提供创建所需变量的代码。
  • 最小化该代码。如果我在看帖子时眼神呆滞,那我将继续下一个问题,或者回到我正在做的其他事情。
  • 考虑您的要求并做到具体。我们想看看您做了什么,因为自然语言(英语)不准确且令人困惑。您尝试过的代码示例有助于解决自然语言描述中的不一致问题。
  • 请显示您的期望!!!我必须坐下来尝试一下。如果不尝试一些事情,我几乎永远不会知道问题的答案。如果我看不到您要查找的示例,那么我可能会继续提问,因为我不想猜测。

您的声誉不仅仅是您的声誉。

我喜欢要点(我在上面提到过)。但是这些并不是我真正的声誉。我的真实声誉是网站上其他人对我的看法的融合。我努力做到公平诚实,希望其他人能看到这一点。对于询问者而言,这意味着我们记住询问者的行为。我记得,如果您没有选择答案并推荐好的答案。我记得,如果你的举止表现得我不喜欢或我喜欢。这还将播放我将回答的问题。


无论如何,我可能可以继续,但是我会饶恕所有真正读过这篇文章的人。

回答4:

挑战回答SO问题最具挑战性的方面之一是重新创建问题(包括数据)所花费的时间。没有清晰的方法来重现数据的问题不太可能被回答。既然您花时间写问题,并且有一个需要帮助的问题,则可以通过提供其他人可以用来帮助解决问题的数据来轻松地帮助自己。

@Andy提供的有关编写Pandas良好问题的说明是一个很好的起点。有关更多信息,请参阅如何提问以及如何创建最少,完整和可验证的示例

请提前清楚地说明您的问题。请花一些时间编写您的问题和任何示例代码,然后尝试阅读并为您的读者提供一个"执行摘要",以概括问题并清楚地加以说明。陈述问题。

原始问题

我有此数据...

我要这样做...

我希望我的结果看起来像这样...

但是,当我尝试执行[this]时,出现以下问题...

我试图通过[this]和[that]找到解决方案。

我该如何解决?

根据所提供的数据量,示例代码和错误堆栈,读者需要走很长一段路才能了解问题所在。尝试重新陈述问题,使问题本身排在最前面,然后提供必要的详细信息。

修订的问题

问题:我该怎么做?

我试图通过[this]和[that]找到解决方案。

当我尝试执行[this]时,出现以下问题...

我希望我的最终结果看起来像这样...

这里有一些最小的代码可以重现我的问题...

这是如何重新创建示例数据的方法:df=pd.DataFrame({'A':[...],'B':[...],...})

如果需要,请提供示例数据!

有时仅需要DataFrame的头部或尾部。您还可以使用@JohnE提出的方法来创建更大的数据集,以供其他人复制。使用他的示例生成一个100行的股价DataFrame:

stocks = pd.DataFrame({ 
    'ticker':np.repeat( ['aapl','goog','yhoo','msft'], 25 ),
    'date':np.tile( pd.date_range('1/1/2011', periods=25, freq='D'), 4 ),
    'price':(np.random.randn(100).cumsum() + 10) })

如果这是您的实际数据,则可能只需要按如下所示包含数据框的头部和/或尾部(请确保匿名化任何敏感数据):

>>> stocks.head(5).to_dict()
{'date': {0: Timestamp('2011-01-01 00:00:00'),
  1: Timestamp('2011-01-01 00:00:00'),
  2: Timestamp('2011-01-01 00:00:00'),
  3: Timestamp('2011-01-01 00:00:00'),
  4: Timestamp('2011-01-02 00:00:00')},
 'price': {0: 10.284260107718254,
  1: 11.930300761831457,
  2: 10.93741046217319,
  3: 10.884574289565609,
  4: 11.78005850418319},
 'ticker': {0: 'aapl', 1: 'aapl', 2: 'aapl', 3: 'aapl', 4: 'aapl'}}

>>> pd.concat([stocks.head(), stocks.tail()], ignore_index=True).to_dict()
{'date': {0: Timestamp('2011-01-01 00:00:00'),
  1: Timestamp('2011-01-01 00:00:00'),
  2: Timestamp('2011-01-01 00:00:00'),
  3: Timestamp('2011-01-01 00:00:00'),
  4: Timestamp('2011-01-02 00:00:00'),
  5: Timestamp('2011-01-24 00:00:00'),
  6: Timestamp('2011-01-25 00:00:00'),
  7: Timestamp('2011-01-25 00:00:00'),
  8: Timestamp('2011-01-25 00:00:00'),
  9: Timestamp('2011-01-25 00:00:00')},
 'price': {0: 10.284260107718254,
  1: 11.930300761831457,
  2: 10.93741046217319,
  3: 10.884574289565609,
  4: 11.78005850418319,
  5: 10.017209045035006,
  6: 10.57090128181566,
  7: 11.442792747870204,
  8: 11.592953372130493,
  9: 12.864146419530938},
 'ticker': {0: 'aapl',
  1: 'aapl',
  2: 'aapl',
  3: 'aapl',
  4: 'aapl',
  5: 'msft',
  6: 'msft',
  7: 'msft',
  8: 'msft',
  9: 'msft'}}

您可能还想提供对DataFrame的描述(仅使用相关列)。这样一来,其他人就可以更轻松地检查每一列的数据类型并确定其他常见错误(例如,日期作为字符串与datetime64与对象):

stocks.info()
<class 'pandas.core.frame.DataFrame'>
Int64Index: 100 entries, 0 to 99
Data columns (total 3 columns):
date      100 non-null datetime64[ns]
price     100 non-null float64
ticker    100 non-null object
dtypes: datetime64[ns](1), float64(1), object(1)

注意:如果您的数据框具有MultiIndex:

如果您的DataFrame具有多索引,则必须首先重置,然后再调用to_dict。然后,您需要使用set_index

重新创建索引。
# MultiIndex example.  First create a MultiIndex DataFrame.
df = stocks.set_index(['date', 'ticker'])
>>> df
                       price
date       ticker           
2011-01-01 aapl    10.284260
           aapl    11.930301
           aapl    10.937410
           aapl    10.884574
2011-01-02 aapl    11.780059
...

# After resetting the index and passing the DataFrame to `to_dict`, make sure to use 
# `set_index` to restore the original MultiIndex.  This DataFrame can then be restored.

d = df.reset_index().to_dict()
df_new = pd.DataFrame(d).set_index(['date', 'ticker'])
>>> df_new.head()
                       price
date       ticker           
2011-01-01 aapl    10.284260
           aapl    11.930301
           aapl    10.937410
           aapl    10.884574
2011-01-02 aapl    11.780059

回答5:

这是我的 dput -用于生成可重复报告的标准R工具-适用于熊猫 DataFrame。对于更复杂的框架,它可能会失败,但是在简单情况下,它似乎可以完成工作:

import pandas as pd
def dput (x):
    if isinstance(x,pd.Series):
        return "pd.Series(%s,dtype='%s',index=pd.%s)" % (list(x),x.dtype,x.index)
    if isinstance(x,pd.DataFrame):
        return "pd.DataFrame({" + ", ".join([
            "'%s': %s" % (c,dput(x[c])) for c in x.columns]) + (
                "}, index=pd.%s)" % (x.index))
    raise NotImplementedError("dput",type(x),x)

现在

df = pd.DataFrame({'a':[1,2,3,4,2,1,3,1]})
assert df.equals(eval(dput(df)))
du = pd.get_dummies(df.a,"foo")
assert du.equals(eval(dput(du)))
di = df
di.index = list('abcdefgh')
assert di.equals(eval(dput(di)))

请注意,它产生的输出要比 DataFrame.to_dict ,例如

pd.DataFrame({
  'foo_1':pd.Series([1, 0, 0, 0, 0, 1, 0, 1],dtype='uint8',index=pd.RangeIndex(start=0, stop=8, step=1)),
  'foo_2':pd.Series([0, 1, 0, 0, 1, 0, 0, 0],dtype='uint8',index=pd.RangeIndex(start=0, stop=8, step=1)),
  'foo_3':pd.Series([0, 0, 1, 0, 0, 0, 1, 0],dtype='uint8',index=pd.RangeIndex(start=0, stop=8, step=1)),
  'foo_4':pd.Series([0, 0, 0, 1, 0, 0, 0, 0],dtype='uint8',index=pd.RangeIndex(start=0, stop=8, step=1))},
  index=pd.RangeIndex(start=0, stop=8, step=1))

vs

{'foo_1': {0: 1, 1: 0, 2: 0, 3: 0, 4: 0, 5: 1, 6: 0, 7: 1}, 
 'foo_2': {0: 0, 1: 1, 2: 0, 3: 0, 4: 1, 5: 0, 6: 0, 7: 0}, 
 'foo_3': {0: 0, 1: 0, 2: 1, 3: 0, 4: 0, 5: 0, 6: 1, 7: 0}, 
 'foo_4': {0: 0, 1: 0, 2: 0, 3: 1, 4: 0, 5: 0, 6: 0, 7: 0}}

上面的du,但它保留列类型。例如,在上述测试案例中,

du.equals(pd.DataFrame(du.to_dict()))
==> False

因为du.dtypesuint8pd.DataFrame(du.to_dict()).dtypesint64。

回到顶部