Passing all possible combinations of arguments to function

I have this problem that I thought was a no-brainer, but I am apparently missing the logic behind passing arguments to a function. So, I have this dataframe,

id type zone    d
0    1    a   a1   23
1    1    a   b1   45
2    1    a   c1   23
3    2    a   c1   56
4    2    b   a1    7
5    2    b   b1    5
6    3    b   a1    2
7    3    b   a1    9
8    3    b   b1   43
9    4    c   c1   21
10   4    c   c1   67
11   5    c   b1   34
12   5    c   a1   21
13   1    a   a1    3
14   1    a   b1    4
15   1    a   c1   12
16   2    a   c1   10
17   2    b   a1   33
18   2    b   b1   22
19   3    b   a1  334
20   3    b   a1   22
21   3    b   b1   11
22   4    c   c1   55
23   4    c   c1   88
24   5    c   b1   22
25   5    c   a1    9

(here it is in the form of a dict:

{'id': {0: 1,
  1: 1,
  2: 1,
  3: 2,
  4: 2,
  5: 2,
  6: 3,
  7: 3,
  8: 3,
  9: 4,
  10: 4,
  11: 5,
  12: 5,
  13: 1,
  14: 1,
  15: 1,
  16: 2,
  17: 2,
  18: 2,
  19: 3,
  20: 3,
  21: 3,
  22: 4,
  23: 4,
  24: 5,
  25: 5},
 'type': {0: 'a',
  1: 'a',
  2: 'a',
  3: 'a',
  4: 'b',
  5: 'b',
  6: 'b',
  7: 'b',
  8: 'b',
  9: 'c',
  10: 'c',
  11: 'c',
  12: 'c',
  13: 'a',
  14: 'a',
  15: 'a',
  16: 'a',
  17: 'b',
  18: 'b',
  19: 'b',
  20: 'b',
  21: 'b',
  22: 'c',
  23: 'c',
  24: 'c',
  25: 'c'},
 'zone': {0: 'a1',
  1: 'b1',
  2: 'c1',
  3: 'c1',
  4: 'a1',
  5: 'b1',
  6: 'a1',
  7: 'a1',
  8: 'b1',
  9: 'c1',
  10: 'c1',
  11: 'b1',
  12: 'a1',
  13: 'a1',
  14: 'b1',
  15: 'c1',
  16: 'c1',
  17: 'a1',
  18: 'b1',
  19: 'a1',
  20: 'a1',
  21: 'b1',
  22: 'c1',
  23: 'c1',
  24: 'b1',
  25: 'a1'},
 'd': {0: 23,
  1: 45,
  2: 23,
  3: 56,
  4: 7,
  5: 5,
  6: 2,
  7: 9,
  8: 43,
  9: 21,
  10: 67,
  11: 34,
  12: 21,
  13: 3,
  14: 4,
  15: 12,
  16: 10,
  17: 33,
  18: 22,
  19: 334,
  20: 22,
  21: 11,
  22: 55,
  23: 88,
  24: 22,
  25: 9}}

I also have two lists

A = ['a','b','c']
B = ['a1','b1','c1']

which are the unique type and zone in the dataframe df_test. Now, I've creates a function that will return histogram for the "accuracy" of measurements for all types to type. Ignore the fact that the function in itself makes no sense with the provided data, it does return exactly what I want with real data.

df_accuracy =[]

def Accuracy_by_id_for_type(distance, df, types):
    df_region = df[df['type']=="{}".format(type)]
    id_dist = df_region.drop_duplicates()

    id_s = id_dist[id_dist['d'].notna()]
    id_sm = id_s.loc[id_s.groupby('id', sort=False)['d'].idxmin()]

    max_dist = id_sm['d'].max()
    min_dist = id_sm['d'].min()

    id_sm['normalized_dist'] = (id_sm['d'] - min_dist) / (max_dist - min_dist)   

    id_sm['accuracy'] = round((1-id_sm['normalized_dist'])*100,1)
    
    df_accuracy.append(id_sm)

    id_sm = id_sm.sort_values('accuracy',ascending=False)
    id_sm.hist()
    plt.suptitle("Accuracy for {} ".format(type))
    
    plt.show(block=True)
    plt.show(block=True)

I pass every type in the following way:

for types in A:
    Accuracy_by_id_for_type(1, df_test,"{}".format(types))

and it returns as many histograms as there are types.

A similar function exists for zone in the list B.

Now, to my issues:

I have created the following function to deal with both types and zone, i.e. "do the same thing" for all combinations of elements in A and B:

df_accuracy_type_zone = []

def Accuracy_by_id_for_type_zone(distance, df, types, zone):
    df_region = df[(df['type']=="{}".format(types)) & (df['type']=="{}".format(zone))]
    id_dist = df_region.drop_duplicates()

    id_s = id_dist[id_dist['d'].notna()]
    id_sm = id_s.loc[id_s.groupby('id', sort=False)['d'].idxmin()]

    max_dist = id_sm['d'].max()
    min_dist = id_sm['d'].min()

    id_sm['normalized_dist'] = (id_sm['d'] - min_dist) / (max_dist - min_dist)   

    id_sm['accuracy'] = round((1-id_sm['normalized_dist'])*100,1)
    
    df_accuracy_type_zone.append(id_sm)

    id_sm = id_sm.sort_values('accuracy',ascending=False)
    id_sm.hist()
    plt.suptitle("Accuracy for {} and zone {}".format(types).format(zone))
    
    plt.show(block=True)
    plt.show(block=True)

As you can see:

df_region = df[(df['type']=="{}".format(types)) & (df['type']=="{}".format(zone))]

keeps only the data in the dataframe for one type and one zone. What I tried was this:

for types in A:
    for zone in B:
        Accuracy_by_id_for_type_zone(1, df_test, "{}".format(types), "{}".format(zone))

but I get the error:

IndexError: Replacement index 1 out of range for positional args tuple

What am I doing wrong? Thankful for any insight.

Upvotes: 0

Views: 68

Answers (1)

Corralien
Corralien

Reputation: 120509

You have to replace:

plt.suptitle("Accuracy for {} and zone {}".format(types).format(zone))

by:

plt.suptitle("Accuracy for {} and zone {}".format(types, zone))

or better:

plt.suptitle(f"Accuracy for {types} and zone {zone}")

To know more about f-strings, refer to the documentation

Upvotes: 1

Related Questions