Odbuduj pandy Dataframe

Nov 05 2020

jestem całkiem nowy w Pythonie. Mam problem z odtworzeniem złej ramki Dataframe. Moja Dataframe wygląda następująco:

df = pd.DataFrame({'col1': ['id 1', 'id 2', 'test 3', 'test 4'],
               'col2': ['test 1', 'test 2',
                        'Number 6135', 'id 4'],
               'col3': ['Number 12344', 'Number 21612','id 3','Number 1131']})

Jak widzisz, mam "id" w pierwszym, drugim i czwartym kol. To samo dla innych wartości.

Moim celem jest posiadanie ramki danych, w której każda kolumna ma tylko Wartości zaczynające się od tego samego podłańcucha, jak w tym przykładzie:

już próbowałem używać for Loops i if Statments, aby sprawdzić, czy określony podciąg znajduje się w moim ciągu. jeśli to prawda, tworzę nową kolumnę i wpisuję w niej moją wartość

for x in df['col1']:
if 'id' in x:
    df['newCol']=x

Wiem, że ten kod nigdy nie rozwiąże mojego problemu, być może jest jakaś funkcja pandy, która pomoże mi rozwiązać ten problem

Jeśli coś jest niejasne, po prostu zapytaj, postaram się jak najlepiej wyjaśnić mój problem. Z góry dziękuję za pomoc i nie przejmuj się :)

Odpowiedzi

3 AndrejKesely Nov 05 2020 at 17:34

Możesz używać sorted()z funkcją klawisza niestandardowego:

def key_fn(x):
    if 'id' in x:
        return 0
    if 'test' in x:
        return 1
    if 'Number' in x:
        return 2
    return 3 

df = df.apply(lambda x: pd.Series(sorted(x, key=key_fn)), axis=1)
df = df.rename(columns=lambda x: 'col{}'.format(x+1))
print(df)

Wydruki:

   col1    col2          col3
0  id 1  test 1  Number 12344
1  id 2  test 2  Number 21612
2  id 3  test 3   Number 6135
3  id 4  test 4   Number 1131

Inna wersja, z komentarzy:

df = pd.DataFrame([sorted(l, key=key_fn) for l in df.values], columns=df.columns)
print(df)
3 jezrael Nov 05 2020 at 17:34

Jeśli to możliwe, uprość rozwiązanie, dzieląc wartości przez pierwsze puste miejsce:

df = (df.reset_index()
        .melt('index')
        .assign(new = lambda x: x['value'].str.split().str[0])
        .pivot('index','new','value'))
print (df)
new          Number    id    test
index                            
0      Number 12344  id 1  test 1
1      Number 21612  id 2  test 2
2       Number 6135  id 3  test 3
3       Number 1131  id 4  test 4

W przeciwnym razie możesz użyć Series.str.extract:

L = ['id','test','Number']

df = (df.reset_index()
        .melt('index')
        .assign(new = lambda x: x['value'].str.extract(f'({"|".join(L)})', expand=False))
        .pivot('index','new','value'))
print (df)
new          Number    id    test
index                            
0      Number 12344  id 1  test 1
1      Number 21612  id 2  test 2
2       Number 6135  id 3  test 3
3       Number 1131  id 4  test 4
AndyL. Nov 05 2020 at 17:38

Spróbuj tego:

s = df.melt()['value']
df_final = pd.DataFrame({x: s[s.str.startswith(x)].values 
                                        for x in s.str.split().str[0].unique()})

Out[27]:
     id    test        Number
0  id 1  test 3   Number 6135
1  id 2  test 4  Number 12344
2  id 4  test 1  Number 21612
3  id 3  test 2   Number 1131
sammywemmy Nov 05 2020 at 17:48

Możesz najpierw stopić ramkę danych, następnie użyć numpy select, aby zmienić kolejność nazw, a na koniec obrócić :

(df.melt(ignore_index=False)
   .assign(variable=lambda x: np.select([x.value.str.startswith("id"),
                                          x.value.str.startswith("test"),
                                          x.value.str.startswith("Number")],
                                          ["col1", "col2", "col3"]))
    .reset_index()
    .pivot("index", "variable", "value")
    .rename_axis(columns=None, index=None))


    col1    col2    col3
0   id 1    test 1  Number 12344
1   id 2    test 2  Number 21612
2   id 3    test 3  Number 6135
3   id 4    test 4  Number 1131