Я делаю функцию, которая принимает в качестве входных данных фрейм данных:

a = {"string": ['xxx', 'yyy'], "array": [[1,2,3,4,5,6,1,2,3,6,6,2,2,3,5,6], [2,6,6]]}
df = pd.DataFrame(a)

    string  array
0   xxx [1, 2, 3, 4, 5, 6, 1, 2, 3, 6, 6, 2, 2, 3, 5, 6]
1   yyy [2, 6, 6]

И возвращает фрейм данных, где переданным параметром является определенный номер разделителя (в примере это 6):

    string  array
0   xxx [1, 2, 3, 4, 5, 6]
1   xxx [1, 2, 3, 6]
2   xxx [6]
3   xxx [2, 2, 3, 5, 6]
4   yyy [2, 6]
5   yyy [6]

Вот что у меня получилось:

def df_conversion(df, sep=None):
    data = {}
    idx = []
    
    for i in range(df.shape[0]):       
        key = df['string'].iloc[i]
        value = df['array'].iloc[i]

        spl = [[]]
        for item in value:
            if item == sep:
                spl[-1].append(item)
                idx.append(key)
                spl.append([])
            else:
                spl[-1].append(item)

        del spl[-1]
        if i == 0: spl_0 = spl
        if i == 1: spl_0.extend(spl)

    data['string'] = idx
    data['array'] = spl_0

    return pd.DataFrame(data)

df_conversion(df, 6)

Как упростить функцию и сделать ее более универсальной? Как сделать функцию быстрее? Спасибо.

3
Chegevara 9 Апр 2021 в 09:53

2 ответа

Лучший ответ

Вы можете сделать это кратко с помощью np.split() и {{X1} } :

sep = 6
df.array = df.array.apply(lambda a:
    np.split(a, 1 + np.where(np.array(a) == sep)[0][:-1]))

df = df.set_index('string')
df = df.explode('array').reset_index()

#   string               array
# 0    xxx  [1, 2, 3, 4, 5, 6]
# 1    xxx        [1, 2, 3, 6]
# 2    xxx                 [6]
# 3    xxx     [2, 2, 3, 5, 6]
# 4    yyy              [2, 6]
# 5    yyy                 [6]

Объяснение для np.split() и np.where() < / а>

Мы используем np.where() , чтобы найти индексы sep:

a = [1, 2, 3, 4, 5, 6, 1, 2, 3, 6, 6, 2, 2, 3, 5, 6]
sep = 6
np.where(np.array(a) == sep)[0]

# array([ 5,  9, 10, 15])

Однако, если мы np.split() в этих индексах элемент sep перемещается в начало каждого разбиения:

np.split(a, np.where(np.array(a) == sep)[0])

# [array([1, 2, 3, 4, 5]),
#  array([6, 1, 2, 3]),
#  array([6]),
#  array([6, 2, 2, 3, 5]),
#  array([6])]

Но желаемый результат - оставить sep в конце разбиения, поэтому мы добавляем 1 к индексам и удаляем последний индекс:

np.split(a, 1 + np.where(np.array(a) == sep)[0][:-1])

# [array([1, 2, 3, 4, 5, 6]),
#  array([1, 2, 3, 6]),
#  array([6]),
#  array([2, 2, 3, 5, 6])]
5
tdy 9 Апр 2021 в 08:01

Используйте Series.str.split с < a href = "https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.explode.html" rel = "nofollow noreferrer"> df.explode :

In [2174]: sep = '6'

In [2167]: df.array = df.array.apply(lambda x: ','.join(map(str, x))).str.split(sep)

In [2168]: df = df.explode('array')

In [2169]: df.array = df.array + sep

In [2171]: df.array = np.where(df.array.str.startswith(','), df.array.str[1:], df.array)
In [2183]: df = df.drop_duplicates()
In [2172]: df.array = df.array.str.split(',')

In [2186]: df
Out[2186]: 
  string               array
0    xxx  [1, 2, 3, 4, 5, 6]
0    xxx        [1, 2, 3, 6]
0    xxx                 [6]
0    xxx     [2, 2, 3, 5, 6]
1    yyy              [2, 6]
1    yyy                 [6]
1
Mayank Porwal 9 Апр 2021 в 07:39