Как заполнить строки повторяющимися данными в pandas?
В R при добавлении новых данных с неравной длиной в кадр данных значения повторяются для заполнения кадра данных:
df <- data.frame(first=c(1,2,3,4,5,6))
df$second <- c(1,2,3)
получая:
first second
1 1 1
2 2 2
3 3 3
4 4 1
5 5 2
6 6 3
Однако pandas требует равных длин индекса.
Как мне "заполнить" повторяющиеся данные в pandas, как я могу в R?
Ответы
Ответ 1
Кажется, нет элегантного способа. Это обходной путь, который я только что понял. В основном создайте повторяющийся список, который больше, чем исходный фреймворк данных, а затем присоедините их к ним.
import pandas
df = pandas.DataFrame(range(100), columns=['first'])
repeat_arr = [1, 2, 3]
df = df.join(pandas.DataFrame(repeat_arr * (len(df)/len(repeat_arr)+1),
columns=['second']))
Ответ 2
Метод цикла из itertools хорош для повторения общего шаблона.
from itertools import cycle
seq = cycle([1, 2, 3])
df['Seq'] = [next(seq) for count in range(df.shape[0])]
Ответ 3
import pandas as pd
import numpy as np
def put(df, column, values):
df[column] = 0
np.put(df[column], np.arange(len(df)), values)
df = pd.DataFrame({'first':range(1, 8)})
put(df, 'second', [1,2,3])
дает
first second
0 1 1
1 2 2
2 3 3
3 4 1
4 5 2
5 6 3
6 7 1
Не особенно красиво, но одна "особенность", которой он обладает, заключается в том, что вам не нужно беспокоиться, если длина DataFrame кратна длине повторяющихся значений. np.put
повторяет значения по мере необходимости.
Мой первый ответ был:
import itertools as IT
df['second'] = list(IT.islice(IT.cycle([1,2,3]), len(df)))
но оказывается, что это значительно медленнее:
In [312]: df = pd.DataFrame({'first':range(10**6)})
In [313]: %timeit df['second'] = list(IT.islice(IT.cycle([1,2,3]), len(df)))
10 loops, best of 3: 143 ms per loop
In [316]: %timeit df['second'] = 0; np.put(df['second'], np.arange(N), [1,2,3])
10 loops, best of 3: 27.9 ms per loop
Ответ 4
Как обычно вы ищете решение? Я попытался сделать это немного менее жестко:
import numpy as np
import pandas
df = pandas.DataFrame(np.arange(1,7), columns=['first'])
base = [1, 2, 3]
df['second'] = base * (df.shape[0]/len(base))
print(df.to_string())
first second
0 1 1
1 2 2
2 3 3
3 4 1
4 5 2
5 6 3
Ответ 5
В моем случае мне нужно было повторить значения, не зная длины суб-списка, т.е. проверяя длину каждой группы.
Это было мое решение:
import numpy as np
import pandas
df = pandas.DataFrame(['a','a','a','b','b','b','b'], columns=['first'])
list = df.groupby('first').apply(lambda x: range(len(x))).tolist()
loop = [val for sublist in list for val in sublist]
df['second']=loop
df
first second
0 a 0
1 a 1
2 a 2
3 b 0
4 b 1
5 b 2
6 b 3
Ответ 6
Вероятно, неэффективно, но здесь вроде чистого решения панд.
import numpy as np
import pandas as pd
base = [1,2,3]
df = pd.DataFrame(data = None,index = np.arange(10),columns = ["filler"])
df["filler"][:len(base)] = base
df["tmp"] = np.arange(len(df)) % len(base)
df["filler"] = df.sort_values("tmp")["filler"].ffill() #.sort_index()
print(df)
Ответ 7
Вы можете попробовать использовать силу по модулю (%). Вы можете взять значение (или индекс) первого и использовать длину секунды в качестве модуля, чтобы получить искомое значение (или индекс). Что-то вроде:
df = pandas.DataFrame([0,1,2,3,4,5], columns=['first'])
sec = [0,1,2]
df['second'] = df['first'].apply(lambda x: x % len(sec) )
print(df)
first second
0 0 0
1 1 1
2 2 2
3 3 0
4 4 1
5 5 2
Надеюсь, это поможет.