将Pandas系列列表转换为一个系列

47

我有一个由字符串列表组成的Pandas Series:

0                           [slim, waist, man]
1                                [slim, waistline]
2                                     [santa]

正如您所看到的,这些列表的长度是不同的。我想要一种高效地将它们合并成一个序列的方法。

0 slim
1 waist
2 man
3 slim
4 waistline
5 santa

我知道可以使用

li

标签来分隔列表。

series_name.split(' ')

但我很难将这些字符串放回一个列表中。

谢谢!


可能是一个重复的问题,可以参考如何提取嵌套列表? - tegancp
对于那些想要做类似的事情但保留其他列不变的人,类似于数据透视表,您可能想查看此问题和答案 - MattR
10个回答

52

这是一个只使用pandas函数的简单方法:

import pandas as pd

s = pd.Series([
    ['slim', 'waist', 'man'],
    ['slim', 'waistline'],
    ['santa']])

然后

s.apply(pd.Series).stack().reset_index(drop=True)

产生所需的输出结果。在某些情况下,您可能希望保存原始索引并添加第二级来索引嵌套元素,例如:

0  0         slim
   1        waist
   2          man
1  0         slim
   1    waistline
2  0        santa

如果这正是您所需的,请从链条中省略.reset_index(drop=True)


1
请注意,s.apply(pd.Series) 创建的是一个数据框,其宽度为原始序列中最长的列表。因此,如果您有一个包含10个列表的序列,并且其中一个列表有500个条目,它将生成一个具有10行、500列和潜在大量NAs的数据框! - machow
1
请注意,如果输入为空,则apply将返回一个Series,并且Series对象没有stack方法... - Joseph Young
2
在我的情况下速度非常慢。 - keramat

51
在 pandas 版本 0.25.0 中,出现了一个新的方法“explode”,适用于 seriesdataframes。旧版本中没有此方法。
它有助于构建所需的结果。
例如,您有这样的 series:
import pandas as pd

s = pd.Series([
    ['slim', 'waist', 'man'],
    ['slim', 'waistline'],
    ['santa']])

然后您可以使用

s.explode()

为了获得这样的结果:

0         slim
0        waist
0          man
1         slim
1    waistline
2        santa

在数据框中:

df = pd.DataFrame({
  's': pd.Series([
    ['slim', 'waist', 'man'],
    ['slim', 'waistline'],
    ['santa']
   ]),
   'a': 1
})

你将拥有这样的数据框:

                    s  a
0  [slim, waist, man]  1
1   [slim, waistline]  1
2             [santa]  1

s 列上应用 explode 函数:

df.explode('s')

会给您带来这样的结果:

           s  a
0       slim  1
0      waist  1
0        man  1
1       slim  1
1  waistline  1
2      santa  1

如果你的系列中包含空列表

import pandas as pd

s = pd.Series([
    ['slim', 'waist', 'man'],
    ['slim', 'waistline'],
    ['santa'],
    []
])

然后运行explode将为空列表引入NaN值,如下所示:

0         slim
0        waist
0          man
1         slim
1    waistline
2        santa
3          NaN
如果不需要这个,请使用dropna方法来调用:
s.explode().dropna()

要得到这个结果:

0         slim
0        waist
0          man
1         slim
1    waistline
2        santa

Dataframes也有dropna方法:

df = pd.DataFrame({
  's': pd.Series([
    ['slim', 'waist', 'man'],
    ['slim', 'waistline'],
    ['santa'],
    []
   ]),
   'a': 1
})

使用 explode 而不带有 dropna 参数:

df.explode('s')

会导致:

           s  a
0       slim  1
0      waist  1
0        man  1
1       slim  1
1  waistline  1
2      santa  1
3        NaN  1

使用 dropna:

df.explode('s').dropna(subset=['s'])

结果:

           s  a
0       slim  1
0      waist  1
0        man  1
1       slim  1
1  waistline  1
2      santa  1

22

您基本上只是在尝试展开一个嵌套的列表。

您只需要遍历系列的元素即可:

slist =[]
for x in series:
    slist.extend(x)

或者使用更简洁但难以理解的列表推导式:

slist = [st for row in s for st in row]

18
series_name.sum()

它完全可以满足你的需求。但请确保它是一系列列表,否则你的值会被连接起来(如果是字符串)或相加(如果是整数)。


7
你可以尝试使用itertools.chain来简单地展开列表:

(你可以尝试使用itertools.chain来简单地展开列表)

In [70]: from itertools import chain
In [71]: import pandas as pnd
In [72]: s = pnd.Series([['slim', 'waist', 'man'], ['slim', 'waistline'], ['santa']])
In [73]: s
Out[73]: 
0    [slim, waist, man]
1     [slim, waistline]
2               [santa]
dtype: object
In [74]: new_s = pnd.Series(list(chain(*s.values)))
In [75]: new_s
Out[75]: 
0         slim
1        waist
2          man
3         slim
4    waistline
5        santa
dtype: object

1
如果您的pandas版本太旧而无法使用series_name.explode(),则可以尝试以下方法:
from itertools import chain

pd.Series(
    chain.from_iterable(
        value
        for i, value
        in series_name.iteritems()
    )
)

0

被接受的答案(由 @mcwitt)看起来很像 pandas,但是非常慢,如果列表大小有离群值并且有缺陷(请参见该答案的注释),则需要占用大量内存。

+1 对于 @Tadej Magajna 的答案,将 sum() 应用于系列。 由于它正在将列表相加,因此在情况下使用numpy的 flatten() 是一种更有效的方法,即系列元素为 nparrays:

series_name.values.flatten()


0
您可以使用以下方式的列表连接运算符 -
lst1 = ['hello','world']
lst2 = ['bye','world']
newlst = lst1 + lst2
print(newlst)
>> ['hello','world','bye','world']

或者你可以像下面这样使用list.extend()函数 -

lst1 = ['hello','world']
lst2 = ['bye','world']
lst1.extend(lst2)
print(lst1)
>> ['hello', 'world', 'bye', 'world']

使用extend函数的好处在于它可以适用于多种类型,而concatenation运算符只有在LHS和RHS都是列表时才能工作。

extend函数的其他示例 -

lst1.extend(('Bye','Bye'))
>> ['hello', 'world', 'Bye', 'Bye']

0

使用此函数可以进行平铺和取消平铺

def flatten(df, col):
    col_flat = pd.DataFrame([[i, x] for i, y in df[col].apply(list).iteritems() for x in y], columns=['I', col])
    col_flat = col_flat.set_index('I')
    df = df.drop(col, 1)
    df = df.merge(col_flat, left_index=True, right_index=True)

    return df

非扁平化:

def unflatten(flat_df, col):
    flat_df.groupby(level=0).agg({**{c:'first' for c in flat_df.columns}, col: list})

展开后,我们得到相同的数据框,除了列的顺序不同:

(df.sort_index(axis=1) == unflatten(flatten(df)).sort_index(axis=1)).all().all()
>> True

0

您也可以尝试以下方法:

combined = []
for i in s.index:
    combined = combined + s.iloc[i]

print(combined)

s = pd.Series(combined)
print(s)

输出:

['slim', 'waist', 'man', 'slim', 'waistline', 'santa']

0         slim
1        waist
2          man
3         slim
4    waistline
5        santa

dtype: object

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接