如何制作良好的可重复的熊猫示例
- 2024-11-15 08:36:00
- admin 原创
- 18
问题描述:
在花了相当多的时间观看r和熊猫标签,我得到的印象是pandas
问题不太可能包含可重现的数据。这是 R 社区一直非常鼓励的事情,而且由于有了这样的指南,新手能够在整理这些示例时获得一些帮助。能够阅读这些指南并带回可重现数据的人通常会更幸运地获得问题的答案。
我们如何为pandas
问题创建良好的可重复示例?可以将简单的数据框放在一起,例如:
import pandas as pd
df = pd.DataFrame({'user': ['Bob', 'Jane', 'Alice'],
'income': [40000, 50000, 42000]})
但是许多示例数据集需要更复杂的结构,例如:
datetime
指数或数据多个分类变量(是否有与 R 函数等效的
expand.grid()
函数,可以生成某些给定变量的所有可能组合?)多索引数据
对于难以使用几行代码模拟的数据集,是否有与 R 等效的程序dput()
允许您生成可复制粘贴的代码来重新生成数据结构?
解决方案 1:
注意:这里的大部分想法对于 Stack Overflow 来说非常通用,实际上也是一般问题。请参阅最小、可重现的示例或简短、独立、正确的示例。
免责声明:写出一个好的问题很难。
优点:
请包含一个小示例 DataFrame,可以作为可运行代码:
In [1]: df = pd.DataFrame([[1, 2], [1, 3], [4, 6]], columns=['A', 'B'])
或者使用 使其“可复制和粘贴” pd.read_clipboard(sep=r'ss+')
。
In [2]: df
Out[2]:
A B
0 1 2
1 1 3
2 4 6
亲自测试以确保它能正常工作并重现问题。
+ 您可以通过突出显示和使用+ (或在每行前面添加四个空格)来格式化 Stack Overflow 的文本,或者在代码上方和下方放置三个反引号(“``”),并且代码不缩进。`Ctrl``K`
+ 我确实是指**小**。绝大多数示例 DataFrames 可能少于 6 行,[需要引用]并且**我敢打赌我可以在 5 中完成**。您可以使用重现错误吗`df = df.head()`?如果不能,请摆弄一下,看看您是否可以制作一个小的 DataFrame 来展示您所面临的问题。
但是每条规则都有例外,明显的例外是性能问题(在这种情况下肯定会使用`%timeit`并且可能`%prun`要分析你的代码),你应该生成:
df = pd.DataFrame(np.random.randn(100000000, 10))
考虑使用`np.random.seed`,这样我们就有了完全相同的框架。话虽如此,“让这段代码对我来说更快”并不是该网站的严格主题。
+ 对于获取可运行代码,`df.to_dict`通常很有用,`orient`不同情况下有不同的选项。在上面的例子中,我可以从中获取数据和列`df.to_dict('split')`。
写出你想要的结果(与上述类似)
In [3]: iwantthis
Out[3]:
A B
0 1 5
1 4 6
解释一下这些数字的来源:
5 是 A 为 1 的行中 B 列的总和。
请显示您已尝试过的代码:
In [4]: df.groupby('A').sum()
Out[4]:
B
A
1 5
4 6
但说一下不正确的地方:
A 列位于索引中,而不是列中。
请表明你已经做了一些研究(搜索文档、搜索 Stack Overflow),并给出总结:
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,因为我们无法复制和粘贴它(见上文)。这有点不满意 Pandas 的默认显示,但仍然很烦人:
In [11]: df
Out[11]:
C
A B
1 2 3
2 6
正确的方法是包含一个带有调用的普通 DataFrame set_index
:
In [12]: df = pd.DataFrame([[1, 2, 3], [1, 2, 6]], columns=['A', 'B', 'C'])
In [13]: df = df.set_index(['A', 'B'])
In [14]: df
Out[14]:
C
A B
1 2 3
2 6
在给出您想要的结果时,请提供以下见解:
B
A
1 1
5 0
具体说明你是如何得到这些数字的(它们是什么)...仔细检查它们是否正确。
如果您的代码抛出错误,请包含整个堆栈跟踪。如果太嘈杂,可以稍后将其删除。显示行号和它所针对的代码的相应行。
Pandas 2.0 引入了许多变化,而之前的Pandas 1.0 也进行了改进,因此如果您得到了意外的输出,请包含以下版本:
pd.__version__
就这一点而言,您可能还想包含 Python 版本、操作系统和任何其他库。您可以使用pd.show_versions()
或session_info
包(显示已加载的库和 Jupyter/IPython 环境)。
丑陋的一面:
不要链接到我们无权访问的 CSV 文件(最好根本不要链接到外部源)。
df = pd.read_csv('my_secret_file.csv') # ideally with lots of parsing options
我们知道,大多数数据都是专有的。制作类似的数据,看看是否可以重现问题(一些小问题)。
不要用语言含糊地解释情况,比如你有一个“很大”的 DataFrame,顺便提一下一些列名(确保不要提及它们的 dtype)。尝试详细阐述一些完全没有意义的、没有看到实际上下文的内容。大概没人会读到本段的结尾。
论文很糟糕;用小例子会更容易。
在回答实际问题之前,不要包含 10+(100+??)行数据。
拜托,我们在日常工作中已经见多了这样的情况。我们想提供帮助,但不想这样……。删掉简介,只显示导致您遇到麻烦的步骤中的相关 DataFrame(或它们的小版本)。
解决方案 2:
如何创建示例数据集
这主要是为了扩展AndyHayden 的答案,提供如何创建示例数据框的示例。Pandas 和(尤其是)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
一些说明:
np.repeat
和np.tile
(列d
和e
)对于以非常规则的方式创建组和索引非常有用。对于 2 列,这可用于轻松复制 r,expand.grid()
但在提供所有排列的子集方面也更灵活。但是,对于 3 列或更多列,语法很快就会变得笨拙。有关 R 的更直接替代品,
expand.grid()
请参阅pandas cookbookitertools
中的解决方案或此处显示的解决方案。它们将允许任意数量的维度。np.meshgrid
你可以用 做很多事情
np.random.choice
。例如,在 列中g
,我们从 2011 年随机选择了六个日期。此外,通过设置,replace=False
我们可以确保这些日期是唯一的——如果我们想将其用作具有唯一值的索引,这非常方便。
虚假股市数据
除了使用上述代码的子集之外,您还可以进一步组合这些技术来执行几乎任何操作。例如,下面是一个简短的示例,它结合np.tile
和date_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:
答题者日记
我对于提问的最佳建议是利用回答问题的人的心理。作为回答者之一,我可以深入了解我为什么回答某些问题,为什么不回答其他问题。
动机
我回答问题有几个原因
Stackoverflow.com 对我来说是一个非常宝贵的资源。我想回报它。
在努力回馈的过程中,我发现这个网站比以前更加有用。回答问题对我来说是一种学习经历,我喜欢学习。 阅读另一位兽医的回答和评论。这种互动让我很开心。
我喜欢积分!
见#3。
我喜欢有趣的问题。
我所有最纯粹的意图都是伟大的,但是如果我回答 1 个或 30 个问题,我就会感到满足。 我选择回答哪些问题的驱动因素在很大程度上取决于积分最大化。
我也会花时间解决有趣的问题,但这种情况很少见,而且对需要解决无趣问题的提问者没有帮助。让我回答问题的最佳方法是将问题放在一个盘子上,让我尽可能少地回答。如果我正在看两个问题,其中一个有代码,我可以复制粘贴来创建我需要的所有变量……我会选择那个!如果有时间,我可能会回过头来回答另一个。
主要建议
让人们轻松回答问题。
提供创建所需变量的代码。
尽量减少代码。如果我在看帖子时目光呆滞,我就会转向下一个问题或返回去做我正在做的其他事情。
考虑一下您要问的问题,并具体说明。我们希望了解您做了什么,因为自然语言(英语)不准确且令人困惑。您尝试过的代码示例有助于解决自然语言描述中的不一致问题。
请展示您所期望的内容!!!我必须坐下来尝试一些东西。如果不尝试一些东西,我几乎永远不知道问题的答案。如果我没有看到您正在寻找的示例,我可能会放弃这个问题,因为我不想猜测。
您的声誉不仅仅是您的声誉。
我喜欢积分(我上面提到过)。但这些积分实际上并不是我的声誉。我真正的声誉是网站上其他人对我的看法的综合。我努力做到公平诚实,希望其他人能看到这一点。对于提问者来说,这意味着我们会记住提问者的行为。如果你不选择答案并给好的答案点赞,我会记住。如果你的行为方式我不喜欢或我喜欢,我都会记住。这也会影响到我会回答哪些问题。
无论如何,我可能还可以继续,但我不会打扰所有真正读过这篇文章的人。
解决方案 4:
挑战回答 SO 问题最具挑战性的方面之一是重现问题(包括数据)所需的时间。没有明确方法重现数据的问题不太可能得到回答。考虑到您花时间写下问题,并且您有一个需要帮助的问题,您可以通过提供数据轻松帮助自己,然后其他人可以使用这些数据来帮助解决您的问题。
@Andy 提供的关于如何编写好的 Pandas 问题的说明是一个很好的起点。有关更多信息,请参阅如何提问以及如何创建最小、完整和可验证的示例。
请提前明确说明您的问题。 花时间写下您的问题和任何示例代码后,请尝试阅读它并为读者提供“执行摘要”,其中总结了问题并清楚地说明了问题。
原始问题:
我有这些数据...
我想这样做...
我希望我的结果看起来像这样......
但是,当我尝试这样做时,出现了以下问题...
我尝试通过做[这个]和[那个]来寻找解决方案。
我该如何修复它?
根据提供的数据量、示例代码和错误堆栈,读者需要进行大量阅读才能理解问题所在。尝试重新陈述您的问题,使问题本身处于首位,然后提供必要的详细信息。
修改后的问题:
问: 我该怎么做?
我尝试通过做[这个]和[那个]来寻找解决方案。
当我尝试这样做时,遇到了以下问题......
我希望我的最终结果看起来像这样......
以下是一些可以重现我的问题的最小代码......
以下是重新创建示例数据的方法:
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)
注意:如果你的 DataFrame 有 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:
这是我为 Pandas 编写的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))
对比
{'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.dtypes
是uint8
且pd.DataFrame(du.to_dict()).dtypes
是int64
。
- 2024年20款好用的项目管理软件推荐,项目管理提效的20个工具和技巧
- 2024年开源项目管理软件有哪些?推荐5款好用的项目管理工具
- 项目管理软件有哪些?推荐7款超好用的项目管理工具
- 项目管理软件哪个最好用?盘点推荐5款好用的项目管理工具
- 项目管理软件有哪些最好用?推荐6款好用的项目管理工具
- 项目管理软件有哪些,盘点推荐国内外超好用的7款项目管理工具
- 2024项目管理软件排行榜(10类常用的项目管理工具全推荐)
- 项目管理软件排行榜:2024年项目经理必备5款开源项目管理软件汇总
- 2024年常用的项目管理软件有哪些?推荐这10款国内外好用的项目管理工具
- 项目管理必备:盘点2024年13款好用的项目管理软件