Python:合并列表或数据框并覆盖缺失值

3
假设我有以下列表:
list1 = ['MI', '', 'NY', '', 'AR', '']
list2 = ['', 'MS', '', 'OH', '', '']

如果在list1中存在缺失值或空字符串,我希望将空字符串覆盖为list2中相应的值。有没有一种高效的方法可以做到这一点而不必遍历list1中的每个项目?以下是我目前的解决方案:

list1 = ['MI', '', 'NY', '', 'AR', '']
list2 = ['', 'MS', '', 'OH', '', '']

counter = 0

for each in list1:
    counter = counter + 1
    if len(each) == 0:
        list1[counter-1] = list2[counter-1]
print(list1)
>>> ['MI', 'MS', 'NY', 'OH', 'AR', '']

我试图将我的列表转换为Pandas数据框并使用 pandas.DataFrame.update(),但没有得到我想要的结果。类似的问题在这里被解决(但是使用R语言):https://dev59.com/8XDYa4cB1Zd3GeqPBYvG


1
不,你必须要进行迭代。你可以使用复杂的列表推导式等来隐藏迭代过程,但是在幕后一定会有东西对这些列表进行迭代。 - user2782067
3个回答

3

有一种更符合Python风格的方法(使用列表推导),但最终仍需要迭代:

[x or y for x, y in zip(list1, list2)]

由于这个循环同时迭代两个列表,所以也许比最初的解决方案效率低,后者完全迭代list1,但只访问list2的特定索引。你有什么想法? - sedeh

1

您可以使用 pandas pandas.Series.where() 方法,但我认为仍然需要迭代:

>>> s1 = pd.Series(list1)
>>> s2 = pd.Series(list2)
>>> s1.where(s1 != '', s2)
0    MI
1    MS
2    NY
3    OH
4    AR
5      

关于你原来的方法,你不需要拥有自己的计数器,顺便说一下,你可以使用enumerate()方法:

>>> def isnull1(list1, list2):
...     res = []
...     for i, x in enumerate(list1):
...         if not x:
...             res.append(list2[i])
...         else:
...             res.append(x)
...     return res
... 
>>> isnull1(list1, list2)
['MI', 'MS', 'NY', 'OH', 'AR', '']

但更好的解决方案是使用 zip()map()

>>> map(lambda x: x[1] if not x[0] else x[0], zip(list1, list2))
['MI', 'MS', 'NY', 'OH', 'AR', '']

如果您不需要立即使用列表,使用 generators 更好:

>>> def isnull2(list1, list2):
...     for i, x in enumerate(list1):
...         if not x:
...             yield list2[i]
...         else:
...             yield x
... 
>>> list(isnull2(list1, list2))
['MI', 'MS', 'NY', 'OH', 'AR', '']

或者,使用imap()izip()来自itertools

>>> from itertools import izip, imap
>>> list(imap(lambda x: x[1] if not x[0] else x[0], izip(list1, list2)))
['MI', 'MS', 'NY', 'OH', 'AR', '']

不错!这个代码完全遍历了 s1 和 s2 吗?如果是的话,它可能是 O(n2),而问题中的解决方案似乎是 O(n)。还有其他想法吗? - sedeh
如果对于s1的每个元素都迭代s2,那么它将是O(n2)。两种解决方案都是O(n),您可以测试一下哪个更快。Pandas可能会更快,因为它可以更快地访问Series的元素(其底层是numpy数组)。 - Roman Pekar

0

可能这可以帮到你:

def list_default(l1, l2):
    i1 = iter(l1)
    i2 = iter(l2)
    for i in i1:
        next_default = i2.next()
        if not i:
            yield next_default
        else:
            yield i

list1 = ['MI', '', 'NY', '', 'AR', '']
list2 = ['', 'MS', '', 'OH', '', '']

print(list(list_default(list1, list2)))
>>> ['MI', 'MS', 'NY', 'OH', 'AR', '']

你必须迭代序列以找到缺失值,使用上一个函数可以避免跟踪列表的索引。

对不起我的英语。


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