为什么 reticulate 会将 pandas dfs 列表转换为 r dfs 列表,但如果使用字典或嵌套列表则不会?
Why will reticulate convert a list of pandas dfs to a list of r dfs but not if using a dictionary or nested lists?
这是我第一次使用 reticulate
。我有 20 个多页 pdf tables 我正在从 python 中使用 camelot
提取数据(它们并不简单 tables 所以我需要更强大的 table reader).它创建一个 table 列表(每个页面一个 table)并创建一个 TableList
对象。我能够遍历列表并将 table 转换为 pandas 数据帧。使用其中一个 pdf 执行此操作的示例:
tables2001 = camelot.read_pdf('2001.pdf', flavor='stream', pages='1-end')
df2001 = list()
for t in tables2001:
df = t.df
df2001.append(df)
然后我可以 return 到 r,rdf2001 <- py$df2001
给我一个 r 的列表 data.frames。
但是,如果我改为将 python 数据帧列表放入嵌套列表或包含列表的字典中,则 r 转换将不再有效,并且生成的嵌套列表仍包含 pandas data.frames。可以理解地手动转换其中一个 dfs 的尝试给出了这个:
Error in as.data.frame.default(rdf2001_nested[[1]]) :
cannot coerce class ‘c("pandas.core.frame.DataFrame", "pandas.core.generic.NDFrame", ’ to a data.frame
如果我从嵌套列表中将单个列表拉入 r,例如df2001_a <- py$df2001[1]
,转换为 r data.frames 的单个列表。我不能对字典做同样的事情,因为转换将键保留为列表,所以嵌套仍然存在。
使用字典的想法是在 r 中获取一个每年标识的命名列表,因为 tables 本身不包含该信息。我可以解决它,但是命名列表的字典对我来说是最清晰的方法,假设它可以工作。尝试嵌套列表是为了弄清楚转换问题是否只发生在字典中,而事实并非如此;它与任何类型的嵌套。
我想了解为什么会这样。 reticulate
只能转换单层列表吗?这是否有潜在的原因,或者只是没有添加该功能但理论上可以?
更新完整代码:
Pdf table 是 here。我提取了每年涉及刑事案件的页面,这就是页面被列为 1-end 的原因;每本有 14 页。 Python 代码 运行 和 repl_python()
- 工作并给出我想要的列表和字典的结果:
import camelot
import pandas
# Lists
tables2001 = camelot.read_pdf('2001.pdf', flavor='stream', pages='1-end')
tables2002 = camelot.read_pdf('2002.pdf', flavor='stream', pages='1-end')
tables2003 = camelot.read_pdf('2003.pdf', flavor='stream', pages='1-end')
dflist = list()
tablelist=[tables2001,tables2002,tables2003,tables2004]
for t in tablelist:
df = t.df
dflist.append(df)
# Dictionary - I got help with this from someone who is knows python well
tables = { f'20{str(n).zfill(2)}': camelot.read_pdf(f'20{str(n).zfill(2)}.pdf',
flavor='stream', pages='1-end', table_regions=['50,580,780,50']) for n in range(1,3)}
dfdict = { k: [df.df for df in v] for k, v in tables.items() }
R代码:
library(reticulate)
# List
rdflist <- py$dflist
# Dictionary
rdfdict <- py$dfdict
rdflist
是 data.frames 的列表。 rdfdict
是一个命名的嵌套列表,包含 3 个列表(2001、2002、2003),每个列表有 14 个 pandas 数据帧,即在 r.
中不可用
class(rdflist[[1]])
[1] "data.frame"
class(rdfdict[[1]][[1]])
[1] "pandas.core.frame.DataFrame" "pandas.core.generic.NDFrame"
[3] "pandas.core.base.PandasObject" "pandas.core.base.StringMixin"
[5] "pandas.core.accessor.DirNamesMixin" "pandas.core.base.SelectionMixin"
[7] "python.builtin.object"
尝试将单个 df 强制为 data.frame:
as.data.frame(rdfdict[[1]][[1]])
Error in as.data.frame.default(rdfdict[[1]][[1]]) :
cannot coerce class ‘c("pandas.core.frame.DataFrame", "pandas.core.generic.NDFrame", ’ to a data.frame
比较两个版本,您 运行 字典版本的一些差异包括一个额外的参数,table_regions
和字典理解中的额外嵌套循环:[df.df for df in v]
(有趣的是没有在 Python).
中引发错误
考虑调整可比返回值的一致性。顺便说一句,在 Python 中,您还可以 运行 类似于字典理解的列表理解。
Python
import camelot
import pandas as pd
# LIST COMPREHENSION
pydf_list = [
[tbl.df for tbl in camelot.read_pdf(f'{yr}.pdf', flavor='stream', pages='1-end')]
for yr in range(2001, 2004)
]
# DICT COMPREHENSION
pydf_dict = {
str(yr): [tbl.df for tbl in camelot.read_pdf(f'{yr}.pdf', flavor='stream', pages='1-end')]
for yr in range(2001, 2004)
}
R
library(reticulate)
reticulate::source_python("myscript.py")
# NESTED LIST
rdf_list <- reticulate::py$pydf_list
# NESTED NAMED LIST
rdf_dict <- reticulate::py$pydf_dict
但是,正如您所指出的,我确实使用可重现的示例重现了有问题的 dict 到命名列表的转换。报告此问题,一位 suggestion 的维护者将使用 py_to_r
:
rdf_dict2 <- lapply(rdf_dict, function(lst) lapply(lst, py_to_r))
这是我第一次使用 reticulate
。我有 20 个多页 pdf tables 我正在从 python 中使用 camelot
提取数据(它们并不简单 tables 所以我需要更强大的 table reader).它创建一个 table 列表(每个页面一个 table)并创建一个 TableList
对象。我能够遍历列表并将 table 转换为 pandas 数据帧。使用其中一个 pdf 执行此操作的示例:
tables2001 = camelot.read_pdf('2001.pdf', flavor='stream', pages='1-end')
df2001 = list()
for t in tables2001:
df = t.df
df2001.append(df)
然后我可以 return 到 r,rdf2001 <- py$df2001
给我一个 r 的列表 data.frames。
但是,如果我改为将 python 数据帧列表放入嵌套列表或包含列表的字典中,则 r 转换将不再有效,并且生成的嵌套列表仍包含 pandas data.frames。可以理解地手动转换其中一个 dfs 的尝试给出了这个:
Error in as.data.frame.default(rdf2001_nested[[1]]) :
cannot coerce class ‘c("pandas.core.frame.DataFrame", "pandas.core.generic.NDFrame", ’ to a data.frame
如果我从嵌套列表中将单个列表拉入 r,例如df2001_a <- py$df2001[1]
,转换为 r data.frames 的单个列表。我不能对字典做同样的事情,因为转换将键保留为列表,所以嵌套仍然存在。
使用字典的想法是在 r 中获取一个每年标识的命名列表,因为 tables 本身不包含该信息。我可以解决它,但是命名列表的字典对我来说是最清晰的方法,假设它可以工作。尝试嵌套列表是为了弄清楚转换问题是否只发生在字典中,而事实并非如此;它与任何类型的嵌套。
我想了解为什么会这样。 reticulate
只能转换单层列表吗?这是否有潜在的原因,或者只是没有添加该功能但理论上可以?
更新完整代码:
Pdf table 是 here。我提取了每年涉及刑事案件的页面,这就是页面被列为 1-end 的原因;每本有 14 页。 Python 代码 运行 和 repl_python()
- 工作并给出我想要的列表和字典的结果:
import camelot
import pandas
# Lists
tables2001 = camelot.read_pdf('2001.pdf', flavor='stream', pages='1-end')
tables2002 = camelot.read_pdf('2002.pdf', flavor='stream', pages='1-end')
tables2003 = camelot.read_pdf('2003.pdf', flavor='stream', pages='1-end')
dflist = list()
tablelist=[tables2001,tables2002,tables2003,tables2004]
for t in tablelist:
df = t.df
dflist.append(df)
# Dictionary - I got help with this from someone who is knows python well
tables = { f'20{str(n).zfill(2)}': camelot.read_pdf(f'20{str(n).zfill(2)}.pdf',
flavor='stream', pages='1-end', table_regions=['50,580,780,50']) for n in range(1,3)}
dfdict = { k: [df.df for df in v] for k, v in tables.items() }
R代码:
library(reticulate)
# List
rdflist <- py$dflist
# Dictionary
rdfdict <- py$dfdict
rdflist
是 data.frames 的列表。 rdfdict
是一个命名的嵌套列表,包含 3 个列表(2001、2002、2003),每个列表有 14 个 pandas 数据帧,即在 r.
class(rdflist[[1]])
[1] "data.frame"
class(rdfdict[[1]][[1]])
[1] "pandas.core.frame.DataFrame" "pandas.core.generic.NDFrame"
[3] "pandas.core.base.PandasObject" "pandas.core.base.StringMixin"
[5] "pandas.core.accessor.DirNamesMixin" "pandas.core.base.SelectionMixin"
[7] "python.builtin.object"
尝试将单个 df 强制为 data.frame:
as.data.frame(rdfdict[[1]][[1]])
Error in as.data.frame.default(rdfdict[[1]][[1]]) :
cannot coerce class ‘c("pandas.core.frame.DataFrame", "pandas.core.generic.NDFrame", ’ to a data.frame
比较两个版本,您 运行 字典版本的一些差异包括一个额外的参数,table_regions
和字典理解中的额外嵌套循环:[df.df for df in v]
(有趣的是没有在 Python).
考虑调整可比返回值的一致性。顺便说一句,在 Python 中,您还可以 运行 类似于字典理解的列表理解。
Python
import camelot
import pandas as pd
# LIST COMPREHENSION
pydf_list = [
[tbl.df for tbl in camelot.read_pdf(f'{yr}.pdf', flavor='stream', pages='1-end')]
for yr in range(2001, 2004)
]
# DICT COMPREHENSION
pydf_dict = {
str(yr): [tbl.df for tbl in camelot.read_pdf(f'{yr}.pdf', flavor='stream', pages='1-end')]
for yr in range(2001, 2004)
}
R
library(reticulate)
reticulate::source_python("myscript.py")
# NESTED LIST
rdf_list <- reticulate::py$pydf_list
# NESTED NAMED LIST
rdf_dict <- reticulate::py$pydf_dict
但是,正如您所指出的,我确实使用可重现的示例重现了有问题的 dict 到命名列表的转换。报告此问题,一位 suggestion 的维护者将使用 py_to_r
:
rdf_dict2 <- lapply(rdf_dict, function(lst) lapply(lst, py_to_r))