我可以用另一列的特定列表元素填充一列的nan值吗?

w41d8nur  于 2021-07-13  发布在  Java
关注(0)|答案(3)|浏览(349)

例如,我有以下Dataframe(称为items):

| index | itemID | maintopic | subtopics          |
|:----- |:------:|:---------:| ------------------:|
| 1     | 235    | FBR       | [FZ, 1RH, FL]      |
| 2     | 1787   | NaN       | [1RH, YRS, FZ, FL] |
| 3     | 2454   | NaN       | [FZX, 1RH, FZL]    |
| 4     | 3165   | NaN       | [YHS]              |

我想用以字母开头的子主题列表的第一个元素来填充maintopic列中的nan值。有人有主意吗(问题1)
我试过了,但没成功´t工作:

import pandas as pd
import string
alphabet = list(string.ascii_lowercase)

items['maintopic'] = items['maintopic'].apply(lambda x : items['maintopic'].fillna(items['subtopics'][x][0]) if items['subtopics'][x][0].lower().startswith(tuple(alphabet)) else x)

高级(问题2):更好的办法是看一下副标题列表中的所有元素,如果有更多的元素有第一个字母,甚至是第一个和第二个字母的共同点,那么我就看这个。例如,在第2行中有fz和fl,所以我想用f填充此行的主主题。第三行有fzx和fzl,我想用fz来填充主主题。但如果这太复杂了,那么我也很乐意回答第一个问题。
谢谢你的帮助!

6jygbczu

6jygbczu1#

尝试:

from itertools import chain, combinations

def commonprefix(m):
    "Given a list of pathnames, returns the longest common leading component"
    if not m:
        return ""
    s1 = min(m)
    s2 = max(m)
    for i, c in enumerate(s1):
        if c != s2[i]:
            return s1[:i]
    return s1

def powerset(iterable):
    "powerset([1,2,3]) --> () (1,) (2,) (3,) (1,2) (1,3) (2,3) (1,2,3)"
    s = list(iterable)
    return chain.from_iterable(combinations(s, r) for r in range(len(s) + 1))

def choose(x):
    filtered = [v for v in x if not v[0].isdigit()]
    if not filtered:
        return np.nan

    longest = ""
    for s in powerset(filtered):
        if len(s) < 2:
            continue
        pref = commonprefix(s)
        if len(pref) > len(longest):
            longest = pref

    return filtered[0] if longest == "" else longest

m = df["maintopic"].isna()
df.loc[m, "maintopic"] = df.loc[m, "subtopics"].apply(choose)
print(df)

印刷品:

index  itemID maintopic           subtopics
0      1     235       FBR       [FZ, 1RH, FL]
1      2    1787         F  [1RH, YRS, FZ, FL]
2      3    2454        FZ     [FZX, 1RH, FZL]
3      4    3165       YHS               [YHS]
epggiuax

epggiuax2#

试着回答第一个问题:

import pandas as pd
import numpy as np

def fill_value(sub):
    for i in sub:
        if i[0].isalpha():
            return i
    return sub[0]

data = {
    'maintopic': ['FBR', np.nan, np.nan, np.nan],
    'subtopic': [['FZ', '1RH', 'FL'] , ['1RH', 'YRS', 'FZ', 'FL'], ['FZX', '1RH', 'FZL'], ['YHS']]
}

df = pd.DataFrame(data)
print('Before\n', df)
df['maintopic'] = df.apply(
    lambda row: fill_value(row['subtopic']) if pd.isnull(row['maintopic']) else row['maintopic'],
    axis=1
)
print('\nAfter\n', df)

输出:

Before
   maintopic            subtopic
0       FBR       [FZ, 1RH, FL]
1       NaN  [1RH, YRS, FZ, FL]
2       NaN     [FZX, 1RH, FZL]
3       NaN               [YHS]

After
   maintopic            subtopic
0       FBR       [FZ, 1RH, FL]
1       YRS  [1RH, YRS, FZ, FL]
2       FZX     [FZX, 1RH, FZL]
3       YHS               [YHS]

您可以更改fill\ u value函数以返回所需的值来填充值。现在,我已经返回了以字母表开头的子主题的第一个值。

kmpatx3s

kmpatx3s3#

可以这样做:获取列表中每个值中以第一个字母开头的所有子字符串 subtopics 列并构建一个计数器,然后根据其频率对计数器中的项进行排序。如果项目的频率相同,请考虑最长的字符串。

from collections import Counter
from functools import cmp_to_key
def get_main_topic_modified(m, l):
    if m is not np.nan:
       return m
    if len(l) == 1:
       return l[0]
    res = []
    for s in l:
        il = [s[:i+1] for i in range(len(s)-1)]
        res.append(il)
    res = [item for s in res for item in s]
    c = Counter(res)
    d = dict(c)
    l = list(d.items())

    l.sort(key=cmp_to_key(lambda x, y: len(y[0])-len(x[0]) if x[1] == y[1] else y[1] - x[1]))

    return l[0][0]

df['maintopic'] = df[['maintopic', 'subtopics']].apply(
                       lambda x : get_main_topic_modified(*x), axis = 1)

输出:

index itemID  maintopic            subtopics
0     1    235        FBR        [FZ, 1RH, FL]
1     2   1787          F   [1RH, YRS, FZ, FL]
2     3   2454         FZ      [FZX, 1RH, FZL]
3     4   3165        YHS                [YHS]

相关问题