如何合并Series和DataFrame


82

如果您是来这里寻找有关如何合并aDataFrameSeries索引的信息,请查看此答案

OP的最初意图是询问如何将系列元素作为列分配给另一个DataFrame。如果您想知道答案,请查看EdChum接受的答案


我能想到的最好的是

df = pd.DataFrame({'a':[1, 2], 'b':[3, 4]})  # see EDIT below
s = pd.Series({'s1':5, 's2':6})

for name in s.index:
    df[name] = s[name]

   a  b  s1  s2
0  1  3   5   6
1  2  4   5   6

有人可以建议更好的语法/更快的方法吗?

我的尝试:

df.merge(s)
AttributeError: 'Series' object has no attribute 'columns'

df.join(s)
ValueError: Other Series must have a name

编辑发布的前两个答案突出了我的问题,所以请使用以下内容来构造df

df = pd.DataFrame({'a':[np.nan, 2, 3], 'b':[4, 5, 6]}, index=[3, 5, 6])

最终结果

    a  b  s1  s2
3 NaN  4   5   6
5   2  5   5   6
6   3  6   5   6

Answers:


25

您可以从系列中构造一个数据框,然后与该数据框合并。因此,您将数据指定为值,然后将它们乘以长度,将列设置为索引,并将left_index和right_index的参数设置为True:

In [27]:

df.merge(pd.DataFrame(data = [s.values] * len(s), columns = s.index), left_index=True, right_index=True)
Out[27]:
   a  b  s1  s2
0  1  3   5   6
1  2  4   5   6

编辑以下情况:要从系列中构造的df的索引使用df的索引,则可以执行以下操作:

df.merge(pd.DataFrame(data = [s.values] * len(df), columns = s.index, index=df.index), left_index=True, right_index=True)

这假定索引与长度匹配。


163

更新
从v0.24.0开始,你可以只要系列被命名为对数据帧和系列合并。

df.merge(s.rename('new'), left_index=True, right_index=True)
# If series is already named,
# df.merge(s, left_index=True, right_index=True)

如今,您可以使用to_frame()将Series转换为DataFrame 。因此(如果加入索引):

df.merge(s.to_frame(), left_index=True, right_index=True)

5
使用问题的定义dfs,这个答案返回给我一个空的数据帧,没有结果要求的问题。我们不想匹配索引;我们想将s值广播到的所有行df
CPBL

2
这正在解决一个不同的问题:“给定一个DataFrame和Series,如何将它们合并到索引上”。OP的问题是“将Series的每个元素分配为DataFrame中的新列”。
cs95

5

这是一种方法:

df.join(pd.DataFrame(s).T).fillna(method='ffill')

要分解这里发生的事情...

pd.DataFrame(s).T创建一个单行DataFrame s,看起来像这样:

   s1  s2
0   5   6

接下来,join将此新框架与串联df

   a  b  s1  s2
0  1  3   5   6
1  2  4 NaN NaN

最后,NaN使用fillnaforward-fill(ffill)参数将索引1中的值填充为该列中的先前值:

   a  b  s1  s2
0  1  3   5   6
1  2  4   5   6

为了避免使用fillna,可以pd.concat重复使用从构造的DataFrame的行s。在这种情况下,一般的解决方案是:

df.join(pd.concat([pd.DataFrame(s).T] * len(df), ignore_index=True))

这是解决已编辑问题中提出的索引挑战的另一种解决方案:

df.join(pd.DataFrame(s.repeat(len(df)).values.reshape((len(df), -1), order='F'), 
        columns=s.index, 
        index=df.index))

s通过重复这些值并重塑(指定“ Fortran”顺序),并传入适当的列名和索引,将其转换为DataFrame。然后将此新的DataFrame加入df


不错的一句,警告是,已经存在于df中的所有NaN也会被填充。
内森·劳埃德

@Nonth谢谢,很好。我进行了编辑,以包括避免填写NaN值的替代方法。
Alex Riley 2014年

EdChums原始答案发生了什么,影响了此修订的答案。如果我用构造df index=[3, 5],则新列将在命令后包含nan。
内森·劳埃德

@Nonth再次编辑!现在,它应该满足您的新要求。
Alex Riley 2014年

您的答案快了20倍,但与1e5行df的结果仍然相差约100毫秒。我的for循环太慢了。顺便说一句,在您的回答中2应该len(df)是普遍适用的。
内森·劳埃德

0

如果我建议像这样设置您的数据框(自动索引):

df = pd.DataFrame({'a':[np.nan, 1, 2], 'b':[4, 5, 6]})

那么您可以设置s1和s2值(使用shape()从df返回行数):

s = pd.DataFrame({'s1':[5]*df.shape[0], 's2':[6]*df.shape[0]})

那么您想要的结果很简单:

display (df.merge(s, left_index=True, right_index=True))

或者,只需将新值添加到数据框df中:

df = pd.DataFrame({'a':[nan, 1, 2], 'b':[4, 5, 6]})
df['s1']=5
df['s2']=6
display(df)

两者都返回:

     a  b  s1  s2
0  NaN  4   5   6
1  1.0  5   5   6
2  2.0  6   5   6

如果您还有另一个数据列表(而不是仅应用一个值),并且知道它与df的顺序相同,例如:

s1=['a','b','c']

那么您可以通过以下相同方式附加它:

df['s1']=s1

返回:

     a  b s1
0  NaN  4  a
1  1.0  5  b
2  2.0  6  c

0

您可以轻松地将pandas.DataFrame列设置为常量。这个常量可以是int,例如您的示例。如果您指定的列不在df中,则pandas将使用您指定的名称创建一个新列。因此,在构造完数据框之后,(根据您的问题):

df = pd.DataFrame({'a':[np.nan, 2, 3], 'b':[4, 5, 6]}, index=[3, 5, 6])

您可以运行:

df['s1'], df['s2'] = 5, 6

您可以编写一个循环或理解来使它对元组列表中的所有元素,字典中的键和值执行此操作,具体取决于您存储真实数据的方式。


0

如果df为,pandas.DataFrame则将df['new_col']= Series list_object of length len(df)或系列list_object添加为名为的列'new_col'df['new_col']= scalar(例如您的情况下为5或6)也可以使用,并且等效于df['new_col']= [scalar]*len(df)

因此,两行代码可以达到目的:

df = pd.DataFrame({'a':[1, 2], 'b':[3, 4]})
s = pd.Series({'s1':5, 's2':6})
for x in s.index:    
    df[x] = s[x]

Output: 
   a  b  s1  s2
0  1  3   5   6
1  2  4   5   6
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.