有没有办法只复制Pandas DataFrame的结构(而不​​是数据)?

bme*_*llo 50 python dataframe pandas

我从某个地方收到了一个DataFrame,并希望创建另一个具有相同数量和列和行(索引)名称的DataFrame.例如,假设原始数据框被创建为

import pandas as pd
df1 = pd.DataFrame([[11,12],[21,22]], columns=['c1','c2'], index=['i1','i2'])
Run Code Online (Sandbox Code Playgroud)

我通过显式定义列和名称来复制结构:

df2 = pd.DataFrame(columns=df1.columns, index=df1.index)    
Run Code Online (Sandbox Code Playgroud)

我不想复制数据,否则我就可以写了df2 = df1.copy().换句话说,在创建df2之后,它必须只包含NaN元素:

In [1]: df1
Out[1]: 
    c1  c2
i1  11  12
i2  21  22

In [2]: df2
Out[2]: 
     c1   c2
i1  NaN  NaN
i2  NaN  NaN
Run Code Online (Sandbox Code Playgroud)

有没有更惯用的方式呢?

ayh*_*han 36

这是一份工作reindex_like.从原始开始:

df1 = pd.DataFrame([[11, 12], [21, 22]], columns=['c1', 'c2'], index=['i1', 'i2'])
Run Code Online (Sandbox Code Playgroud)

构造一个空的DataFrame并像df1一样重新索引它:

pd.DataFrame().reindex_like(df1)
Out: 
    c1  c2
i1 NaN NaN
i2 NaN NaN   
Run Code Online (Sandbox Code Playgroud)

  • 从未见过“ reindex_like”,很高兴看到新事物 (2认同)
  • 谢谢,这是一个很好的解决方案。它不仅保留了列名和行名,还保留了列的类型,而无需显式复制这些属性。另外,我认为它非常有效,因为它从一个空的 DataFrame 开始,然后是一个调整大小的操作。 (2认同)
  • 这比显式解决方案快得多。在我的情况下是 20 倍。 (2认同)

fir*_*ynx 29

0.18版本的pandas中,DataFrame构造函数没有选项来创建数据,就像使用NaN而不是值来创建另一个数据一样.

您使用的代码df2 = pd.DataFrame(columns=df1.columns, index=df1.index)是最合乎逻辑的方式,改进它的唯一方法是拼出更多您要做的是添加data=None,以便其他编码人员直接看到您故意从这个新的DataFrame中省略数据创建.

TLDR:所以我的建议是:

显式优于隐式

df2 = pd.DataFrame(data=None, columns=df1.columns, index=df1.index)
Run Code Online (Sandbox Code Playgroud)

非常像你的,但更详细说明.

  • 这不会保留列类型。有什么建议? (2认同)

小智 11

不完全回答这个问题,但对于通过搜索引擎来到这里的人来说是一个类似的问题

我的情况是创建一个没有 data 和 index数据框的副本。可以通过执行以下操作来实现这一点。这将保持列的 dtypes。

empty_copy = df.drop(df.index)
Run Code Online (Sandbox Code Playgroud)

  • 主要结合现有评论的点点滴滴(为了“类似的情况”):`empty_copy = df.head(0).copy()`或(来自下面的另一个答案,但多了2个字符......):` empty_copy = df.iloc[0:0].copy()`。这是更有效的(不会从一个大集合到达一个空集合)并且将副本与原始对象分离。似乎这就是“dtypes”可以保留的程度,“.reindex()”否则就会忘记它们。(尽管正如许多人指出的那样,“dtype”并不那么强大,因此不如人们最初想象或希望的那么有价值。) (2认同)

Ped*_*rte 10

让我们从一些示例数据开始

In [1]: import pandas as pd

In [2]: df = pd.DataFrame([[1, 'a'], [2, 'b'], [3, 'c']],
   ...:                   columns=['num', 'char'])

In [3]: df
Out[3]: 
   num char
0    1    a
1    2    b
2    3    c

In [4]: df.dtypes
Out[4]: 
num      int64
char    object
dtype: object
Run Code Online (Sandbox Code Playgroud)

现在让我们使用DataFrame原始列的简单初始化,DataFrame但不提供数据:

In [5]: empty_copy_1 = pd.DataFrame(data=None, columns=df.columns)

In [6]: empty_copy_1
Out[6]: 
Empty DataFrame
Columns: [num, char]
Index: []

In [7]: empty_copy_1.dtypes
Out[7]: 
num     object
char    object
dtype: object
Run Code Online (Sandbox Code Playgroud)

如您所见,列数据类型与原始数据类型不同DataFrame.

所以,如果你想保留列dtype......

如果你想保留列的数据类型,你需要构造DataFrame一个Series在同一时间

In [8]: empty_copy_2 = pd.DataFrame.from_items([
   ...:     (name, pd.Series(data=None, dtype=series.dtype))
   ...:     for name, series in df.iteritems()])

In [9]: empty_copy_2
Out[9]: 
Empty DataFrame
Columns: [num, char]
Index: []

In [10]: empty_copy_2.dtypes
Out[10]: 
num      int64
char    object
dtype: object
Run Code Online (Sandbox Code Playgroud)

  • 应当指出,在一个数据框设置为D型的空栏不以任何方式更改数据帧的行为. (2认同)

dav*_*arc 7

一个简单的替代方法 - 首先将基本结构或索引和列与原始数据帧(df1)中的数据类型复制到df2

df2 = df1.iloc[0:0]
Run Code Online (Sandbox Code Playgroud)

然后用空行填充数据帧 - 需要调整伪代码以更好地匹配您的实际结构:

s = pd.Series([Nan,Nan,Nan], index=['Col1', 'Col2', 'Col3'])
Run Code Online (Sandbox Code Playgroud)

循环遍历df1中的行

df2 = df2.append(s)
Run Code Online (Sandbox Code Playgroud)

  • 将 `df1.iloc[0:0]` 更改为 `df1.iloc[0:0].copy()`,因为如果不这样做,您仍在使用对 `df1` 的引用。这可以防止在执行“df2.rename(columns={"c1": "z1"}, inplace=True)”之类的操作时出现警告“SettingWithCopyWarning: A value is attempts to be set on a copy of a slice from a DataFrame” 。 (3认同)